diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8a7c6dfc5c6f0..3289d4a1d67e0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -245,7 +245,6 @@ packages/react-components/react-colorpicker-compat @microsoft/cxe-red @sopranopi packages/react-components/react-nav-preview @microsoft/cxe-red @mltejera packages/react-components/react-motion-preview @microsoft/cxe-prg @marcosmoura packages/react-components/react-message-bar @microsoft/teams-prg -packages/react-components/react-timepicker-compat-preview @microsoft/teams-prg packages/react-components/react-rating-preview @microsoft/cxe-red @tomi-msft packages/react-components/react-swatch-picker-preview @microsoft/cxe-prg packages/react-components/react-calendar-compat @microsoft/cxe-red @sopranopillow diff --git a/packages/react-components/react-timepicker-compat-preview/.babelrc.json b/packages/react-components/react-timepicker-compat-preview/.babelrc.json deleted file mode 100644 index 45fb71ca16d2c..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/.babelrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../../../.babelrc-v9.json", - "plugins": ["annotate-pure-calls", "@babel/transform-react-pure-annotations"] -} diff --git a/packages/react-components/react-timepicker-compat-preview/.eslintrc.json b/packages/react-components/react-timepicker-compat-preview/.eslintrc.json deleted file mode 100644 index ceea884c70dcc..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/.eslintrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": ["plugin:@fluentui/eslint-plugin/react"], - "root": true -} diff --git a/packages/react-components/react-timepicker-compat-preview/.storybook/main.js b/packages/react-components/react-timepicker-compat-preview/.storybook/main.js deleted file mode 100644 index 26536b61b387f..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/.storybook/main.js +++ /dev/null @@ -1,14 +0,0 @@ -const rootMain = require('../../../../.storybook/main'); - -module.exports = /** @type {Omit} */ ({ - ...rootMain, - stories: [...rootMain.stories, '../stories/**/*.stories.mdx', '../stories/**/index.stories.@(ts|tsx)'], - addons: [...rootMain.addons], - webpackFinal: (config, options) => { - const localConfig = { ...rootMain.webpackFinal(config, options) }; - - // add your own webpack tweaks if needed - - return localConfig; - }, -}); diff --git a/packages/react-components/react-timepicker-compat-preview/.storybook/preview.js b/packages/react-components/react-timepicker-compat-preview/.storybook/preview.js deleted file mode 100644 index 1939500a3d18c..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/.storybook/preview.js +++ /dev/null @@ -1,7 +0,0 @@ -import * as rootPreview from '../../../../.storybook/preview'; - -/** @type {typeof rootPreview.decorators} */ -export const decorators = [...rootPreview.decorators]; - -/** @type {typeof rootPreview.parameters} */ -export const parameters = { ...rootPreview.parameters }; diff --git a/packages/react-components/react-timepicker-compat-preview/.storybook/tsconfig.json b/packages/react-components/react-timepicker-compat-preview/.storybook/tsconfig.json deleted file mode 100644 index ea89218a3d916..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/.storybook/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "", - "allowJs": true, - "checkJs": true, - "types": ["static-assets", "environment", "storybook__addons"] - }, - "include": ["../stories/**/*.stories.ts", "../stories/**/*.stories.tsx", "*.js"] -} diff --git a/packages/react-components/react-timepicker-compat-preview/.swcrc b/packages/react-components/react-timepicker-compat-preview/.swcrc deleted file mode 100644 index b4ffa86dee306..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/.swcrc +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/swcrc", - "exclude": [ - "/testing", - "/**/*.cy.ts", - "/**/*.cy.tsx", - "/**/*.spec.ts", - "/**/*.spec.tsx", - "/**/*.test.ts", - "/**/*.test.tsx" - ], - "jsc": { - "parser": { - "syntax": "typescript", - "tsx": true, - "decorators": false, - "dynamicImport": false - }, - "externalHelpers": true, - "transform": { - "react": { - "runtime": "classic", - "useSpread": true - } - }, - "target": "es2019" - }, - "minify": false, - "sourceMaps": true -} diff --git a/packages/react-components/react-timepicker-compat-preview/CHANGELOG.json b/packages/react-components/react-timepicker-compat-preview/CHANGELOG.json deleted file mode 100644 index e66dedbbaafc6..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/CHANGELOG.json +++ /dev/null @@ -1,382 +0,0 @@ -{ - "name": "@fluentui/react-timepicker-compat-preview", - "entries": [ - { - "date": "Tue, 09 Jan 2024 10:21:34 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.2.0", - "version": "0.2.0", - "comments": { - "minor": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "a5e34e3c996d322bb0735f4fca9537deafd07b59", - "comment": "Deprecate preview package. Use @fluentui/react-timepicker-compat instead." - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.39", - "commit": "a5e34e3c996d322bb0735f4fca9537deafd07b59" - } - ] - } - }, - { - "date": "Mon, 08 Jan 2024 16:24:28 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.10", - "version": "0.1.10", - "comments": { - "patch": [ - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.38", - "commit": "0893aaa977c642d01c3c39032f929bc50a04d867" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-field to v9.1.47", - "commit": "0893aaa977c642d01c3c39032f929bc50a04d867" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-jsx-runtime to v9.0.24", - "commit": "0893aaa977c642d01c3c39032f929bc50a04d867" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-utilities to v9.15.6", - "commit": "0893aaa977c642d01c3c39032f929bc50a04d867" - } - ] - } - }, - { - "date": "Wed, 03 Jan 2024 09:26:44 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.9", - "version": "0.1.9", - "comments": { - "patch": [ - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.37", - "commit": "9d99266dec5a450bcd44c0f777735b31dd98eccc" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-field to v9.1.46", - "commit": "9d99266dec5a450bcd44c0f777735b31dd98eccc" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-jsx-runtime to v9.0.23", - "commit": "9d99266dec5a450bcd44c0f777735b31dd98eccc" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-utilities to v9.15.5", - "commit": "9d99266dec5a450bcd44c0f777735b31dd98eccc" - } - ] - } - }, - { - "date": "Thu, 21 Dec 2023 17:00:41 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.8", - "version": "0.1.8", - "comments": { - "patch": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "430e58ba1d1a6f0b2bcad8577070f01af099770c", - "comment": "fix: set default value of hourCycle to undefined" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.36", - "commit": "fe0792a703aec2388daee8d6c0b727f1736147f1" - } - ] - } - }, - { - "date": "Mon, 18 Dec 2023 17:48:16 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.7", - "version": "0.1.7", - "comments": { - "patch": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "c1b96dae4218975ea6366c714880e174cf9955e4", - "comment": "fix: provides a default aria-labelledby for the chevron icon if the TimePicker is wrapped in a Field." - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.35", - "commit": "2034818a2dd109f3e9f7bb5cdf4caae47a9116d4" - } - ] - } - }, - { - "date": "Mon, 18 Dec 2023 14:40:43 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.6", - "version": "0.1.6", - "comments": { - "patch": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "73c8cb55e5957d6ce321ecabe35d177d791ff0b6", - "comment": "fix: use useEventCallback instead of useCallback" - }, - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "a657b210377643bdab23b145b47f715e1d7effa9", - "comment": "fix: letter key navigation in listbox should be case insensitive" - }, - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "af6a9cb92082860c218fe72c99a03d45d6d7d1e4", - "comment": "fix: add custom style hook for TimePicker compat." - }, - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "8012cdf639e843847ee633040994c2d4e135185b", - "comment": "fix: set autoComeplete to off by default" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.34", - "commit": "c1b96dae4218975ea6366c714880e174cf9955e4" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-jsx-runtime to v9.0.22", - "commit": "c1b96dae4218975ea6366c714880e174cf9955e4" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-shared-contexts to v9.13.2", - "commit": "c1b96dae4218975ea6366c714880e174cf9955e4" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-utilities to v9.15.4", - "commit": "c1b96dae4218975ea6366c714880e174cf9955e4" - } - ] - } - }, - { - "date": "Thu, 14 Dec 2023 09:58:46 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.5", - "version": "0.1.5", - "comments": { - "patch": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "07bc7ffdd9a6abb244e1ac339677998729dee7eb", - "comment": "fix: add max-height to show 12 items in listbox" - }, - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "0d1d32a39687023d0d09632cbfc6e40fb04fa888", - "comment": "fix: use default time format instead of h23 hour cycle." - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.33", - "commit": "73c8cb55e5957d6ce321ecabe35d177d791ff0b6" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-jsx-runtime to v9.0.21", - "commit": "73c8cb55e5957d6ce321ecabe35d177d791ff0b6" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-utilities to v9.15.3", - "commit": "73c8cb55e5957d6ce321ecabe35d177d791ff0b6" - } - ] - } - }, - { - "date": "Thu, 30 Nov 2023 13:42:08 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.4", - "version": "0.1.4", - "comments": { - "patch": [ - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.32", - "commit": "f882fe7c3fbe6b4d6c3153732d384880bfd351dc" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-jsx-runtime to v9.0.20", - "commit": "f882fe7c3fbe6b4d6c3153732d384880bfd351dc" - } - ] - } - }, - { - "date": "Mon, 20 Nov 2023 09:55:10 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.3", - "version": "0.1.3", - "comments": { - "patch": [ - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.31", - "commit": "873b079e8c57fc139366d6ab57d9070abd81865a" - } - ] - } - }, - { - "date": "Tue, 14 Nov 2023 17:51:27 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.2", - "version": "0.1.2", - "comments": { - "patch": [ - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.30", - "commit": "74af9993e1f812bdc9d8a4635f8477295168efa8" - } - ] - } - }, - { - "date": "Thu, 09 Nov 2023 17:29:46 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.1", - "version": "0.1.1", - "comments": { - "patch": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "ff6d3f116ad039e81dc6343bd2cd5dee861c7282", - "comment": "fix: rename `formatTimeStringToDate` to `parseTimeStringToDate`." - }, - { - "author": "martinhochel@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "baa8387b51ae5e028dd7c2f98827ab9bd749f90e", - "comment": "chore: use package.json#files setup instead of npmignore for all v9 libraries" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/keyboard-keys to v9.0.7", - "commit": "9c30220feb177e8336960c21cf6df78c9c1ca629" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.29", - "commit": "9c30220feb177e8336960c21cf6df78c9c1ca629" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-jsx-runtime to v9.0.19", - "commit": "9c30220feb177e8336960c21cf6df78c9c1ca629" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-theme to v9.1.16", - "commit": "9c30220feb177e8336960c21cf6df78c9c1ca629" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-utilities to v9.15.2", - "commit": "9c30220feb177e8336960c21cf6df78c9c1ca629" - } - ], - "none": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "f62bf36e60a63938f0a0715b867de6782a153519", - "comment": "chore: add cypress tests." - } - ] - } - }, - { - "date": "Thu, 02 Nov 2023 17:38:46 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.0", - "version": "0.1.0", - "comments": { - "none": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "727224140e113363c3e5bb1f26b092b81da2ccb9", - "comment": "chore: add bundle size fixture." - } - ] - } - }, - { - "date": "Wed, 01 Nov 2023 12:55:58 GMT", - "tag": "@fluentui/react-timepicker-compat-preview_v0.1.0", - "version": "0.1.0", - "comments": { - "minor": [ - { - "author": "yuanboxue@microsoft.com", - "package": "@fluentui/react-timepicker-compat-preview", - "commit": "d4664628ced0837e16fd0cb20c79ba66030ed33d", - "comment": "feat: release preview package" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-combobox to v9.5.28", - "commit": "838b05367dbdddb17732b9e0c807090e0a4445d5" - }, - { - "author": "beachball", - "package": "@fluentui/react-timepicker-compat-preview", - "comment": "Bump @fluentui/react-theme to v9.1.15", - "commit": "838b05367dbdddb17732b9e0c807090e0a4445d5" - } - ] - } - } - ] -} diff --git a/packages/react-components/react-timepicker-compat-preview/CHANGELOG.md b/packages/react-components/react-timepicker-compat-preview/CHANGELOG.md deleted file mode 100644 index 73c3ff087a313..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/CHANGELOG.md +++ /dev/null @@ -1,141 +0,0 @@ -# Change Log - @fluentui/react-timepicker-compat-preview - -This log was last generated on Tue, 09 Jan 2024 10:21:34 GMT and should not be manually modified. - - - -## [0.2.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.2.0) - -Tue, 09 Jan 2024 10:21:34 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.10..@fluentui/react-timepicker-compat-preview_v0.2.0) - -### Minor changes - -- Deprecate preview package. Use @fluentui/react-timepicker-compat instead. ([PR #30217](https://github.com/microsoft/fluentui/pull/30217) by yuanboxue@microsoft.com) -- Bump @fluentui/react-combobox to v9.5.39 ([PR #30217](https://github.com/microsoft/fluentui/pull/30217) by beachball) - -## [0.1.10](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.10) - -Mon, 08 Jan 2024 16:24:28 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.9..@fluentui/react-timepicker-compat-preview_v0.1.10) - -### Patches - -- Bump @fluentui/react-combobox to v9.5.38 ([PR #30179](https://github.com/microsoft/fluentui/pull/30179) by beachball) -- Bump @fluentui/react-field to v9.1.47 ([PR #30179](https://github.com/microsoft/fluentui/pull/30179) by beachball) -- Bump @fluentui/react-jsx-runtime to v9.0.24 ([PR #30179](https://github.com/microsoft/fluentui/pull/30179) by beachball) -- Bump @fluentui/react-utilities to v9.15.6 ([PR #30179](https://github.com/microsoft/fluentui/pull/30179) by beachball) - -## [0.1.9](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.9) - -Wed, 03 Jan 2024 09:26:44 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.8..@fluentui/react-timepicker-compat-preview_v0.1.9) - -### Patches - -- Bump @fluentui/react-combobox to v9.5.37 ([PR #30163](https://github.com/microsoft/fluentui/pull/30163) by beachball) -- Bump @fluentui/react-field to v9.1.46 ([PR #30163](https://github.com/microsoft/fluentui/pull/30163) by beachball) -- Bump @fluentui/react-jsx-runtime to v9.0.23 ([PR #30163](https://github.com/microsoft/fluentui/pull/30163) by beachball) -- Bump @fluentui/react-utilities to v9.15.5 ([PR #30163](https://github.com/microsoft/fluentui/pull/30163) by beachball) - -## [0.1.8](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.8) - -Thu, 21 Dec 2023 17:00:41 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.7..@fluentui/react-timepicker-compat-preview_v0.1.8) - -### Patches - -- fix: set default value of hourCycle to undefined ([PR #30108](https://github.com/microsoft/fluentui/pull/30108) by yuanboxue@microsoft.com) -- Bump @fluentui/react-combobox to v9.5.36 ([PR #30140](https://github.com/microsoft/fluentui/pull/30140) by beachball) - -## [0.1.7](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.7) - -Mon, 18 Dec 2023 17:48:16 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.6..@fluentui/react-timepicker-compat-preview_v0.1.7) - -### Patches - -- fix: provides a default aria-labelledby for the chevron icon if the TimePicker is wrapped in a Field. ([PR #30103](https://github.com/microsoft/fluentui/pull/30103) by yuanboxue@microsoft.com) -- Bump @fluentui/react-combobox to v9.5.35 ([PR #30010](https://github.com/microsoft/fluentui/pull/30010) by beachball) - -## [0.1.6](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.6) - -Mon, 18 Dec 2023 14:40:43 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.5..@fluentui/react-timepicker-compat-preview_v0.1.6) - -### Patches - -- fix: use useEventCallback instead of useCallback ([PR #30056](https://github.com/microsoft/fluentui/pull/30056) by yuanboxue@microsoft.com) -- fix: letter key navigation in listbox should be case insensitive ([PR #30072](https://github.com/microsoft/fluentui/pull/30072) by yuanboxue@microsoft.com) -- fix: add custom style hook for TimePicker compat. ([PR #30058](https://github.com/microsoft/fluentui/pull/30058) by yuanboxue@microsoft.com) -- fix: set autoComeplete to off by default ([PR #30057](https://github.com/microsoft/fluentui/pull/30057) by yuanboxue@microsoft.com) -- Bump @fluentui/react-combobox to v9.5.34 ([PR #30103](https://github.com/microsoft/fluentui/pull/30103) by beachball) -- Bump @fluentui/react-jsx-runtime to v9.0.22 ([PR #30103](https://github.com/microsoft/fluentui/pull/30103) by beachball) -- Bump @fluentui/react-shared-contexts to v9.13.2 ([PR #30103](https://github.com/microsoft/fluentui/pull/30103) by beachball) -- Bump @fluentui/react-utilities to v9.15.4 ([PR #30103](https://github.com/microsoft/fluentui/pull/30103) by beachball) - -## [0.1.5](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.5) - -Thu, 14 Dec 2023 09:58:46 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.4..@fluentui/react-timepicker-compat-preview_v0.1.5) - -### Patches - -- fix: add max-height to show 12 items in listbox ([PR #29989](https://github.com/microsoft/fluentui/pull/29989) by yuanboxue@microsoft.com) -- fix: use default time format instead of h23 hour cycle. ([PR #30035](https://github.com/microsoft/fluentui/pull/30035) by yuanboxue@microsoft.com) -- Bump @fluentui/react-combobox to v9.5.33 ([PR #30056](https://github.com/microsoft/fluentui/pull/30056) by beachball) -- Bump @fluentui/react-jsx-runtime to v9.0.21 ([PR #30056](https://github.com/microsoft/fluentui/pull/30056) by beachball) -- Bump @fluentui/react-utilities to v9.15.3 ([PR #30056](https://github.com/microsoft/fluentui/pull/30056) by beachball) - -## [0.1.4](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.4) - -Thu, 30 Nov 2023 13:42:08 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.3..@fluentui/react-timepicker-compat-preview_v0.1.4) - -### Patches - -- Bump @fluentui/react-combobox to v9.5.32 ([PR #29929](https://github.com/microsoft/fluentui/pull/29929) by beachball) -- Bump @fluentui/react-jsx-runtime to v9.0.20 ([PR #29929](https://github.com/microsoft/fluentui/pull/29929) by beachball) - -## [0.1.3](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.3) - -Mon, 20 Nov 2023 09:55:10 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.2..@fluentui/react-timepicker-compat-preview_v0.1.3) - -### Patches - -- Bump @fluentui/react-combobox to v9.5.31 ([PR #29878](https://github.com/microsoft/fluentui/pull/29878) by beachball) - -## [0.1.2](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.2) - -Tue, 14 Nov 2023 17:51:27 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.1..@fluentui/react-timepicker-compat-preview_v0.1.2) - -### Patches - -- Bump @fluentui/react-combobox to v9.5.30 ([PR #29835](https://github.com/microsoft/fluentui/pull/29835) by beachball) - -## [0.1.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.1) - -Thu, 09 Nov 2023 17:29:46 GMT -[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-timepicker-compat-preview_v0.1.0..@fluentui/react-timepicker-compat-preview_v0.1.1) - -### Patches - -- fix: rename `formatTimeStringToDate` to `parseTimeStringToDate`. ([PR #29707](https://github.com/microsoft/fluentui/pull/29707) by yuanboxue@microsoft.com) -- chore: use package.json#files setup instead of npmignore for all v9 libraries ([PR #29734](https://github.com/microsoft/fluentui/pull/29734) by martinhochel@microsoft.com) -- Bump @fluentui/keyboard-keys to v9.0.7 ([PR #29800](https://github.com/microsoft/fluentui/pull/29800) by beachball) -- Bump @fluentui/react-combobox to v9.5.29 ([PR #29800](https://github.com/microsoft/fluentui/pull/29800) by beachball) -- Bump @fluentui/react-jsx-runtime to v9.0.19 ([PR #29800](https://github.com/microsoft/fluentui/pull/29800) by beachball) -- Bump @fluentui/react-theme to v9.1.16 ([PR #29800](https://github.com/microsoft/fluentui/pull/29800) by beachball) -- Bump @fluentui/react-utilities to v9.15.2 ([PR #29800](https://github.com/microsoft/fluentui/pull/29800) by beachball) - -## [0.1.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-timepicker-compat-preview_v0.1.0) - -Wed, 01 Nov 2023 12:55:58 GMT - -### Minor changes - -- feat: release preview package ([PR #29677](https://github.com/microsoft/fluentui/pull/29677) by yuanboxue@microsoft.com) -- Bump @fluentui/react-combobox to v9.5.28 ([PR #29663](https://github.com/microsoft/fluentui/pull/29663) by beachball) -- Bump @fluentui/react-theme to v9.1.15 ([PR #29663](https://github.com/microsoft/fluentui/pull/29663) by beachball) diff --git a/packages/react-components/react-timepicker-compat-preview/LICENSE b/packages/react-components/react-timepicker-compat-preview/LICENSE deleted file mode 100644 index bbd067250180f..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -@fluentui/react-timepicker-compat-preview - -Copyright (c) Microsoft Corporation - -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Note: Usage of the fonts and icons referenced in Fluent UI React is subject to the terms listed at https://aka.ms/fluentui-assets-license diff --git a/packages/react-components/react-timepicker-compat-preview/README.md b/packages/react-components/react-timepicker-compat-preview/README.md deleted file mode 100644 index c1d76aa833b1f..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# @fluentui/react-timepicker-compat-preview - -**React Timepicker 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. - -TimePicker offers a control that’s optimized for selecting a time from a drop-down list or using free-form input to enter a custom time. - -## Usage - -To import Timepicker: - -```js -import { TimePicker } from '@fluentui/react-timepicker-compat-preview'; -``` - -### Examples - -```jsx - -``` - -# Compat component - -## What makes a compat component? - -A compat component is a component taken from v8 and partially updated with the v9 toolset while keeping its original functionality and most of the original API surface. The most noticeable change being the removal of all v8 dependencies and using only v9 dependencies. While this is a good first step, this is not the final v9 component. We are working on a fully fleshed v9 replacement that will follow all v9 patterns and conventions. - -## How publishing the package will be handled - -Compat components are not added in the `@fluentui/react-components` package suite. Instead, these components should be imported from their respective package as shown above. In contrast with components that live in `@fluentui/react-components`, compat components are to be released as `0.x.x` and there won't be an unstable release (`beta/alpha`) before this release. This is due to the way we will handle versioning for changes, allowing for breaking changes when necessary. - -### Versioning for changes - -We will take a similar approach as v0 where we will follow this pattern: - -- `breaking change (major)`: Since this is a compat component, we will allow breaking changes if absolutely necessary. To accommodate for this, we will denote those changes as a minor version in semver, i.e. `0.(change will be reflected here).x`. -- `minor and patch`: These changes will be reflected in the patch version in semver as `0.x.(change will be reflected here)`. diff --git a/packages/react-components/react-timepicker-compat-preview/bundle-size/TimePicker.fixture.js b/packages/react-components/react-timepicker-compat-preview/bundle-size/TimePicker.fixture.js deleted file mode 100644 index 26943af23efa8..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/bundle-size/TimePicker.fixture.js +++ /dev/null @@ -1,7 +0,0 @@ -import { TimePicker } from '@fluentui/react-timepicker-compat-preview'; - -console.log(TimePicker); - -export default { - name: 'TimePicker', -}; diff --git a/packages/react-components/react-timepicker-compat-preview/config/api-extractor.json b/packages/react-components/react-timepicker-compat-preview/config/api-extractor.json deleted file mode 100644 index e533bf30b48a2..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/config/api-extractor.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "extends": "@fluentui/scripts-api-extractor/api-extractor.common.v-next.json" -} diff --git a/packages/react-components/react-timepicker-compat-preview/config/tests.js b/packages/react-components/react-timepicker-compat-preview/config/tests.js deleted file mode 100644 index 2e211ae9e2142..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/config/tests.js +++ /dev/null @@ -1 +0,0 @@ -/** Jest test setup file. */ diff --git a/packages/react-components/react-timepicker-compat-preview/cypress.config.ts b/packages/react-components/react-timepicker-compat-preview/cypress.config.ts deleted file mode 100644 index ca52cf041bbf2..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/cypress.config.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { baseConfig } from '@fluentui/scripts-cypress'; - -export default baseConfig; diff --git a/packages/react-components/react-timepicker-compat-preview/docs/Migration.md b/packages/react-components/react-timepicker-compat-preview/docs/Migration.md deleted file mode 100644 index 89c5d91501c87..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/docs/Migration.md +++ /dev/null @@ -1,34 +0,0 @@ -# @fluentui/react-timepicker-compat-preview Migration Guide - -## Migration from v8 TimePicker - -### Property mapping - -TimePicker specific props: - -| v8 TimePicker | v9 TimePicker | -| --------------------- | ------------------------------------------------------------- | -| `dateAnchor` | `dateAnchor` | -| `defaultValue` | `defaultSelectedTime` | -| `increments` | `increment` | -| `label` | handled by `Field` | -| `onChange` | `onTimeChange` | -| `onFormatDate` | `formatDateToTimeString` | -| `onValidateUserInput` | `formatDateToTimeString` | -| `onValidationResult` | `onTimeChange` contains error type in `data` | -| `showSeconds` | `showSeconds` | -| `strings` | use `Field` to display error. See 'Custom Validation' example | -| `timeRange` | `startHour` and `endHour` | -| `useHour12` | `hourCycle='h11'` or `hourCycle='h12'` | -| `value` | `selectedTime` | - -V8 TimePicker is built on v8 Combobox, and v9 TimePicker compat on v9 Combobox. Please see Combobox migration guide for the rest of the props. - -\*In v9, any native HTML properties supported on an `` element may be set on ``, including the `onChange` handler. Because of this, the v8 `onChange` selection callback has been updated to `onTimeChange`. The v9 TimePicker's `onChange` event behavior is the same as for an `` element, or the v9 Input control. - -### Validate selected time - -V8 TimePicker allows custom validation on freeform input via `onValidateUserInput`. There is no way to validate selected option from dropdown. -V9 TimePicker should be used together with `Field` component, and it provides more flexibility for custom validation. You can perform custom parsing and validation for freeform input using `formatDateToTimeString`. Validation of the selected time option from the dropdown can be achieved by validating the `selectedTime` within `onTimeChange` callback. - -v8 TimePicker has default error messages. v9 TimePicker has no default error message - it returns an error type from `onTimeChange` that can be used to display a custom error message. diff --git a/packages/react-components/react-timepicker-compat-preview/docs/Spec.md b/packages/react-components/react-timepicker-compat-preview/docs/Spec.md deleted file mode 100644 index a3c730ee78d17..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/docs/Spec.md +++ /dev/null @@ -1,38 +0,0 @@ -# @fluentui/react-timepicker-compat-preview Spec - -## Background - -Compat component for [V8 TimePicker](https://developer.microsoft.com/en-us/fluentui#/controls/web/timepicker). - -> ⚠️ A compat component is a component taken from v8 and partially updated with the v9 toolset while keeping its original functionality and most of the original API surface. The most noticeable change being the removal of all v8 dependencies and using only v9 dependencies. While this is a good first step, this is not the final v9 component. We are working on a fully fleshed v9 replacement that will follow all v9 patterns and conventions. - -TimePicker offers a control that’s optimized for selecting a time from a drop-down list or using free-form input to enter a custom time. - -**TimePicker is built on top of v9 Combobox. Combobox [Spec.md](../../react-combobox/docs/Spec.md) covers the variants, structure and accessibility of TimePicker. This spec highlights the TimePicker specifics.** - -## Prior Art - -- [26642](https://github.com/microsoft/fluentui/issues/26642) - -## Selection Behaviors - -When selecting a time, the time is validated, `onTimeChange` callback is fired with the selected time and the error if the time is invalid. TimePicker has two variants that provides different selection behavior: - -1. **Basic TimePicker**: a v9 Combobox with predefined time options. - - Selecting an option from the dropdown invokes `onTimeChange` callback. -2. **Freeform TimePicker**: a v9 Combobox with predefined time options that allows freeform input. - - Selecting an option from the dropdown invokes `onTimeChange` callback. - - Time is selected from freeform input when its value has changed, and TimePicker loses focus or Enter key is pressed. `onTimeChange` is triggered with the selected time from `input` value. This behavior aligns with the native `change` event for text input. - > freeform TimePicker's selection behavior is different from freeform Combobox. Combobox lacks the equivalent callback for native change event ([29494](https://github.com/microsoft/fluentui/issues/29494)) - -## API - -See API at [TimePicker.types.ts](../src/components/TimePicker/TimePicker.types.ts). - -TimePicker share slots, visual and positioning props with Combobox. Its own specific props are: - -- For selection: `defaultSelectedTime`, `selectedTime` and `onTimeChange`. - - parsing and validation of selected time text: `formatDateToTimeString` -- For generating time options: - - `startHour`, `endHour` and `increment` props are used to generate the predefined time options. - - The options' format can be changed via `hourCycle` and `showSeconds` props. Further customization is available via `formatDateToTimeString`. diff --git a/packages/react-components/react-timepicker-compat-preview/etc/react-timepicker-compat-preview.api.md b/packages/react-components/react-timepicker-compat-preview/etc/react-timepicker-compat-preview.api.md deleted file mode 100644 index 491c5cc745799..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/etc/react-timepicker-compat-preview.api.md +++ /dev/null @@ -1,67 +0,0 @@ -## API Report File for "@fluentui/react-timepicker-compat-preview" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import type { ComboboxProps } from '@fluentui/react-combobox'; -import type { ComboboxSlots } from '@fluentui/react-combobox'; -import type { ComboboxState } from '@fluentui/react-combobox'; -import type { ComponentProps } from '@fluentui/react-utilities'; -import type { ForwardRefComponent } from '@fluentui/react-utilities'; -import * as React_2 from 'react'; -import type { SelectionEvents } from '@fluentui/react-combobox'; -import type { SlotClassNames } from '@fluentui/react-utilities'; - -// @public @deprecated -export function formatDateToTimeString(date: Date, { hourCycle, showSeconds }?: TimeFormatOptions): string; - -// @public @deprecated -export const TimePicker: ForwardRefComponent; - -// @public @deprecated (undocumented) -export const timePickerClassNames: SlotClassNames; - -// @public @deprecated -export type TimePickerErrorType = 'invalid-input' | 'out-of-bounds' | 'required-input'; - -// @public @deprecated -export type TimePickerProps = Omit, 'input'>, 'children' | 'size'> & Pick & TimeFormatOptions & { - startHour?: Hour; - endHour?: Hour; - increment?: number; - dateAnchor?: Date; - selectedTime?: Date | null; - defaultSelectedTime?: Date; - onTimeChange?: (event: TimeSelectionEvents, data: TimeSelectionData) => void; - formatDateToTimeString?: (date: Date) => string; - parseTimeStringToDate?: (time: string | undefined) => TimeStringValidationResult; -}; - -// @public @deprecated (undocumented) -export type TimePickerSlots = ComboboxSlots; - -// @public @deprecated -export type TimePickerState = ComboboxState & Required> & { - submittedText: string | undefined; -}; - -// @public @deprecated (undocumented) -export type TimeSelectionData = { - selectedTime: Date | null; - selectedTimeText: string | undefined; - errorType: TimePickerErrorType | undefined; -}; - -// @public @deprecated (undocumented) -export type TimeSelectionEvents = SelectionEvents | React_2.FocusEvent; - -// @public @deprecated -export const useTimePicker_unstable: (props: TimePickerProps, ref: React_2.Ref) => TimePickerState; - -// @public @deprecated -export const useTimePickerStyles_unstable: (state: TimePickerState) => TimePickerState; - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/react-components/react-timepicker-compat-preview/jest.config.js b/packages/react-components/react-timepicker-compat-preview/jest.config.js deleted file mode 100644 index c4d9b5590e45c..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/jest.config.js +++ /dev/null @@ -1,21 +0,0 @@ -// @ts-check - -/** - * @type {import('@jest/types').Config.InitialOptions} - */ -module.exports = { - displayName: 'react-timepicker-compat-preview', - preset: '../../../jest.preset.js', - transform: { - '^.+\\.tsx?$': [ - 'ts-jest', - { - tsconfig: '/tsconfig.spec.json', - isolatedModules: true, - }, - ], - }, - coverageDirectory: './coverage', - setupFilesAfterEnv: ['./config/tests.js'], - snapshotSerializers: ['@griffel/jest-serializer'], -}; diff --git a/packages/react-components/react-timepicker-compat-preview/just.config.ts b/packages/react-components/react-timepicker-compat-preview/just.config.ts deleted file mode 100644 index b7b2c9a33bf43..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/just.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { preset, task } from '@fluentui/scripts-tasks'; - -preset(); - -task('build', 'build:react-components').cached?.(); diff --git a/packages/react-components/react-timepicker-compat-preview/package.json b/packages/react-components/react-timepicker-compat-preview/package.json deleted file mode 100644 index ae22cf176df4d..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@fluentui/react-timepicker-compat-preview", - "version": "0.2.0", - "description": "Fluent UI TimePicker Compat Component", - "main": "lib-commonjs/index.js", - "module": "lib/index.js", - "typings": "./dist/index.d.ts", - "sideEffects": false, - "repository": { - "type": "git", - "url": "https://github.com/microsoft/fluentui" - }, - "license": "MIT", - "scripts": { - "build": "just-scripts build", - "bundle-size": "monosize measure", - "clean": "just-scripts clean", - "e2e": "cypress run --component", - "e2e:local": "cypress open --component", - "generate-api": "just-scripts generate-api", - "lint": "just-scripts lint", - "start": "yarn storybook", - "storybook": "start-storybook", - "test": "jest --passWithNoTests", - "test-ssr": "test-ssr \"./stories/**/*.stories.tsx\"", - "type-check": "tsc -b tsconfig.json" - }, - "devDependencies": { - "@fluentui/eslint-plugin": "*", - "@fluentui/react-conformance": "*", - "@fluentui/react-conformance-griffel": "*", - "@fluentui/scripts-api-extractor": "*", - "@fluentui/scripts-tasks": "*" - }, - "dependencies": { - "@fluentui/keyboard-keys": "^9.0.7", - "@fluentui/react-combobox": "^9.5.39", - "@fluentui/react-field": "^9.1.47", - "@fluentui/react-jsx-runtime": "^9.0.24", - "@fluentui/react-shared-contexts": "^9.13.2", - "@fluentui/react-theme": "^9.1.16", - "@fluentui/react-utilities": "^9.15.6", - "@griffel/react": "^1.5.14", - "@swc/helpers": "^0.5.1" - }, - "peerDependencies": { - "@types/react": ">=16.8.0 <19.0.0", - "@types/react-dom": ">=16.8.0 <19.0.0", - "react": ">=16.8.0 <19.0.0", - "react-dom": ">=16.8.0 <19.0.0" - }, - "exports": { - ".": { - "types": "./dist/index.d.ts", - "node": "./lib-commonjs/index.js", - "import": "./lib/index.js", - "require": "./lib-commonjs/index.js" - }, - "./package.json": "./package.json" - }, - "beachball": { - "disallowedChangeTypes": [ - "major", - "prerelease" - ] - }, - "files": [ - "*.md", - "dist/*.d.ts", - "lib", - "lib-commonjs" - ] -} diff --git a/packages/react-components/react-timepicker-compat-preview/project.json b/packages/react-components/react-timepicker-compat-preview/project.json deleted file mode 100644 index 83b66e67df444..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@fluentui/react-timepicker-compat-preview", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "sourceRoot": "packages/react-components/react-timepicker-compat-preview/src", - "tags": ["platform:web", "vNext", "compat"], - "implicitDependencies": [] -} diff --git a/packages/react-components/react-timepicker-compat-preview/src/TimePicker.ts b/packages/react-components/react-timepicker-compat-preview/src/TimePicker.ts deleted file mode 100644 index fb8fc412805e6..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/TimePicker.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/TimePicker/index'; diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.cy.tsx b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.cy.tsx deleted file mode 100644 index 85d6fb162a3ae..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.cy.tsx +++ /dev/null @@ -1,212 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import { mount as mountBase } from '@cypress/react'; - -import { FluentProvider } from '@fluentui/react-provider'; -import { teamsLightTheme } from '@fluentui/react-theme'; -import { TimePicker, TimePickerProps } from '@fluentui/react-timepicker-compat-preview'; - -const mount = (element: JSX.Element) => { - mountBase({element}); -}; - -const Default = ({ freeform }: Pick) => { - const [selectedTimeText, setSelectedTimeText] = React.useState(undefined); - const onTimeChange: TimePickerProps['onTimeChange'] = (_ev, data) => { - setSelectedTimeText(data.selectedTimeText); - }; - return ( -
- - {
{selectedTimeText}
} -
- ); -}; - -const Controlled = ({ freeform }: Pick) => { - const [selectedTime, setSelectedTime] = React.useState(null); - const [selectedTimeText, setSelectedTimeText] = React.useState(undefined); - const [value, setValue] = React.useState(''); - - const onTimeChange: TimePickerProps['onTimeChange'] = (_ev, data) => { - setSelectedTime(data.selectedTime); - setSelectedTimeText(data.selectedTimeText); - setValue(data.selectedTimeText ?? ''); - }; - const onInput = (ev: React.ChangeEvent) => { - setValue(ev.target.value); - }; - - return ( -
- - {
{selectedTimeText}
} -
- ); -}; - -const inputSelector = '[role="combobox"]'; -const optionSelector = (index: number) => `[role="option"]:nth-of-type(${index + 1})`; - -describe('TimePicker', () => { - [ - { Example: Default, name: 'uncontrolled' }, - { Example: Controlled, name: 'controlled' }, - ].forEach(({ Example, name }) => { - it(`${name} should open dropdown when clicked`, () => { - mount(); - cy.get(inputSelector).click().get(optionSelector(0)).should('be.visible'); - }); - - it(`${name} should select first option on Enter`, () => { - mount(); - cy.get(inputSelector).click().realPress('Enter').get(inputSelector).should('have.value', '10:00'); - cy.get('#selected-time-text').should('have.text', '10:00'); - }); - - it(`${name} should select second option on ArrowDown+Enter`, () => { - mount(); - cy.get(inputSelector) - .click() - .realPress('ArrowDown') - .realPress('Enter') - .get(inputSelector) - .should('have.value', '11:00'); - cy.get('#selected-time-text').should('have.text', '11:00'); - }); - - it(`${name} should select third option on Click`, () => { - mount(); - cy.get(inputSelector).click().get(optionSelector(2)).click().get(inputSelector).should('have.value', '12:00'); - cy.get('#selected-time-text').should('have.text', '12:00'); - }); - - it(`${name} should select option matching prefix on Enter`, () => { - mount(); - cy.get(inputSelector).click().type('14{enter}').get(inputSelector).should('have.value', '14:00'); - cy.get('#selected-time-text').should('have.text', '14:00'); - }); - - it(`${name} should select 1st option on Enter when no option has matching prefix`, () => { - mount(); - cy.get(inputSelector).click().type('a{enter}').get(inputSelector).should('have.value', '10:00'); - cy.get('#selected-time-text').should('have.text', '10:00'); - }); - - describe('freeform', () => { - it(`${name} should select option matching prefix on Enter`, () => { - mount(); - cy.get(inputSelector).click().type('14{enter}').get(inputSelector).should('have.value', '14:00'); - cy.get('#selected-time-text').should('have.text', '14:00'); - }); - - it(`${name} should keep input value as is on Enter when no option has matching prefix`, () => { - mount(); - cy.get(inputSelector).click().type('a{enter}').get(inputSelector).should('have.value', 'a'); - cy.get('#selected-time-text').should('have.text', 'a'); - }); - - it(`${name} should select input value on blur`, () => { - mount(); - cy.get(inputSelector).click().type('a').get(inputSelector).should('have.value', 'a'); - cy.get('#selected-time-text').should('have.text', ''); - cy.realPress('Tab'); - cy.get('#selected-time-text').should('have.text', 'a'); - }); - - it(`${name} should select input value only on change`, () => { - mount(); - cy.get(inputSelector).click().type('10:3').get(inputSelector).should('have.value', '10:3'); - cy.realPress('Tab'); - cy.get('#selected-time-text').should('have.text', '10:3'); - - cy.get(inputSelector).click().type('0').get(inputSelector).should('have.value', '10:30'); - cy.get('#selected-time-text').should('have.text', '10:3'); - - cy.realPress('Tab'); - cy.get('#selected-time-text').should('have.text', '10:30'); - }); - }); - }); -}); - -describe('TimePicker with custom parsing', () => { - const Example = () => { - const [anchor] = React.useState(() => new Date(2023, 1, 1)); - const formatDateToTimeString = (date: Date) => { - const localeTimeString = date.toLocaleTimeString([], { - hour: 'numeric', - hourCycle: 'h23', - minute: '2-digit', - }); - if (date.getHours() < 12) { - return `Morning: ${localeTimeString}`; - } - if (date.getHours() === 12) { - return `noon: ${localeTimeString}`; - } - return `Afternoon: ${localeTimeString}`; - }; - - const parseTimeStringToDate: TimePickerProps['parseTimeStringToDate'] = (time: string | undefined) => { - if (!time) { - return { date: null }; - } - - const [hours, minutes] = (time.split(' ')[1].match(/\d+/g) ?? []).map(Number); - const date = new Date(anchor.getFullYear(), anchor.getMonth(), anchor.getDate(), hours, minutes); - - return { date }; - }; - - const [selectedTimeText, setSelectedTimeText] = React.useState(undefined); - const onTimeChange: TimePickerProps['onTimeChange'] = (_ev, data) => { - setSelectedTimeText(data.selectedTimeText); - }; - return ( -
- - {
{selectedTimeText}
} -
- ); - }; - it('letter navigation should be case insensitive and select option on enter', () => { - mount(); - cy.get(inputSelector).click().get(optionSelector(0)).should('be.visible'); - - cy.get(inputSelector).click().type('a').realPress('Enter'); - cy.get(inputSelector).should('have.value', 'Afternoon: 13:00'); - cy.get('#selected-time-text').should('have.text', 'Afternoon: 13:00'); - - cy.get(inputSelector).clear().click().type('N').realPress('Enter'); - cy.get(inputSelector).should('have.value', 'noon: 12:00'); - cy.get('#selected-time-text').should('have.text', 'noon: 12:00'); - }); -}); diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.test.tsx b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.test.tsx deleted file mode 100644 index fb6b6f54af0e7..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.test.tsx +++ /dev/null @@ -1,210 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import { render, fireEvent } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { Field } from '@fluentui/react-components'; -import { isConformant } from '../../testing/isConformant'; -import { TimePicker } from './TimePicker'; -import { TimePickerProps } from './TimePicker.types'; - -const dateAnchor = new Date('November 25, 2021 01:00:00'); - -describe('TimePicker', () => { - // mock locale to make sure the test generates same result as browser, and not affected by the test runner's locale - const originalToLocaleTimeString = Date.prototype.toLocaleTimeString; - beforeAll(() => { - // eslint-disable-next-line no-extend-native - Date.prototype.toLocaleTimeString = function (locales?: string | string[], options?: Intl.DateTimeFormatOptions) { - return originalToLocaleTimeString.call(this, locales ?? 'en-US', options); - }; - }); - afterAll(() => { - // eslint-disable-next-line no-extend-native - Date.prototype.toLocaleTimeString = originalToLocaleTimeString; - }); - - isConformant({ - Component: TimePicker, - displayName: 'TimePicker', - primarySlot: 'input', - testOptions: { - 'has-static-classnames': [ - { - props: { - open: true, - // Portal messes with the classNames test, so rendering the listbox inline here - inlinePopup: true, - }, - }, - ], - }, - }); - - it('generates the formatted option', () => { - const { getByRole, getAllByRole } = render(); - - const input = getByRole('combobox'); - userEvent.click(input); - const options = getAllByRole('option'); - expect(options.length).toBe(2); - expect(options[0].textContent).toBe('8:00 AM'); - expect(options[1].textContent).toBe('8:30 AM'); - }); - - it('generates the formatted option using formatDateToTimeString', () => { - const { getByRole, getAllByRole } = render( - 'custom'} />, - ); - - const input = getByRole('combobox'); - userEvent.click(input); - expect(getAllByRole('option')[0].textContent).toBe('custom'); - }); - - it('shows controlled time correctly', () => { - const TestExample = () => { - const [selectedTime, setSelectedTime] = React.useState(dateAnchor); - const onTimeChange: TimePickerProps['onTimeChange'] = (_e, data) => setSelectedTime(data.selectedTime); - return ( - - ); - }; - - const { getByRole, getAllByRole } = render(); - - const input = getByRole('combobox'); - userEvent.click(input); - expect(getAllByRole('option')[1].getAttribute('aria-selected')).toBe('true'); // '1:00' is selected - - userEvent.click(getAllByRole('option')[10]); - expect(getByRole('combobox').getAttribute('value')).toBe('10:00 AM'); - }); - - it('when wrapped in Field, sets default aria-labelledby on chevron icon', () => { - const { getByRole } = render( - - - , - ); - - const chevronIcon = getByRole('button'); - expect(chevronIcon.getAttribute('aria-labelledby')).not.toBeNull(); - }); - - describe('freeform', () => { - const handleTimeSelect = jest.fn(); - - const ControlledFreeFormExample = () => { - const [selectedTime, setSelectedTime] = React.useState(dateAnchor); - const onTimeChange: TimePickerProps['onTimeChange'] = (e, data) => { - handleTimeSelect(e, data); - setSelectedTime(data.selectedTime); - }; - return ( - - ); - }; - - const UnControlledFreeFormExample = () => ( - - ); - - beforeEach(() => { - handleTimeSelect.mockClear(); - }); - - it.each` - name | Component - ${'uncontrolled'} | ${UnControlledFreeFormExample} - ${'controlled'} | ${ControlledFreeFormExample} - `( - '$name - when input value is not prefix of any option, submit the value as selectedTime on Enter', - ({ Component }) => { - const { getByRole } = render(); - const input = getByRole('combobox'); - userEvent.type(input, '111{enter}'); - expect(handleTimeSelect).toHaveBeenCalledTimes(1); - expect(handleTimeSelect).toHaveBeenCalledWith( - expect.anything(), - expect.objectContaining({ selectedTime: null, selectedTimeText: '111', errorType: 'invalid-input' }), - ); - }, - ); - - it.each` - name | Component - ${'uncontrolled'} | ${UnControlledFreeFormExample} - ${'controlled'} | ${ControlledFreeFormExample} - `('$name - when input value is prefix of an option, select the option from dropdown on Enter', ({ Component }) => { - const { getByRole } = render(); - const input = getByRole('combobox'); - userEvent.type(input, '11:{enter}'); - expect(handleTimeSelect).toHaveBeenCalledTimes(1); - expect(handleTimeSelect).toHaveBeenCalledWith( - expect.anything(), - expect.objectContaining({ selectedTimeText: '11:00 AM', errorType: undefined }), - ); - }); - - it.each` - name | Component - ${'uncontrolled'} | ${UnControlledFreeFormExample} - ${'controlled'} | ${ControlledFreeFormExample} - `('$name - trigger onTimeChange only when value change', ({ Component }) => { - const { getByRole, getAllByRole } = render(); - - const input = getByRole('combobox'); - - // Call onTimeChange when select an option - userEvent.click(input); - userEvent.click(getAllByRole('option')[1]); - expect(handleTimeSelect).toHaveBeenCalledTimes(1); - expect(handleTimeSelect).toHaveBeenCalledWith( - expect.anything(), - expect.objectContaining({ selectedTimeText: '10:30 AM' }), - ); - handleTimeSelect.mockClear(); - - // Do not call onTimeChange on Enter when the value remains the same - fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' }); - expect(handleTimeSelect).toHaveBeenCalledTimes(0); - - // Call onTimeChange on Enter when the value changes - userEvent.type(input, '111{enter}'); - expect(handleTimeSelect).toHaveBeenCalledTimes(1); - expect(handleTimeSelect).toHaveBeenCalledWith( - expect.anything(), - expect.objectContaining({ selectedTimeText: '10:30 AM111', errorType: 'invalid-input' }), - ); - }); - - it.each` - name | Component - ${'uncontrolled'} | ${UnControlledFreeFormExample} - ${'controlled'} | ${ControlledFreeFormExample} - `('$name - trigger onTimeChange on blur when value change', ({ Component }) => { - const { getByRole } = render(); - - const input = getByRole('combobox'); - const expandIcon = getByRole('button'); - - // Do not call onTimeChange when clicking dropdown icon - userEvent.type(input, '111'); - userEvent.click(expandIcon); - expect(handleTimeSelect).toHaveBeenCalledTimes(0); - - // Call onTimeChange on focus lose - userEvent.tab(); - expect(handleTimeSelect).toHaveBeenCalledWith( - expect.anything(), - expect.objectContaining({ selectedTimeText: '111' }), - ); - }); - }); -}); diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.tsx b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.tsx deleted file mode 100644 index bfd6966c486dd..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import type { ForwardRefComponent } from '@fluentui/react-utilities'; -import { useTimePicker_unstable } from './useTimePicker'; -import { useTimePickerStyles_unstable } from './useTimePickerStyles.styles'; -import type { TimePickerProps } from './TimePicker.types'; -import { renderCombobox_unstable, useComboboxContextValues } from '@fluentui/react-combobox'; -import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts'; - -/** - * TimePicker Compat component - * @deprecated use \@fluentui/react-timepicker-compat - */ -export const TimePicker: ForwardRefComponent = React.forwardRef((props, ref) => { - const state = useTimePicker_unstable(props, ref); - - const contextValues = useComboboxContextValues(state); - - useTimePickerStyles_unstable(state); - useCustomStyleHook_unstable('useTimePickerCompatStyles_unstable')(state); - - return renderCombobox_unstable(state, contextValues); -}); - -TimePicker.displayName = 'TimePicker'; diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.types.ts b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.types.ts deleted file mode 100644 index 46498526ff7fd..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/TimePicker.types.ts +++ /dev/null @@ -1,183 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import type { ComboboxSlots, ComboboxState, ComboboxProps, SelectionEvents } from '@fluentui/react-combobox'; -import type { ComponentProps } from '@fluentui/react-utilities'; - -export type Hour = - | 0 - | 1 - | 2 - | 3 - | 4 - | 5 - | 6 - | 7 - | 8 - | 9 - | 10 - | 11 - | 12 - | 13 - | 14 - | 15 - | 16 - | 17 - | 18 - | 19 - | 20 - | 21 - | 22 - | 23 - | 24; - -/** - * Data structure for rendering options in the TimePicker. - */ -export type TimePickerOption = { - /** - * The Date object associated with the option. - */ - date: Date; - - /** - * A unique identifier for the option. - */ - key: string; - - /** - * The display text for the option within the Combobox dropdown. - */ - text: string; -}; - -/** - * Error types returned by the `onValidationResult` callback. - * @deprecated use \@fluentui/react-timepicker-compat - */ -export type TimePickerErrorType = 'invalid-input' | 'out-of-bounds' | 'required-input'; - -export type TimeStringValidationResult = { - date: Date | null; - errorType?: TimePickerErrorType; -}; - -/** - * @deprecated use \@fluentui/react-timepicker-compat - */ -export type TimePickerSlots = ComboboxSlots; - -/** - * @deprecated use \@fluentui/react-timepicker-compat - */ -export type TimeSelectionEvents = SelectionEvents | React.FocusEvent; -/** - * @deprecated use \@fluentui/react-timepicker-compat - */ -export type TimeSelectionData = { - /** - * The Date object associated with the selected option. For freeform TimePicker it can also be the Date object parsed from the user input. - */ - selectedTime: Date | null; - /** - * The display text for the selected option. For freeform TimePicker it can also be the value in user input. - */ - selectedTimeText: string | undefined; - /** - * The error type for the selected option. - */ - errorType: TimePickerErrorType | undefined; -}; - -export type TimeFormatOptions = { - /** - * A string value indicating whether the 12-hour format ("h11", "h12") or the 24-hour format ("h23", "h24") should be used. - * - 'h11' and 'h23' start with hour 0 and go up to 11 and 23 respectively. - * - 'h12' and 'h24' start with hour 1 and go up to 12 and 24 respectively. - * @default undefined - */ - hourCycle?: 'h11' | 'h12' | 'h23' | 'h24' | undefined; - - /** - * If true, show seconds in the dropdown options and consider seconds for default validation purposes. - */ - showSeconds?: boolean; -}; - -/** - * TimePicker Props - * @deprecated use \@fluentui/react-timepicker-compat - */ -export type TimePickerProps = Omit, 'input'>, 'children' | 'size'> & - Pick< - ComboboxProps, - | 'appearance' - | 'defaultOpen' - | 'defaultValue' - | 'inlinePopup' - | 'onOpenChange' - | 'open' - | 'placeholder' - | 'positioning' - | 'size' - | 'value' - | 'mountNode' - | 'freeform' - > & - TimeFormatOptions & { - /** - * Start hour (inclusive) for the time range, 0-24. - */ - startHour?: Hour; - - /** - * End hour (exclusive) for the time range, 0-24. - */ - endHour?: Hour; - - /** - * Time increment, in minutes, of the options in the dropdown. - */ - increment?: number; - - /** - * The date in which all dropdown options are based off of. - */ - dateAnchor?: Date; - - /** - * Currently selected time in the TimePicker. - */ - selectedTime?: Date | null; - - /** - * Default selected time in the TimePicker, for uncontrolled scenarios. - */ - defaultSelectedTime?: Date; - - /** - * Callback for when a time selection is made. - */ - onTimeChange?: (event: TimeSelectionEvents, data: TimeSelectionData) => void; - - /** - * Customizes the formatting of date strings displayed in dropdown options. - */ - formatDateToTimeString?: (date: Date) => string; - - /** - * In the freeform TimePicker, customizes the parsing from the input time string into a Date and provides custom validation. - */ - parseTimeStringToDate?: (time: string | undefined) => TimeStringValidationResult; - }; - -/** - * State used in rendering TimePicker - * @deprecated use \@fluentui/react-timepicker-compat - */ -export type TimePickerState = ComboboxState & - Required> & { - /** - * Submitted text from the input field. It is used to determine if the input value has changed when user submit a new value on Enter or blur from input. - */ - submittedText: string | undefined; - }; diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/index.ts b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/index.ts deleted file mode 100644 index 08b70909de0d0..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './TimePicker'; -export * from './TimePicker.types'; -export * from './useTimePicker'; -export * from './useTimePickerStyles.styles'; -// eslint-disable-next-line deprecation/deprecation -export { formatDateToTimeString } from './timeMath'; diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/timeMath.test.ts b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/timeMath.test.ts deleted file mode 100644 index ed3e615657ee7..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/timeMath.test.ts +++ /dev/null @@ -1,232 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import { - dateToKey, - keyToDate, - formatDateToTimeString, - getDateEndAnchor, - getDateStartAnchor, - getTimesBetween, - getDateFromTimeString, -} from './timeMath'; - -describe('Time Utilities', () => { - describe('dateToKey', () => { - it('should return empty string for null date', () => { - expect(dateToKey(null)).toBe(''); - }); - - it('should return "invalid" for invalid dates', () => { - const invalidDate = new Date('invalid-date'); - expect(dateToKey(invalidDate)).toBe('invalid'); - }); - - it('should return ISO string for valid dates', () => { - const date = new Date(2023, 9, 6); - expect(dateToKey(date)).toBe(date.toISOString()); - }); - }); - - describe('keyToDate', () => { - it('should return null for empty string', () => { - expect(keyToDate('')).toBeNull(); - }); - - it('should return null for "invalid" string', () => { - expect(keyToDate('invalid')).toBeNull(); - }); - - it('should return date for valid ISO string', () => { - const date = new Date(2023, 9, 6); - expect(keyToDate(date.toISOString())).toEqual(date); - }); - }); - - describe('dateToKey and keyToDate correspondence', () => { - it('should be inverses of each other for valid dates', () => { - const originalDate = new Date(2023, 9, 6, 23, 45, 12); - const key = dateToKey(originalDate); - const revertedDate = keyToDate(key); - - expect(revertedDate?.getTime()).toEqual(originalDate.getTime()); - }); - - it('should be inverses of each other for null date', () => { - const originalDate = null; - const key = dateToKey(originalDate); - const revertedDate = keyToDate(key); - - expect(revertedDate).toEqual(originalDate); - }); - - it('should be inverses of each other for invalid dates', () => { - const originalDate = new Date('invalid-date'); - const key = dateToKey(originalDate); - const revertedDate = keyToDate(key); - - expect(revertedDate).toBeNull(); - }); - }); - - describe('formatDateToTimeString', () => { - const testDate = new Date(2023, 9, 6, 23, 45, 12); - - it('should format time in 24-hour format without seconds', () => { - expect(formatDateToTimeString(testDate, { hourCycle: 'h23' })).toBe('23:45'); - }); - - it('should format time in 24-hour format with seconds', () => { - expect(formatDateToTimeString(testDate, { showSeconds: true, hourCycle: 'h23' })).toBe('23:45:12'); - }); - - it('should format time in 12-hour format with seconds', () => { - expect(formatDateToTimeString(testDate, { showSeconds: true, hourCycle: 'h11' })).toBe('11:45:12 PM'); - }); - - it('should format midnight correctly in 24-hour format', () => { - const midnight = new Date(2023, 9, 7, 0, 0, 0); - expect(formatDateToTimeString(midnight, { hourCycle: 'h23' })).toBe('00:00'); - }); - - it('should format time in Japanese locale', () => { - const { toLocaleTimeString } = Date.prototype; - const toLocaleTimeStringMock = jest.spyOn(Date.prototype, 'toLocaleTimeString'); - // Mock toLocaleTimeString to simulate running in a Japanese locale - toLocaleTimeStringMock.mockImplementationOnce(function (this: Date, _locales, options) { - return toLocaleTimeString.call(this, 'ja-JP', { ...options, timeZone: 'Japan' }); - }); - - expect( - formatDateToTimeString(new Date(Date.UTC(2023, 9, 6, 14, 45, 12)), { showSeconds: true, hourCycle: 'h11' }), - ).toBe('午後11:45:12'); - - toLocaleTimeStringMock.mockClear(); - }); - - it('should format time without prefix 0 in US local', () => { - const { toLocaleTimeString } = Date.prototype; - const toLocaleTimeStringMock = jest.spyOn(Date.prototype, 'toLocaleTimeString'); - // Mock toLocaleTimeString to simulate running in PST locale - toLocaleTimeStringMock.mockImplementationOnce(function (this: Date, _locales, options) { - return toLocaleTimeString.call(this, 'en-US', { ...options, timeZone: 'America/Los_Angeles' }); - }); - - expect(formatDateToTimeString(new Date(Date.UTC(2023, 9, 6, 15, 45, 12)))).toBe('8:45 AM'); - - toLocaleTimeStringMock.mockClear(); - }); - }); - - describe('Anchor Date Calculations', () => { - it('should calculate the correct start anchor date', () => { - const date = new Date(2023, 9, 6); - const result = getDateStartAnchor(date, 5); - expect(result.getHours()).toBe(5); - }); - - it('should calculate the correct end anchor date (same day)', () => { - const date = new Date(2023, 9, 6); - const result = getDateEndAnchor(date, 5, 10); - expect(result.getHours()).toBe(10); - }); - - it('should calculate the correct end anchor date (next day)', () => { - const date = new Date(2023, 9, 6); - const result = getDateEndAnchor(date, 10, 5); - expect(result.getHours()).toBe(5); - expect(result.getDate()).toBe(7); - }); - - it('should handle the endHour being 24 correctly', () => { - const date = new Date(2023, 9, 6); - const result = getDateEndAnchor(date, 10, 24); - expect(result.getHours()).toBe(0); - expect(result.getDate()).toBe(7); - }); - }); - - describe('getTimesBetween', () => { - it('should return correct Date objects with 15-minute increment', () => { - const start = new Date('January 1, 2023 10:00:00'); - const end = new Date('January 1, 2023 11:00:00'); - const result = getTimesBetween(start, end, 15); - - expect(result.length).toBe(4); - result.forEach((date, i) => expect(date.getMinutes()).toBe(15 * i)); - }); - - it('should return correct Date objects spanning across midnight with 30-minute increment', () => { - const start = new Date('January 1, 2023 23:30:00'); - const end = new Date('January 2, 2023 00:30:00'); - const result = getTimesBetween(start, end, 30); - - expect(result.length).toBe(2); - expect([result[0].getHours(), result[0].getMinutes()]).toEqual([23, 30]); - expect([result[1].getHours(), result[1].getMinutes()]).toEqual([0, 0]); - }); - - it('should return correct Date objects for day light saving', () => { - const start = new Date('2023-11-05T01:00:00-07:00'); // UTC-7 is PDT - const end = new Date('2023-11-05T03:00:00-08:00'); // UTC-8 is PST - const result = getTimesBetween(start, end, 60); - - expect(result.length).toBe(3); - expect( - result.map(date => date.toLocaleString('en-US', { timeZone: 'America/Los_Angeles', timeZoneName: 'short' })), - ).toMatchInlineSnapshot(` - Array [ - "11/5/2023, 1:00:00 AM PDT", - "11/5/2023, 1:00:00 AM PST", - "11/5/2023, 2:00:00 AM PST", - ] - `); - }); - }); - - describe('getDateFromTimeString', () => { - const dateStartAnchor = new Date('November 25, 2023 12:00:00'); - const dateEndAnchor = new Date('November 26, 2023 12:00:00'); - - it('returns a valid date when given a valid time string', () => { - const result = getDateFromTimeString('2:30 PM', dateStartAnchor, dateEndAnchor, { - hourCycle: 'h11', - showSeconds: false, - }); - expect(result.date?.getHours()).toBe(14); - expect(result.date?.getMinutes()).toBe(30); - expect(result.errorType).toBeUndefined(); - }); - - it('returns an errorType when no time string is provided', () => { - const result = getDateFromTimeString(undefined, dateStartAnchor, dateEndAnchor, {}); - expect(result.date).toBeNull(); - expect(result.errorType).toBe('required-input'); - }); - - it('returns an errorType for an invalid time string', () => { - const result = getDateFromTimeString('25:30', dateStartAnchor, dateEndAnchor, {}); - expect(result.date).toBeNull(); - expect(result.errorType).toBe('invalid-input'); - }); - - it('returns a date in the next day and an out-of-bounds errorType when the time is before the dateStartAnchor', () => { - const result = getDateFromTimeString('11:30 AM', dateStartAnchor, new Date('November 25, 2023 13:00:00'), { - hourCycle: 'h11', - showSeconds: false, - }); - expect(result.date?.getDate()).toBe(26); - expect(result.date?.getHours()).toBe(11); - expect(result.date?.getMinutes()).toBe(30); - expect(result.errorType).toBe('out-of-bounds'); - }); - - it('returns an out-of-bounds errorType when the time is same as the dateEndAnchor', () => { - const result = getDateFromTimeString('1:00 PM', dateStartAnchor, new Date('November 25, 2023 13:00:00'), { - hourCycle: 'h11', - showSeconds: false, - }); - expect(result.date?.getHours()).toBe(13); - expect(result.date?.getMinutes()).toBe(0); - expect(result.errorType).toBe('out-of-bounds'); - }); - }); -}); diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/timeMath.ts b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/timeMath.ts deleted file mode 100644 index cac562a35e9c3..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/timeMath.ts +++ /dev/null @@ -1,198 +0,0 @@ -import type { TimeFormatOptions, TimeStringValidationResult } from './TimePicker.types'; - -function isValidDate(date: Date): boolean { - return !isNaN(date.getTime()); -} - -/** - * Converts a Date object to a string key. - */ -export function dateToKey(date: Date | null): string { - if (!date) { - return ''; - } - if (!isValidDate(date)) { - return 'invalid'; - } - return date.toISOString(); -} - -/** - * Converts a string key back to a Date object. - * Returns undefined for keys that don't represent valid dates. - */ -export function keyToDate(key: string): Date | null { - if (key === '' || key === 'invalid') { - return null; - } - const date = new Date(key); - return isValidDate(date) ? date : null; -} - -/** - * Formats a Date object into a time string based on provided options. - * - * @param date - The Date object to be formatted. - * @param options - Formatting options. It has two properties: - * 1. hourCycle (default: undefined): Determines if the time format should be 12-hour or 24-hour. - * 2. showSeconds (default: false): Determines if the seconds should be included in the formatted string. - * @returns Formatted time string based on the given options. - * - * @example - * const date = new Date(2023, 9, 6, 23, 45, 12); - * formatDateToTimeString(date); // Returns "23:45" in CET - * formatDateToTimeString(date, \{ showSeconds: true \}); // Returns "23:45:12" in CET - * formatDateToTimeString(date, \{ hourCycle: 'h12', showSeconds: true \}); // Returns "11:45:12 PM" in CET - * - * @deprecated use \@fluentui/react-timepicker-compat - */ -export function formatDateToTimeString(date: Date, { hourCycle, showSeconds }: TimeFormatOptions = {}): string { - return date.toLocaleTimeString(undefined, { - hour: 'numeric', - hourCycle, - minute: '2-digit', - second: showSeconds ? '2-digit' : undefined, - }); -} - -/** - * Get the start date anchor based on the provided parameters. - * @example - * const date = new Date(2023, 9, 6); // October 6, 2023 - * getStartAnchorDate(date, 5); // Returns a date for October 6, 2023, 05:00:00 - */ -export function getDateStartAnchor(dateAnchor: Date, startHour: number): Date { - const startDate = new Date(dateAnchor); - startDate.setHours(startHour, 0, 0, 0); - return startDate; -} - -/** - * Get the end date anchor based on the provided parameters. - * @example - * const date = new Date(2023, 9, 6); // October 6, 2023 - * getEndAnchorDate(date, 5, 10); // Returns a date for October 6, 2023, 10:00:00 - * getEndAnchorDate(date, 10, 5); // Returns a date for October 7, 2023, 05:00:00 (next day due to hour conditions) - */ -export function getDateEndAnchor(dateAnchor: Date, startHour: number, endHour: number): Date { - const endDate = new Date(dateAnchor); - if (startHour > endHour || endHour === 24) { - endDate.setDate(endDate.getDate() + 1); - } - endDate.setHours(endHour === 24 ? 0 : endHour, 0, 0, 0); - return endDate; -} - -/** - * Generates an array of Date objects between two given Date anchors. - * - * @param dateStartAnchor - The starting Date anchor. - * @param dateEndAnchor - The ending Date anchor. - * @param increment - The minute increment between each Date in the resulting array. - * @returns - An array of Date objects. - * - * @example - * const start = new Date(2023, 0, 1, 10, 0); // Jan 1, 2023 10:00:00 AM - * const end = new Date(2023, 0, 1, 11, 0); // Jan 1, 2023 11:00:00 AM - * getTimesBetween(start, end, 15); // Returns array with Dates [10:00, 10:15, 10:30, 10:45] - */ -export function getTimesBetween(dateStartAnchor: Date, dateEndAnchor: Date, increment: number) { - if (increment <= 0) { - // eslint-disable-next-line no-console - console.error('Increment value should be a positive number.'); - return []; - } - - const result: Date[] = []; - - const startDate = new Date(dateStartAnchor); - while (startDate < dateEndAnchor) { - result.push(new Date(startDate)); - startDate.setMinutes(startDate.getMinutes() + increment); - } - - return result; -} - -const REGEX_SHOW_SECONDS_HOUR_12 = /^((1[0-2]|0?[0-9]):([0-5][0-9]):([0-5][0-9])\s([AaPp][Mm]))$/; -const REGEX_HIDE_SECONDS_HOUR_12 = /^((1[0-2]|0?[0-9]):[0-5][0-9]\s([AaPp][Mm]))$/; -const REGEX_SHOW_SECONDS_HOUR_24 = /^([0-1]?[0-9]|2[0-4]):[0-5][0-9]:[0-5][0-9]$/; -const REGEX_HIDE_SECONDS_HOUR_24 = /^([0-1]?[0-9]|2[0-4]):[0-5][0-9]$/; - -/** - * Calculates a new date from the user-selected time string based on anchor dates. - * Returns an object containing a date if the provided time string is valid, and an optional string indicating the type of error. - * - * @param time - The time string to be parsed (e.g., "2:30 PM", "15:45:20"). - * @param dateStartAnchor - The start anchor date. - * @param dateEndAnchor - The end anchor date. - * @param timeFormatOptions - format options for the provided time string. - * @returns An object with either a 'date' or an 'errorType'. - * - * @example - * Input: time="2:30 PM", dateStartAnchor=2023-10-06T12:00:00Z, dateEndAnchor=2023-10-07T12:00:00Z, options={hourCycle: 'h12', showSeconds: false} - * Output: { date: 2023-10-06T14:30:00Z } - * - * Input: time="25:30" - * Output: { errorType: 'invalid-input' } - * - * Input: time="1:30 AM", dateStartAnchor=2023-10-06T03:00:00Z, dateEndAnchor=2023-10-07T03:00:00Z, options={hourCycle: 'h12', showSeconds: false} - * Output: { date: 2023-10-07T01:30:00Z, errorType: 'out-of-bounds' } - */ -export function getDateFromTimeString( - time: string | undefined, - dateStartAnchor: Date, - dateEndAnchor: Date, - timeFormatOptions: TimeFormatOptions, -): TimeStringValidationResult { - if (!time) { - return { date: null, errorType: 'required-input' }; - } - - const { hourCycle, showSeconds } = timeFormatOptions; - const hour12 = hourCycle === 'h11' || hourCycle === 'h12'; - - // Determine the regex based on format - const regex = hour12 - ? showSeconds - ? REGEX_SHOW_SECONDS_HOUR_12 - : REGEX_HIDE_SECONDS_HOUR_12 - : showSeconds - ? REGEX_SHOW_SECONDS_HOUR_24 - : REGEX_HIDE_SECONDS_HOUR_24; - - if (!regex.test(time)) { - return { date: null, errorType: 'invalid-input' }; - } - - const timeParts = /^(\d\d?):(\d\d):?(\d\d)? ?([ap]m)?/i.exec(time); - if (!timeParts) { - return { date: null, errorType: 'invalid-input' }; - } - - const [, selectedHours, minutes, seconds, amPm] = timeParts; - let hours = selectedHours; - - // Adjust for 12-hour time format if needed - if (hour12 && amPm) { - if (amPm.toLowerCase() === 'pm' && +hours !== 12) { - hours = (+hours + 12).toString(); - } else if (amPm.toLowerCase() === 'am' && +hours === 12) { - hours = '0'; - } - } - - const adjustedDate = new Date(dateStartAnchor); - adjustedDate.setHours(+hours, +minutes, seconds ? +seconds : 0); - - // Adjust to the next day if the selected time is before the anchor time - if (adjustedDate < dateStartAnchor) { - adjustedDate.setDate(adjustedDate.getDate() + 1); - } - - if (adjustedDate >= dateEndAnchor) { - return { date: adjustedDate, errorType: 'out-of-bounds' }; - } - - return { date: adjustedDate }; -} diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/useTimePicker.tsx b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/useTimePicker.tsx deleted file mode 100644 index 29a73bd91c230..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/useTimePicker.tsx +++ /dev/null @@ -1,234 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import { - elementContains, - mergeCallbacks, - useControllableState, - useEventCallback, - useId, - useMergedRefs, -} from '@fluentui/react-utilities'; -import { Enter } from '@fluentui/keyboard-keys'; -import type { Hour, TimePickerOption, TimePickerProps, TimePickerState, TimeSelectionData } from './TimePicker.types'; -import { ComboboxProps, useCombobox_unstable, Option } from '@fluentui/react-combobox'; -import { useFieldContext_unstable as useFieldContext } from '@fluentui/react-field'; -import { - dateToKey, - keyToDate, - formatDateToTimeString as defaultFormatDateToTimeString, - getDateStartAnchor, - getDateEndAnchor, - getTimesBetween, - getDateFromTimeString, -} from './timeMath'; - -/** - * Create the state required to render TimePicker. - * - * The returned state can be modified with hooks such as useTimePickerStyles_unstable, - * before being passed to renderTimePicker_unstable. - * - * @param props - props from this instance of TimePicker - * @param ref - reference to root HTMLElement of TimePicker - * - * @deprecated use \@fluentui/react-timepicker-compat - */ -export const useTimePicker_unstable = (props: TimePickerProps, ref: React.Ref): TimePickerState => { - const { - dateAnchor: dateAnchorInProps, - defaultSelectedTime: defaultSelectedTimeInProps, - endHour = 24, - formatDateToTimeString = defaultFormatDateToTimeString, - hourCycle, - increment = 30, - onTimeChange, - selectedTime: selectedTimeInProps, - showSeconds = false, - startHour = 0, - parseTimeStringToDate: parseTimeStringToDateInProps, - ...rest - } = props; - const { freeform = false } = rest; - - const { dateStartAnchor, dateEndAnchor } = useStableDateAnchor( - dateAnchorInProps ?? selectedTimeInProps ?? defaultSelectedTimeInProps, - startHour, - endHour, - ); - - const options: TimePickerOption[] = React.useMemo( - () => - getTimesBetween(dateStartAnchor, dateEndAnchor, increment).map(time => ({ - date: time, - key: dateToKey(time), - text: formatDateToTimeString(time, { showSeconds, hourCycle }), - })), - [dateEndAnchor, dateStartAnchor, formatDateToTimeString, hourCycle, increment, showSeconds], - ); - - const [selectedTime, setSelectedTime] = useControllableState({ - state: selectedTimeInProps, - defaultState: defaultSelectedTimeInProps, - initialState: null, - }); - - const [submittedText, setSubmittedText] = React.useState(undefined); - - const selectTime: TimePickerProps['onTimeChange'] = useEventCallback((e, data) => { - setSelectedTime(data.selectedTime); - setSubmittedText(data.selectedTimeText); - onTimeChange?.(e, data); - }); - - const selectedOptions = React.useMemo(() => { - const selectedTimeKey = dateToKey(selectedTime); - const selectedOption = options.find(date => date.key === selectedTimeKey); - return selectedOption ? [selectedOption.key] : []; - }, [options, selectedTime]); - - const handleOptionSelect: ComboboxProps['onOptionSelect'] = useEventCallback((e, data) => { - if (freeform && data.optionValue === undefined) { - // Combobox clears selection when input value not matching any option; but we allow this case in freeform TimePicker. - return; - } - const timeSelectionData: TimeSelectionData = { - selectedTime: keyToDate(data.optionValue ?? ''), - selectedTimeText: data.optionText, - errorType: undefined, - }; - selectTime(e, timeSelectionData); - }); - - const baseState = useCombobox_unstable( - { - autoComplete: 'off', - ...rest, - selectedOptions, - onOptionSelect: handleOptionSelect, - children: options.map(date => ( - - )), - }, - ref, - ); - - const defaultParseTimeStringToDate = React.useCallback( - (time: string | undefined) => - getDateFromTimeString(time, dateStartAnchor, dateEndAnchor, { hourCycle, showSeconds }), - [dateEndAnchor, dateStartAnchor, hourCycle, showSeconds], - ); - - const state: TimePickerState = { - ...baseState, - freeform, - parseTimeStringToDate: parseTimeStringToDateInProps ?? defaultParseTimeStringToDate, - submittedText, - }; - - useDefaultChevronIconLabel(state); - useSelectTimeFromValue(state, selectTime); - - return state; -}; - -/** - * Provides stable start and end date anchors based on the provided date and time parameters. - * The hook ensures that the memoization remains consistent even if new Date objects representing the same date are provided. - */ -const useStableDateAnchor = (providedDate: Date | undefined, startHour: Hour, endHour: Hour) => { - const [fallbackDateAnchor] = React.useState(() => new Date()); - - const providedDateKey = dateToKey(providedDate ?? null); - - return React.useMemo(() => { - const dateAnchor = providedDate ?? fallbackDateAnchor; - - const dateStartAnchor = getDateStartAnchor(dateAnchor, startHour); - const dateEndAnchor = getDateEndAnchor(dateAnchor, startHour, endHour); - - return { dateStartAnchor, dateEndAnchor }; - // `providedDate`'s stable key representation is used as dependency instead of the Date object. This ensures that the memoization remains stable when a new Date object representing the same date is passed in. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [endHour, fallbackDateAnchor, providedDateKey, startHour]); -}; - -/** - * Mimics the behavior of the browser's change event for a freeform TimePicker. - * The provided callback is called when input changed and: - * - Enter/Tab key is pressed on the input. - * - TimePicker loses focus, signifying a possible change. - */ -const useSelectTimeFromValue = (state: TimePickerState, callback: TimePickerProps['onTimeChange']) => { - const { activeOption, freeform, parseTimeStringToDate, submittedText, setActiveOption, value } = state; - - // Base Combobox has activeOption default to first option in dropdown even if it doesn't match input value, and Enter key will select it. - // This effect ensures that the activeOption is cleared when the input doesn't match any option. - // This behavior is specific to a freeform TimePicker where the input value is treated as a valid time even if it's not in the dropdown. - React.useEffect(() => { - if (freeform && value) { - setActiveOption(prevActiveOption => { - if (prevActiveOption?.text && prevActiveOption.text.toLowerCase().indexOf(value.toLowerCase()) === 0) { - return prevActiveOption; - } - return undefined; - }); - } - }, [freeform, setActiveOption, value]); - - const selectTimeFromValue = useEventCallback( - (e: React.KeyboardEvent | React.FocusEvent) => { - if (!freeform) { - return; - } - - const { date: selectedTime, errorType } = parseTimeStringToDate(value); - - // Only triggers callback when the text in input has changed. - if (submittedText !== value) { - callback?.(e, { selectedTime, selectedTimeText: value, errorType }); - } - }, - ); - - const handleKeyDown: ComboboxProps['onKeyDown'] = useEventCallback(e => { - if (!activeOption && e.key === Enter) { - selectTimeFromValue(e); - } - }); - state.root.onKeyDown = mergeCallbacks(handleKeyDown, state.root.onKeyDown); - - const rootRef = React.useRef(null); - state.root.ref = useMergedRefs(state.root.ref, rootRef); - - if (state.listbox) { - state.listbox.tabIndex = -1; // allows it to be the relatedTarget of a blur event. - } - - if (state.expandIcon) { - state.expandIcon.tabIndex = -1; // allows it to be the relatedTarget of a blur event. - } - - const handleInputBlur = useEventCallback((e: React.FocusEvent) => { - const isOutside = e.relatedTarget ? !elementContains(rootRef.current, e.relatedTarget) : true; - if (isOutside) { - selectTimeFromValue(e); - } - }); - state.input.onBlur = mergeCallbacks(handleInputBlur, state.input.onBlur); -}; - -/** - * Provides a default aria-labelledby for the chevron icon if the TimePicker is wrapped in a Field. - */ -const useDefaultChevronIconLabel = (state: TimePickerState) => { - const fieldContext = useFieldContext(); - const chevronDefaultId = useId('timepicker-chevron-'); - const defaultLabelFromCombobox = 'Open'; - - if (fieldContext?.labelId && state.expandIcon?.['aria-label'] === defaultLabelFromCombobox) { - const chevronId = state.expandIcon.id ?? chevronDefaultId; - state.expandIcon['aria-labelledby'] = `${chevronId} ${fieldContext.labelId}`; - } -}; diff --git a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/useTimePickerStyles.styles.ts b/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/useTimePickerStyles.styles.ts deleted file mode 100644 index e402386f6babc..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/components/TimePicker/useTimePickerStyles.styles.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import { makeStyles, mergeClasses } from '@griffel/react'; -import type { SlotClassNames } from '@fluentui/react-utilities'; -import type { TimePickerSlots, TimePickerState } from './TimePicker.types'; -import { useComboboxStyles_unstable } from '@fluentui/react-combobox'; - -/** - * @deprecated use \@fluentui/react-timepicker-compat - */ -export const timePickerClassNames: SlotClassNames = { - root: 'fui-TimePicker', - input: 'fui-TimePicker__input', - expandIcon: 'fui-TimePicker__expandIcon', - listbox: 'fui-TimePicker__listbox', -}; - -const useStyles = makeStyles({ - listbox: { - maxHeight: 'min(80vh, 416px)', // height for 12 items or 80vh, whichever is smaller - }, -}); - -/** - * Apply styling to the TimePicker slots based on the state - * @deprecated use \@fluentui/react-timepicker-compat - */ -export const useTimePickerStyles_unstable = (state: TimePickerState): TimePickerState => { - const styles = useStyles(); - - state.root.className = mergeClasses(timePickerClassNames.root, state.root.className); - - state.input.className = mergeClasses(timePickerClassNames.input, state.input.className); - - if (state.expandIcon) { - state.expandIcon.className = mergeClasses(timePickerClassNames.expandIcon, state.expandIcon.className); - } - - if (state.listbox) { - state.listbox.className = mergeClasses(timePickerClassNames.listbox, styles.listbox, state.listbox.className); - } - - useComboboxStyles_unstable(state); - - return state; -}; diff --git a/packages/react-components/react-timepicker-compat-preview/src/index.ts b/packages/react-components/react-timepicker-compat-preview/src/index.ts deleted file mode 100644 index 7ecf5d77ca46a..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -export { - TimePicker, - timePickerClassNames, - useTimePickerStyles_unstable, - useTimePicker_unstable, - formatDateToTimeString, -} from './TimePicker'; -export type { - TimePickerProps, - TimePickerSlots, - TimePickerState, - TimeSelectionData, - TimeSelectionEvents, - TimePickerErrorType, -} from './TimePicker'; diff --git a/packages/react-components/react-timepicker-compat-preview/src/testing/isConformant.ts b/packages/react-components/react-timepicker-compat-preview/src/testing/isConformant.ts deleted file mode 100644 index a3d988f29a172..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/src/testing/isConformant.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { isConformant as baseIsConformant } from '@fluentui/react-conformance'; -import type { IsConformantOptions, TestObject } from '@fluentui/react-conformance'; -import griffelTests from '@fluentui/react-conformance-griffel'; - -export function isConformant( - testInfo: Omit, 'componentPath'> & { componentPath?: string }, -) { - const defaultOptions: Partial> = { - tsConfig: { configName: 'tsconfig.spec.json' }, - componentPath: require.main?.filename.replace('.test', ''), - extraTests: griffelTests as TestObject, - }; - - baseIsConformant(defaultOptions, testInfo); -} diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerBestPractices.md b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerBestPractices.md deleted file mode 100644 index 40f9008d6a2ac..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerBestPractices.md +++ /dev/null @@ -1,6 +0,0 @@ -## Best practices - -### Do - -- Use `freeform` to give users the flexibility to input and select a time that may not be present in the predefined options. -- Use TimePicker within `Field` component to ensure an accessible label and error message are provided. diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerControlled.md b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerControlled.md deleted file mode 100644 index 72c2be8de22a3..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerControlled.md +++ /dev/null @@ -1,4 +0,0 @@ -A TimePicker may have controlled selection and value. There are a few things to keep in mind: - -1. **Control `selectedTime` with `value` (or `defaultSelectedTime` with `defaultValue`)**: When the `selectedTime` is controlled or a `defaultSelectedTime` is provided, a controlled `value` or `defaultValue` must also be defined. Otherwise, the TimePicker will not be able to display a value before the Options are rendered. -2. **Clearing input with null**: when controlled, the `selectedTime` prop should use `null` instead of `undefined` to clear the value of the TimePicker. diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerControlled.stories.tsx b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerControlled.stories.tsx deleted file mode 100644 index da2bc0a59bc47..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerControlled.stories.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import { Field, makeStyles } from '@fluentui/react-components'; -import { TimePicker, TimePickerProps, formatDateToTimeString } from '@fluentui/react-timepicker-compat-preview'; -import story from './TimePickerControlled.md'; - -const useStyles = makeStyles({ - root: { - display: 'flex', - flexDirection: 'column', - rowGap: '20px', - maxWidth: '300px', - }, -}); - -const DefaultSelection = () => { - const [defaultSelectedTime] = React.useState(new Date('November 25, 2023 12:30:00')); - return ( - - - - ); -}; - -const ControlledSelection = () => { - const [selectedTime, setSelectedTime] = React.useState(new Date('November 25, 2023 12:30:00')); - const [value, setValue] = React.useState(selectedTime ? formatDateToTimeString(selectedTime) : ''); - - const onTimeChange: TimePickerProps['onTimeChange'] = (_ev, data) => { - setSelectedTime(data.selectedTime); - setValue(data.selectedTimeText ?? ''); - }; - const onInput = (ev: React.ChangeEvent) => { - setValue(ev.target.value); - }; - - return ( - - - - ); -}; - -export const Controlled = () => { - const styles = useStyles(); - return ( -
- - -
- ); -}; - -Controlled.parameters = { - docs: { - description: { - story, - }, - }, -}; diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerDefault.stories.tsx b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerDefault.stories.tsx deleted file mode 100644 index 461776ffca306..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerDefault.stories.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import { Field, makeStyles } from '@fluentui/react-components'; -import { TimePicker, TimePickerProps } from '@fluentui/react-timepicker-compat-preview'; - -const useStyles = makeStyles({ - root: { - maxWidth: '300px', - }, -}); - -export const Default = (props: Partial) => { - const styles = useStyles(); - return ( - - - - ); -}; diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerDescription.md b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerDescription.md deleted file mode 100644 index 8fae7086f4e3d..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerDescription.md +++ /dev/null @@ -1,3 +0,0 @@ -`TimePicker` offers a control that’s optimized for selecting a time from a drop-down list or using free-form input to enter a custom time. - -Note: TimePicker is a compat component - its internal architecture does not follow all the principles regular Fluent UI v9 components follow - it is not composed of atomic hooks and it might be more difficult to tweak its appearance and behavior. It however follows Fluent 2 design and uses design tokens, it is production ready and it is stable. diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformCustomParsing.md b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformCustomParsing.md deleted file mode 100644 index 60b0ee423bc4f..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformCustomParsing.md +++ /dev/null @@ -1,4 +0,0 @@ -This story sets custom time string in the dropdown options, and performs custom parsing from the input text to Date object on selection. - -- The time display format in the dropdown can be customized using `formatDateToTimeString`. -- Freefrom TimePicker can have custom parsing for input text to Date object using `parseTimeStringToDate`. diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformCustomParsing.stories.tsx b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformCustomParsing.stories.tsx deleted file mode 100644 index 22a3fd16e796b..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformCustomParsing.stories.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import { Field, makeStyles } from '@fluentui/react-components'; -import { TimePicker, TimePickerProps } from '@fluentui/react-timepicker-compat-preview'; -import story from './TimePickerFreeformCustomParsing.md'; - -const useStyles = makeStyles({ - root: { - maxWidth: '300px', - }, -}); - -const formatDateToTimeString = (date: Date) => { - const localeTimeString = date.toLocaleTimeString([], { - hour: 'numeric', - minute: '2-digit', - hourCycle: 'h12', - }); - if (date.getHours() < 12) { - return `Morning: ${localeTimeString}`; - } - return `Afternoon: ${localeTimeString}`; -}; - -export const FreeformCustomParsing = () => { - const styles = useStyles(); - - const [anchor] = React.useState(() => new Date(2023, 1, 1)); - - const parseTimeStringToDate: TimePickerProps['parseTimeStringToDate'] = (time: string | undefined) => { - if (!time) { - return { date: null }; - } - - const [hours, minutes] = (time.split(' ')[1].match(/\d+/g) ?? []).map(Number); - const adjustedHours = time.includes('Afternoon: ') && hours !== 12 ? hours + 12 : hours; - const date = new Date(anchor.getFullYear(), anchor.getMonth(), anchor.getDate(), adjustedHours, minutes); - - return { date }; - }; - - const [selectedTimeText, setSelectedTimeText] = React.useState(undefined); - const onTimeChange: TimePickerProps['onTimeChange'] = (_ev, data) => { - setSelectedTimeText(data.selectedTimeText); - }; - - return ( -
- - - - {selectedTimeText &&
Selected time: {selectedTimeText}
} -
- ); -}; - -FreeformCustomParsing.parameters = { - docs: { - description: { - story, - }, - }, -}; diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformWithErrorHandling.md b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformWithErrorHandling.md deleted file mode 100644 index 9ee5c2cf157f8..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformWithErrorHandling.md +++ /dev/null @@ -1,9 +0,0 @@ -TimePicker supports the `freeform` prop, which allows freeform text input. -The selection behavior of freeform TimePicker aligns with the native `change` event behavior for text input: - -- When the value in the TimePicker input changes, and the TimePicker loses focus, the selected time is computed from the `input` value. -- When TimePicker input value has changed and Enter key is pressed on the `input`: - - if the dropdown is expanded and the `input` value is prefix of an option, the selected time is set to the matching option. - - if the dropdown is collapsed or the `input` value does not match any option, the selected time is computed from `input` value. - -The selected time is available in `onTimeChange` callback. Use Field to display the error message based on the error type provided by `onTimeChange`. diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformWithErrorHandling.stories.tsx b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformWithErrorHandling.stories.tsx deleted file mode 100644 index 70fb3007e86ee..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerFreeformWithErrorHandling.stories.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import { Field, FieldProps, makeStyles } from '@fluentui/react-components'; -import { TimePicker, TimePickerErrorType, TimePickerProps } from '@fluentui/react-timepicker-compat-preview'; -import story from './TimePickerFreeformWithErrorHandling.md'; - -const useStyles = makeStyles({ - control: { - maxWidth: '300px', - }, -}); - -const getErrorMessage = (error?: TimePickerErrorType): FieldProps['validationMessage'] => { - switch (error) { - case 'invalid-input': - return 'Invalid time format. Please use the 24-hour format HH:MM.'; - case 'out-of-bounds': - return 'Time out of the 10:00 to 19:59 range.'; - case 'required-input': - return 'Time is required.'; - default: - return ''; - } -}; - -export const FreeformWithErrorHandling = () => { - const styles = useStyles(); - - const [errorType, setErrorType] = React.useState(); - const handleTimeChange: TimePickerProps['onTimeChange'] = (_ev, data) => { - setErrorType(data.errorType); - }; - - return ( - - - - ); -}; - -FreeformWithErrorHandling.parameters = { - docs: { - description: { - story, - }, - }, -}; diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerWithDatePicker.stories.tsx b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerWithDatePicker.stories.tsx deleted file mode 100644 index db288733eb9c5..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/TimePickerWithDatePicker.stories.tsx +++ /dev/null @@ -1,74 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import * as React from 'react'; -import { Field, makeStyles } from '@fluentui/react-components'; -import { DatePicker, DatePickerProps } from '@fluentui/react-datepicker-compat'; -import { TimePicker, TimePickerProps, formatDateToTimeString } from '@fluentui/react-timepicker-compat-preview'; - -const useStyles = makeStyles({ - root: { - display: 'grid', - columnGap: '20px', - gridTemplateColumns: 'repeat(2, 1fr)', - maxWidth: '600px', - marginBottom: '10px', - }, -}); - -export const TimePickerWithDatePicker = () => { - const styles = useStyles(); - - const [selectedDate, setSelectedDate] = React.useState(null); - - const [selectedTime, setSelectedTime] = React.useState(null); - const [timePickerValue, setTimePickerValue] = React.useState( - selectedTime ? formatDateToTimeString(selectedTime) : '', - ); - - const onSelectDate: DatePickerProps['onSelectDate'] = date => { - setSelectedDate(date); - if (date && selectedTime) { - setSelectedTime( - new Date( - date.getFullYear(), - date.getMonth(), - date.getDate(), - selectedTime.getHours(), - selectedTime.getMinutes(), - ), - ); - } - }; - - const onTimeChange: TimePickerProps['onTimeChange'] = (_ev, data) => { - setSelectedTime(data.selectedTime); - setTimePickerValue(data.selectedTimeText ?? ''); - }; - const onTimePickerInput = (ev: React.ChangeEvent) => { - setTimePickerValue(ev.target.value); - }; - - return ( -
-
- - - - - - -
- - {selectedDate && ( -
Selected date time: {selectedTime ? selectedTime.toString() : selectedDate.toString()}
- )} -
- ); -}; diff --git a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/index.stories.tsx b/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/index.stories.tsx deleted file mode 100644 index dfb5a6f63f6f3..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/stories/TimePicker/index.stories.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import { TimePicker } from '@fluentui/react-timepicker-compat-preview'; - -import descriptionMd from './TimePickerDescription.md'; -import bestPracticesMd from './TimePickerBestPractices.md'; - -export { Default } from './TimePickerDefault.stories'; -export { Controlled } from './TimePickerControlled.stories'; -export { FreeformWithErrorHandling } from './TimePickerFreeformWithErrorHandling.stories'; -export { FreeformCustomParsing } from './TimePickerFreeformCustomParsing.stories'; -export { TimePickerWithDatePicker } from './TimePickerWithDatePicker.stories'; - -export default { - title: 'Preview Components/TimePicker', - component: TimePicker, - parameters: { - docs: { - description: { - component: [descriptionMd, bestPracticesMd].join('\n'), - }, - }, - }, -}; diff --git a/packages/react-components/react-timepicker-compat-preview/tsconfig.cy.json b/packages/react-components/react-timepicker-compat-preview/tsconfig.cy.json deleted file mode 100644 index 93a140885851d..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/tsconfig.cy.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "isolatedModules": false, - "types": ["node", "cypress", "cypress-storybook/cypress", "cypress-real-events"], - "lib": ["ES2019", "dom"] - }, - "include": ["**/*.cy.ts", "**/*.cy.tsx"] -} diff --git a/packages/react-components/react-timepicker-compat-preview/tsconfig.json b/packages/react-components/react-timepicker-compat-preview/tsconfig.json deleted file mode 100644 index 1317f81620ca5..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "target": "ES2019", - "noEmit": true, - "isolatedModules": true, - "importHelpers": true, - "jsx": "react", - "noUnusedLocals": true, - "preserveConstEnums": true - }, - "include": [], - "files": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./.storybook/tsconfig.json" - }, - { - "path": "./tsconfig.cy.json" - } - ] -} diff --git a/packages/react-components/react-timepicker-compat-preview/tsconfig.lib.json b/packages/react-components/react-timepicker-compat-preview/tsconfig.lib.json deleted file mode 100644 index 194159fa27a80..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/tsconfig.lib.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "noEmit": false, - "lib": ["ES2019", "dom", "ES2020.Intl"], - "declaration": true, - "declarationDir": "../../../dist/out-tsc/types", - "outDir": "../../../dist/out-tsc", - "inlineSources": true, - "types": ["static-assets", "environment"] - }, - "exclude": [ - "./src/testing/**", - "**/*.spec.ts", - "**/*.spec.tsx", - "**/*.test.ts", - "**/*.test.tsx", - "**/*.stories.ts", - "**/*.stories.tsx", - "**/*.cy.ts", - "**/*.cy.tsx" - ], - "include": ["./src/**/*.ts", "./src/**/*.tsx"] -} diff --git a/packages/react-components/react-timepicker-compat-preview/tsconfig.spec.json b/packages/react-components/react-timepicker-compat-preview/tsconfig.spec.json deleted file mode 100644 index 911456fe4b4d9..0000000000000 --- a/packages/react-components/react-timepicker-compat-preview/tsconfig.spec.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "CommonJS", - "outDir": "dist", - "types": ["jest", "node"] - }, - "include": [ - "**/*.spec.ts", - "**/*.spec.tsx", - "**/*.test.ts", - "**/*.test.tsx", - "**/*.d.ts", - "./src/testing/**/*.ts", - "./src/testing/**/*.tsx" - ] -} diff --git a/tsconfig.base.all.json b/tsconfig.base.all.json index b6a1d82e48bd7..a9f7be4f8165c 100644 --- a/tsconfig.base.all.json +++ b/tsconfig.base.all.json @@ -164,9 +164,6 @@ "@fluentui/react-theme": ["packages/react-components/react-theme/src/index.ts"], "@fluentui/react-theme-sass": ["packages/react-components/react-theme-sass/src/index.ts"], "@fluentui/react-timepicker-compat": ["packages/react-components/react-timepicker-compat/src/index.ts"], - "@fluentui/react-timepicker-compat-preview": [ - "packages/react-components/react-timepicker-compat-preview/src/index.ts" - ], "@fluentui/react-toast": ["packages/react-components/react-toast/src/index.ts"], "@fluentui/react-toolbar": ["packages/react-components/react-toolbar/src/index.ts"], "@fluentui/react-tooltip": ["packages/react-components/react-tooltip/src/index.ts"], diff --git a/tsconfig.base.json b/tsconfig.base.json index 736bd1633f7ae..52b4adb288f43 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -100,9 +100,6 @@ "@fluentui/react-theme": ["packages/react-components/react-theme/src/index.ts"], "@fluentui/react-theme-sass": ["packages/react-components/react-theme-sass/src/index.ts"], "@fluentui/react-timepicker-compat": ["packages/react-components/react-timepicker-compat/src/index.ts"], - "@fluentui/react-timepicker-compat-preview": [ - "packages/react-components/react-timepicker-compat-preview/src/index.ts" - ], "@fluentui/react-toast": ["packages/react-components/react-toast/src/index.ts"], "@fluentui/react-toolbar": ["packages/react-components/react-toolbar/src/index.ts"], "@fluentui/react-tooltip": ["packages/react-components/react-tooltip/src/index.ts"],