From 5544157428c7b8bca83094ab85e6310015d70266 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 04:54:33 +0000 Subject: [PATCH 01/14] update @fluentui/react-components eslint config to disallow and . --- .../eslint-plugin/src/configs/react-config.js | 4 + .../src/configs/restricted-globals.js | 261 ++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 packages/eslint-plugin/src/configs/restricted-globals.js diff --git a/packages/eslint-plugin/src/configs/react-config.js b/packages/eslint-plugin/src/configs/react-config.js index 2663520b69bd5..98a8643d1113c 100644 --- a/packages/eslint-plugin/src/configs/react-config.js +++ b/packages/eslint-plugin/src/configs/react-config.js @@ -1,4 +1,5 @@ const configHelpers = require('../utils/configHelpers'); +const { react: restrictedGlobals } = require('./restricted-globals'); /** @type {import("eslint").Linter.Config} */ module.exports = { @@ -28,6 +29,7 @@ module.exports = { '@griffel/hook-naming': 'error', '@griffel/no-shorthands': 'error', '@griffel/styles-file': 'error', + 'no-restricted-globals': restrictedGlobals, /** * react eslint rules * @see https://github.com/yannickcr/eslint-plugin-react @@ -122,6 +124,7 @@ module.exports = { files: [...configHelpers.testFiles], rules: { 'react/jsx-no-bind': 'off', + 'no-restricted-globals': 'off', }, }, { @@ -129,6 +132,7 @@ module.exports = { rules: { // allow makeStyles calls in stories as examples should be defined in a single file '@griffel/styles-file': 'off', + 'no-restricted-globals': 'off', // allow arrow functions in stories for now (may want to change this later since using // constantly-mutating functions can be an anti-pattern which we may not want to demonstrate // in our converged components docs; it happened to be allowed starting out because .stories diff --git a/packages/eslint-plugin/src/configs/restricted-globals.js b/packages/eslint-plugin/src/configs/restricted-globals.js new file mode 100644 index 0000000000000..d97d02e4ee674 --- /dev/null +++ b/packages/eslint-plugin/src/configs/restricted-globals.js @@ -0,0 +1,261 @@ +// These will be enabled in a follow up PR. + +// Via: https://developer.mozilla.org/en-US/docs/Web/API/Window +// const windowKeys = [ +// // Instance properties +// 'caches', +// 'clientInformation', +// 'closed', +// 'console', +// 'credentialless', +// 'crypto', +// 'customElements', +// 'devicePixelRatio', +// 'frameElement', +// 'frames', +// 'fullScreen', +// 'history', +// 'indexedDB', +// 'innerHeight', +// 'innerWidth', +// 'isSecureContext', +// 'launchQueue', +// 'length', +// 'localStorage', +// 'location', +// 'locationbar', +// 'menubar', +// 'name', +// 'navigation', +// 'navigator', +// 'opener', +// 'origin', +// 'outerHeight', +// 'outerWidth', +// 'pageXOffset', +// 'pageYOffset', +// 'parent', +// 'performance', +// 'personalbar', +// 'scheduler', +// 'screen', +// 'screenX', +// 'screenY', +// 'scrollbars', +// 'scrollX', +// 'scrollY', +// 'self', +// 'sessionStorage', +// 'speechSynthesis', +// 'statusbar', +// 'toolbar', +// 'top', +// 'visualViewport', +// 'window', + +// // Deprecated properties +// 'defaultStatus', +// 'event', +// 'external', +// 'orientation', +// 'returnValue', +// 'sidebar', +// 'status', + +// // Instance methods +// 'addEventListener', +// 'alert', +// 'atob', +// 'blur', +// 'btoa', +// 'cancelAnimationFrame', +// 'cancelIdleCallback', +// 'clearImmediate', +// 'clearInterval', +// 'clearTimeout', +// 'close', +// 'confirm', +// 'createImageBitmap', +// 'dispatchEvent', +// 'dump', +// 'fetch', +// 'find', +// 'focus', +// 'getComputedStyle', +// 'getSelection', +// 'matchMedia', +// 'moveBy', +// 'moveTo', +// 'open', +// 'postMessage', +// 'print', +// 'prompt', +// 'queryLocalFonts', +// 'removeEventListener', +// 'reportError', +// 'requestAnimationFrame', +// 'requestIdleCallback', +// 'resizeBy', +// 'resizeTo', +// 'scroll', +// 'scrollBy', +// 'scrollTo', +// 'setImmediate', +// 'setInterval', +// 'setTimeout', +// 'showDirectoryPicker', +// 'showOpenFilePicker', +// 'showSaveFilePicker', +// 'stop', +// 'updateCommands', + +// // Deprecated methods +// 'back', +// 'captureEvents', +// 'forward', +// 'releaseEvents', +// 'showModalDialog', + +// // Events +// 'onabort', +// 'onafterprint', +// 'onanimationend', +// 'onanimationiteration', +// 'onanimationstart', +// 'onappinstalled', +// 'onauxclick', +// 'onbeforeinput', +// 'onbeforeinstallprompt', +// 'onbeforematch', +// 'onbeforeprint', +// 'onbeforetoggle', +// 'onbeforeunload', +// 'onbeforexrselect', +// 'onblur', +// 'oncancel', +// 'oncanplay', +// 'oncanplaythrough', +// 'onchange', +// 'onclick', +// 'onclose', +// 'oncontentvisibilityautostatechange', +// 'oncontextlost', +// 'oncontextmenu', +// 'oncontextrestored', +// 'oncuechange', +// 'ondblclick', +// 'ondevicemotion', +// 'ondeviceorientation', +// 'ondeviceorientationabsolute', +// 'ondrag', +// 'ondragend', +// 'ondragenter', +// 'ondragleave', +// 'ondragover', +// 'ondragstart', +// 'ondrop', +// 'ondurationchange', +// 'onemptied', +// 'onended', +// 'onerror', +// 'onfocus', +// 'onformdata', +// 'ongotpointercapture', +// 'onhashchange', +// 'oninput', +// 'oninvalid', +// 'onkeydown', +// 'onkeypress', +// 'onkeyup', +// 'onlanguagechange', +// 'onload', +// 'onloadeddata', +// 'onloadedmetadata', +// 'onloadstart', +// 'onlostpointercapture', +// 'onmessage', +// 'onmessageerror', +// 'onmousedown', +// 'onmouseenter', +// 'onmouseleave', +// 'onmousemove', +// 'onmouseout', +// 'onmouseover', +// 'onmouseup', +// 'onmousewheel', +// 'onoffline', +// 'ononline', +// 'onoverscroll', +// 'onpagehide', +// 'onpageshow', +// 'onpause', +// 'onplay', +// 'onplaying', +// 'onpointercancel', +// 'onpointerdown', +// 'onpointerenter', +// 'onpointerleave', +// 'onpointermove', +// 'onpointerout', +// 'onpointerover', +// 'onpointerrawupdate', +// 'onpointerup', +// 'onpopstate', +// 'onprogress', +// 'onratechange', +// 'onrejectionhandled', +// 'onreset', +// 'onresize', +// 'onscroll', +// 'onscrollend', +// 'onsearch', +// 'onsecuritypolicyviolation', +// 'onseeked', +// 'onseeking', +// 'onselect', +// 'onselectionchange', +// 'onselectstart', +// 'onslotchange', +// 'onstalled', +// 'onstorage', +// 'onsubmit', +// 'onsuspend', +// 'ontimeupdate', +// 'ontimezonechange', +// 'ontoggle', +// 'ontransitioncancel', +// 'ontransitionend', +// 'ontransitionrun', +// 'ontransitionstart', +// 'onunhandledrejection', +// 'onunload', +// 'onvolumechange', +// 'onwaiting', +// 'onwebkitanimationend', +// 'onwebkitanimationiteration', +// 'onwebkitanimationstart', +// 'onwebkittransitionend', +// 'onwheel', +// ]; + +const react = [ + 'error', + { + name: 'window', + message: 'Get a reference to `window` from `useFluent()`.', + }, + { + name: 'document', + message: 'Get a reference to `document` from `useFluent()`.', + }, + // ...windowKeys.map(key => { + // return { + // name: key, + // message: `Get a reference to \`window\` from \`useFluent()\` and access \`${key}\` from there.`, + // }; + // }), +]; + +module.exports = { + react, +}; From 047eb9ed00eb06bd733d9f1f1e25e414bffbe856 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 04:56:11 +0000 Subject: [PATCH 02/14] update apps/ to disallow and . --- apps/perf-test-react-components/.eslintrc.json | 3 ++- .../src/scenarios/FluentProviderWithTheme.tsx | 2 ++ apps/perf-test-react-components/src/scenarios/MakeStyles.tsx | 1 + apps/public-docsite-v9/.eslintrc.json | 3 ++- .../Migration/FromV0/Components/IconCatalog/useDebounce.ts | 1 + apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx | 1 + apps/react-18-tests-v9/.eslintrc.json | 4 +++- apps/recipes-react-components/.eslintrc.json | 3 ++- apps/ssr-tests-v9/.eslintrc.json | 3 ++- apps/stress-test/.eslintrc.json | 3 ++- apps/vr-tests-react-components/.eslintrc.json | 3 ++- 11 files changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/perf-test-react-components/.eslintrc.json b/apps/perf-test-react-components/.eslintrc.json index 2948bbf09dea5..2b95bc03dc3f5 100644 --- a/apps/perf-test-react-components/.eslintrc.json +++ b/apps/perf-test-react-components/.eslintrc.json @@ -3,6 +3,7 @@ "root": true, "rules": { "@griffel/styles-file": "off", - "no-console": "off" + "no-console": "off", + "no-restricted-globals": "off" } } diff --git a/apps/perf-test-react-components/src/scenarios/FluentProviderWithTheme.tsx b/apps/perf-test-react-components/src/scenarios/FluentProviderWithTheme.tsx index 6c9a02c6a7112..d371eff22d9a6 100644 --- a/apps/perf-test-react-components/src/scenarios/FluentProviderWithTheme.tsx +++ b/apps/perf-test-react-components/src/scenarios/FluentProviderWithTheme.tsx @@ -5,9 +5,11 @@ import { teamsLightTheme } from '@fluentui/react-theme'; const LayoutShift: React.FunctionComponent = ({ children }) => { // eslint-disable-next-line no-restricted-properties React.useLayoutEffect(() => { + // eslint-disable-next-line no-restricted-globals if (document.body) { // Accessing the offsetWidth forces reflow (browser synchronously calculates style and layout. // This allows us to measure theme impact on the rendering performance. + // eslint-disable-next-line no-restricted-globals document.body.offsetWidth; } }); diff --git a/apps/perf-test-react-components/src/scenarios/MakeStyles.tsx b/apps/perf-test-react-components/src/scenarios/MakeStyles.tsx index 5375ef92490bf..2447150b1b09a 100644 --- a/apps/perf-test-react-components/src/scenarios/MakeStyles.tsx +++ b/apps/perf-test-react-components/src/scenarios/MakeStyles.tsx @@ -1,6 +1,7 @@ import { mergeClasses, makeStyles, createDOMRenderer } from '@griffel/core'; import * as React from 'react'; +// eslint-disable-next-line no-restricted-globals const renderer = createDOMRenderer(document); const useStyles = makeStyles({ diff --git a/apps/public-docsite-v9/.eslintrc.json b/apps/public-docsite-v9/.eslintrc.json index b3f394f7cbaca..54ac641d7b3bf 100644 --- a/apps/public-docsite-v9/.eslintrc.json +++ b/apps/public-docsite-v9/.eslintrc.json @@ -5,6 +5,7 @@ "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/jsx-no-bind": "off", "deprecation/deprecation": "off", - "import/no-extraneous-dependencies": ["error", { "packageDir": [".", "../.."] }] + "import/no-extraneous-dependencies": ["error", { "packageDir": [".", "../.."] }], + "no-restricted-globals": "off" } } diff --git a/apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/IconCatalog/useDebounce.ts b/apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/IconCatalog/useDebounce.ts index c00486012917c..21854c7aade79 100644 --- a/apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/IconCatalog/useDebounce.ts +++ b/apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/IconCatalog/useDebounce.ts @@ -6,6 +6,7 @@ export const useDebounce = (fn: (...args: unknown[]) => void, duration: number) return React.useCallback( (...args: unknown[]) => { clearTimeout(timeoutRef.current); + // eslint-disable-next-line no-restricted-globals timeoutRef.current = window.setTimeout(() => { fn(...args); }, duration); diff --git a/apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx b/apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx index 91c12bd7cd2cb..5356d38fbf1f1 100644 --- a/apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx +++ b/apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx @@ -99,6 +99,7 @@ export const Toc = ({ stories }: { stories: TocItem[] }) => { ); stories.forEach(link => { + // eslint-disable-next-line no-restricted-globals const element = document.getElementById(nameToHash(link.name)); if (element) { observer.observe(element); diff --git a/apps/react-18-tests-v9/.eslintrc.json b/apps/react-18-tests-v9/.eslintrc.json index 92f2e74b606c9..b2f318c6b6a1e 100644 --- a/apps/react-18-tests-v9/.eslintrc.json +++ b/apps/react-18-tests-v9/.eslintrc.json @@ -1,5 +1,7 @@ { "extends": ["plugin:@fluentui/eslint-plugin/react"], "root": true, - "rules": {} + "rules": { + "no-restricted-globals": "off" + } } diff --git a/apps/recipes-react-components/.eslintrc.json b/apps/recipes-react-components/.eslintrc.json index 453f767c8db07..b9d702c5e755d 100644 --- a/apps/recipes-react-components/.eslintrc.json +++ b/apps/recipes-react-components/.eslintrc.json @@ -7,6 +7,7 @@ "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/jsx-no-bind": "off", "deprecation/deprecation": "off", - "import/no-extraneous-dependencies": ["error", { "packageDir": [".", "../.."] }] + "import/no-extraneous-dependencies": ["error", { "packageDir": [".", "../.."] }], + "no-restricted-globals": "off" } } diff --git a/apps/ssr-tests-v9/.eslintrc.json b/apps/ssr-tests-v9/.eslintrc.json index f502b07b22439..b6719ff5c00cf 100644 --- a/apps/ssr-tests-v9/.eslintrc.json +++ b/apps/ssr-tests-v9/.eslintrc.json @@ -2,6 +2,7 @@ "extends": ["plugin:@fluentui/eslint-plugin/node"], "root": true, "rules": { - "import/no-extraneous-dependencies": ["error", { "packageDir": ["../../", "./"] }] + "import/no-extraneous-dependencies": ["error", { "packageDir": ["../../", "./"] }], + "no-restricted-globals": "off" } } diff --git a/apps/stress-test/.eslintrc.json b/apps/stress-test/.eslintrc.json index f502b07b22439..b6719ff5c00cf 100644 --- a/apps/stress-test/.eslintrc.json +++ b/apps/stress-test/.eslintrc.json @@ -2,6 +2,7 @@ "extends": ["plugin:@fluentui/eslint-plugin/node"], "root": true, "rules": { - "import/no-extraneous-dependencies": ["error", { "packageDir": ["../../", "./"] }] + "import/no-extraneous-dependencies": ["error", { "packageDir": ["../../", "./"] }], + "no-restricted-globals": "off" } } diff --git a/apps/vr-tests-react-components/.eslintrc.json b/apps/vr-tests-react-components/.eslintrc.json index 76ca2160a370b..ffeab27cf4c88 100644 --- a/apps/vr-tests-react-components/.eslintrc.json +++ b/apps/vr-tests-react-components/.eslintrc.json @@ -8,6 +8,7 @@ "@typescript-eslint/naming-convention": "off", "@typescript-eslint/jsx-no-bind": "off", "deprecation/deprecation": "off", - "import/no-extraneous-dependencies": ["error", { "packageDir": [".", "../.."] }] + "import/no-extraneous-dependencies": ["error", { "packageDir": [".", "../.."] }], + "no-restricted-globals": "off" } } From e64bc3d392785e31b7685403e661508fa130111c Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 04:59:16 +0000 Subject: [PATCH 03/14] update global-context to disallow and . --- .../global-context/src/global-context-selector.ts | 5 ++++- .../react-components/global-context/src/global-context.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/react-components/global-context/src/global-context-selector.ts b/packages/react-components/global-context/src/global-context-selector.ts index ec2d843afd7e6..1ad1982ebc2dc 100644 --- a/packages/react-components/global-context/src/global-context-selector.ts +++ b/packages/react-components/global-context/src/global-context-selector.ts @@ -5,7 +5,10 @@ import { getMajorVersion } from './utils'; import { GlobalObject } from './types'; const isBrowser = canUseDOM(); -const globalObject: GlobalObject = isBrowser ? window : global; +const globalObject: GlobalObject = isBrowser + ? // eslint-disable-next-line no-restricted-globals + window + : global; // Identifier for the symbol, for easy idenfitifaction of symbols created by this util // Useful for clearning global object during SSR reloads diff --git a/packages/react-components/global-context/src/global-context.ts b/packages/react-components/global-context/src/global-context.ts index a994ddea8f0e4..ad117ce1b8f3e 100644 --- a/packages/react-components/global-context/src/global-context.ts +++ b/packages/react-components/global-context/src/global-context.ts @@ -4,7 +4,10 @@ import { GlobalObject } from './types'; import { getMajorVersion } from './utils'; const isBrowser = canUseDOM(); -const globalObject: GlobalObject = isBrowser ? window : global; +const globalObject: GlobalObject = isBrowser + ? // eslint-disable-next-line no-restricted-globals + window + : global; // Identifier for the symbol, for easy idenfitifaction of symbols created by this util // Useful for clearning global object during SSR reloads From db13cc6eb01223d00ac691e67fac670c56d43fb2 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 04:59:39 +0000 Subject: [PATCH 04/14] update and refactor calendar-compat Updates to remove getWindow() usage in favor of useFluent(). --- .../src/components/Calendar/Calendar.tsx | 40 ++++++++++--------- .../react-calendar-compat/src/utils/dom.ts | 11 ----- .../react-calendar-compat/src/utils/focus.ts | 9 ++--- .../react-calendar-compat/src/utils/index.ts | 1 - 4 files changed, 25 insertions(+), 36 deletions(-) delete mode 100644 packages/react-components/react-calendar-compat/src/utils/dom.ts diff --git a/packages/react-components/react-calendar-compat/src/components/Calendar/Calendar.tsx b/packages/react-components/react-calendar-compat/src/components/Calendar/Calendar.tsx index 5dbc4a88f8812..a3af73849ad4a 100644 --- a/packages/react-components/react-calendar-compat/src/components/Calendar/Calendar.tsx +++ b/packages/react-components/react-calendar-compat/src/components/Calendar/Calendar.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Backspace, Enter, Escape, PageDown, PageUp, Space } from '@fluentui/keyboard-keys'; import { useControllableState } from '@fluentui/react-utilities'; +import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; import { addMonths, addYears, @@ -10,7 +11,6 @@ import { DEFAULT_DATE_FORMATTING, FirstWeekOfYear, focusAsync, - getWindow, } from '../../utils'; import { CalendarDay } from '../CalendarDay/CalendarDay'; import { CalendarMonth } from '../CalendarMonth/CalendarMonth'; @@ -85,20 +85,21 @@ function useVisibilityState({ showMonthPickerAsOverlay, }: CalendarProps) { /** State used to show/hide month picker */ + const showMonthPickerAsOverlayState = useShowMonthPickerAsOverloay({ + isDayPickerVisible: isDayPickerVisibleProp, + showMonthPickerAsOverlay, + }); + const [isMonthPickerVisible, setIsMonthPickerVisible] = useControllableState({ defaultState: false, initialState: true, - state: getShowMonthPickerAsOverlay({ isDayPickerVisible: isDayPickerVisibleProp, showMonthPickerAsOverlay }) - ? undefined - : isMonthPickerVisibleProp, + state: showMonthPickerAsOverlayState ? undefined : isMonthPickerVisibleProp, }); /** State used to show/hide day picker */ const [isDayPickerVisible, setIsDayPickerVisible] = useControllableState({ defaultState: true, initialState: true, - state: getShowMonthPickerAsOverlay({ isDayPickerVisible: isDayPickerVisibleProp, showMonthPickerAsOverlay }) - ? undefined - : isDayPickerVisibleProp, + state: showMonthPickerAsOverlayState ? undefined : isDayPickerVisibleProp, }); const toggleDayMonthPickerVisibility = () => { @@ -113,14 +114,16 @@ function useFocusLogic({ componentRef }: CalendarProps, isDayPickerVisible: bool const dayPicker = React.useRef(null); const monthPicker = React.useRef(null); const focusOnUpdate = React.useRef(false); + const { targetDocument } = useFluent(); + const win = targetDocument?.defaultView; const focus = React.useCallback(() => { if (isDayPickerVisible && dayPicker.current) { - focusAsync(dayPicker.current); + focusAsync(dayPicker.current, win); } else if (isMonthPickerVisible && monthPicker.current) { - focusAsync(monthPicker.current); + focusAsync(monthPicker.current, win); } - }, [isDayPickerVisible, isMonthPickerVisible]); + }, [isDayPickerVisible, isMonthPickerVisible, win]); React.useImperativeHandle(componentRef, () => ({ focus }), [focus]); @@ -240,10 +243,12 @@ export const Calendar: React.FunctionComponent = React.forwardRef navigateDay(date); }; - const onHeaderSelect = getShowMonthPickerAsOverlay({ + const showMonthPickerAsOverlay = useShowMonthPickerAsOverloay({ isDayPickerVisible: isDayPickerVisibleProp, showMonthPickerAsOverlay: showMonthPickerAsOverlayProp, - }) + }); + + const onHeaderSelect = showMonthPickerAsOverlay ? (): void => { toggleDayMonthPickerVisibility(); @@ -306,10 +311,6 @@ export const Calendar: React.FunctionComponent = React.forwardRef break; } }; - const showMonthPickerAsOverlay = getShowMonthPickerAsOverlay({ - isDayPickerVisible: isDayPickerVisibleProp, - showMonthPickerAsOverlay: showMonthPickerAsOverlayProp, - }); const monthPickerOnly = !showMonthPickerAsOverlay && !isDayPickerVisible; @@ -410,7 +411,8 @@ export const Calendar: React.FunctionComponent = React.forwardRef ); Calendar.displayName = 'Calendar'; -function getShowMonthPickerAsOverlay({ isDayPickerVisible, showMonthPickerAsOverlay }: CalendarProps) { - const win = getWindow(); +const useShowMonthPickerAsOverloay = ({ isDayPickerVisible, showMonthPickerAsOverlay }: CalendarProps) => { + const { targetDocument } = useFluent(); + const win = targetDocument?.defaultView; return showMonthPickerAsOverlay || (isDayPickerVisible && win && win.innerWidth <= MIN_SIZE_FORCE_OVERLAY); -} +}; diff --git a/packages/react-components/react-calendar-compat/src/utils/dom.ts b/packages/react-components/react-calendar-compat/src/utils/dom.ts deleted file mode 100644 index 4ce45e2fa22b1..0000000000000 --- a/packages/react-components/react-calendar-compat/src/utils/dom.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { canUseDOM } from '@fluentui/react-utilities'; - -export function getWindow(targetElement?: Element | null): Window | undefined { - if (!canUseDOM() || typeof window === 'undefined') { - return undefined; - } - - const el = targetElement as Element; - - return el && el.ownerDocument && el.ownerDocument.defaultView ? el.ownerDocument.defaultView : window; -} diff --git a/packages/react-components/react-calendar-compat/src/utils/focus.ts b/packages/react-components/react-calendar-compat/src/utils/focus.ts index 97bc5ddb7bfa8..ce48f80e48029 100644 --- a/packages/react-components/react-calendar-compat/src/utils/focus.ts +++ b/packages/react-components/react-calendar-compat/src/utils/focus.ts @@ -1,5 +1,3 @@ -import { getWindow } from './dom'; - let targetToFocusOnNextRepaint: HTMLElement | { focus: () => void } | null | undefined = undefined; /** @@ -8,7 +6,10 @@ let targetToFocusOnNextRepaint: HTMLElement | { focus: () => void } | null | und * only the latest called focusAsync element will actually be focused * @param element - The element to focus */ -export function focusAsync(element: HTMLElement | { focus: () => void } | undefined | null): void { +export function focusAsync( + element: HTMLElement | { focus: () => void } | undefined | null, + win: Window | undefined | null, +): void { if (element) { // An element was already queued to be focused, so replace that one with the new element if (targetToFocusOnNextRepaint) { @@ -18,8 +19,6 @@ export function focusAsync(element: HTMLElement | { focus: () => void } | undefi targetToFocusOnNextRepaint = element; - const win = getWindow(element as Element); - if (win) { // element.focus() is a no-op if the element is no longer in the DOM, meaning this is always safe win.requestAnimationFrame(() => { diff --git a/packages/react-components/react-calendar-compat/src/utils/index.ts b/packages/react-components/react-calendar-compat/src/utils/index.ts index 488020805bb61..cb8c73d5cadcb 100644 --- a/packages/react-components/react-calendar-compat/src/utils/index.ts +++ b/packages/react-components/react-calendar-compat/src/utils/index.ts @@ -3,5 +3,4 @@ export * from './constants'; export * from './dateFormatting'; export * from './dateGrid'; export * from './dateMath'; -export * from './dom'; export * from './focus'; From d7d40e9e9f5eea39e321fdb394e4cef46098f150 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 05:02:07 +0000 Subject: [PATCH 05/14] disable eslint rule for stories --- .../react-components/stories/AccessibilityScenarios/utils.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-components/react-components/stories/AccessibilityScenarios/utils.tsx b/packages/react-components/react-components/stories/AccessibilityScenarios/utils.tsx index 06438c6e95fc4..540d8e94f0f62 100644 --- a/packages/react-components/react-components/stories/AccessibilityScenarios/utils.tsx +++ b/packages/react-components/react-components/stories/AccessibilityScenarios/utils.tsx @@ -30,6 +30,7 @@ export const BackLink = () => Go back to main menu = ({ pageTitle, children }) => { React.useEffect(() => { + // eslint-disable-next-line no-restricted-globals document.title = pageTitle + APP_TITLE_SEPARATOR + APP_TITLE; }, [pageTitle]); From 7494f853157d34614bb697f321dee88a9e437d73 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 05:05:38 +0000 Subject: [PATCH 06/14] disable eslint rule --- .../react-motion-preview/src/utils/dom-style.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/react-components/react-motion-preview/src/utils/dom-style.ts b/packages/react-components/react-motion-preview/src/utils/dom-style.ts index faa0aef71fa58..bbde104c95ffd 100644 --- a/packages/react-components/react-motion-preview/src/utils/dom-style.ts +++ b/packages/react-components/react-motion-preview/src/utils/dom-style.ts @@ -81,7 +81,11 @@ export const hasCSSOMSupport = (node: HTMLElementWithStyledMap) => { * @returns - CSS styles. */ export const getElementComputedStyle = (node: HTMLElement): CSSStyleDeclaration => { - const win = canUseDOM() && (node.ownerDocument?.defaultView ?? window); + const win = + canUseDOM() && + (node.ownerDocument?.defaultView ?? + // eslint-disable-next-line no-restricted-globals + window); if (!win) { return { From 4b332fee3a2c09c6891d538ea97c535d37630881 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 05:06:36 +0000 Subject: [PATCH 07/14] disable eslint rule --- .../react-shared-contexts/src/ProviderContext/ProviderContext.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-components/react-shared-contexts/src/ProviderContext/ProviderContext.ts b/packages/react-components/react-shared-contexts/src/ProviderContext/ProviderContext.ts index 5651db5554568..4b965b8e85a8f 100644 --- a/packages/react-components/react-shared-contexts/src/ProviderContext/ProviderContext.ts +++ b/packages/react-components/react-shared-contexts/src/ProviderContext/ProviderContext.ts @@ -16,6 +16,7 @@ const ProviderContext = React.createContext( ) as React.Context; const providerContextDefaultValue: ProviderContextValue = { + // eslint-disable-next-line no-restricted-globals targetDocument: typeof document === 'object' ? document : undefined, dir: 'ltr' as const, }; From ea89f19c6c52e55d72f243738c6ccf1f279fbb76 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 05:12:49 +0000 Subject: [PATCH 08/14] update to use from context --- .../react-components/react-utilities/package.json | 1 + .../react-utilities/src/hooks/useOnClickOutside.ts | 13 ++++++++----- .../react-utilities/src/ssr/canUseDOM.ts | 5 +++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/react-components/react-utilities/package.json b/packages/react-components/react-utilities/package.json index 4f290812772e7..1c17653f62f73 100644 --- a/packages/react-components/react-utilities/package.json +++ b/packages/react-components/react-utilities/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-shared-contexts": "^9.13.0", "@swc/helpers": "^0.5.1" }, "peerDependencies": { diff --git a/packages/react-components/react-utilities/src/hooks/useOnClickOutside.ts b/packages/react-components/react-utilities/src/hooks/useOnClickOutside.ts index 74b414a8b8ed5..1ae1f9b3e5f1b 100644 --- a/packages/react-components/react-utilities/src/hooks/useOnClickOutside.ts +++ b/packages/react-components/react-utilities/src/hooks/useOnClickOutside.ts @@ -1,5 +1,6 @@ import * as React from 'react'; import { useEventCallback } from './useEventCallback'; +import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; /** * @internal @@ -45,6 +46,8 @@ const DEFAULT_CONTAINS: UseOnClickOrScrollOutsideOptions['contains'] = (parent, * Utility to perform checks where a click/touch event was made outside a component */ export const useOnClickOutside = (options: UseOnClickOrScrollOutsideOptions) => { + const { targetDocument } = useFluent(); + const win = targetDocument?.defaultView; const { refs, callback, element, disabled, disabledFocusOnIframe, contains = DEFAULT_CONTAINS } = options; const timeoutId = React.useRef(undefined); @@ -80,7 +83,7 @@ export const useOnClickOutside = (options: UseOnClickOrScrollOutsideOptions) => // Store the current event to avoid triggering handlers immediately // Note this depends on a deprecated but extremely well supported quirk of the web platform // https://github.com/facebook/react/issues/20074 - let currentEvent = getWindowEvent(window); + let currentEvent = getWindowEvent(win); const conditionalHandler = (event: MouseEvent | TouchEvent) => { // Skip if this event is the same as the one running when we added the handlers @@ -99,7 +102,7 @@ export const useOnClickOutside = (options: UseOnClickOrScrollOutsideOptions) => element?.addEventListener('mousedown', handleMouseDown, true); // Garbage collect this event after it's no longer useful to avoid memory leaks - timeoutId.current = window.setTimeout(() => { + timeoutId.current = win?.setTimeout(() => { currentEvent = undefined; }, 1); @@ -109,13 +112,13 @@ export const useOnClickOutside = (options: UseOnClickOrScrollOutsideOptions) => element?.removeEventListener('contextmenu', conditionalHandler, true); element?.removeEventListener('mousedown', handleMouseDown, true); - clearTimeout(timeoutId.current); + win?.clearTimeout(timeoutId.current); currentEvent = undefined; }; - }, [listener, element, disabled, handleMouseDown]); + }, [listener, element, disabled, handleMouseDown, win]); }; -const getWindowEvent = (target: Node | Window): Event | undefined => { +const getWindowEvent = (target: Node | Window | null | undefined): Event | undefined => { if (target) { if (typeof (target as Window).window === 'object' && (target as Window).window === target) { // eslint-disable-next-line deprecation/deprecation diff --git a/packages/react-components/react-utilities/src/ssr/canUseDOM.ts b/packages/react-components/react-utilities/src/ssr/canUseDOM.ts index 01520b98ccc7a..ee7d26eab76e3 100644 --- a/packages/react-components/react-utilities/src/ssr/canUseDOM.ts +++ b/packages/react-components/react-utilities/src/ssr/canUseDOM.ts @@ -3,10 +3,11 @@ */ export function canUseDOM(): boolean { return ( + // eslint-disable-next-line no-restricted-globals typeof window !== 'undefined' && !!( - window.document && - // eslint-disable-next-line deprecation/deprecation + window.document && // eslint-disable-line no-restricted-globals + // eslint-disable-next-line deprecation/deprecation, no-restricted-globals window.document.createElement ) ); From b53ed0cbea65de081e28e3b4684b3d5b0d0fa7fe Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 05:16:38 +0000 Subject: [PATCH 09/14] update eslint config --- packages/react-components/theme-designer/.eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-components/theme-designer/.eslintrc.json b/packages/react-components/theme-designer/.eslintrc.json index a86d9b8501ad5..eab62c7c347c8 100644 --- a/packages/react-components/theme-designer/.eslintrc.json +++ b/packages/react-components/theme-designer/.eslintrc.json @@ -2,6 +2,7 @@ "extends": ["plugin:@fluentui/eslint-plugin/react"], "root": true, "rules": { - "@griffel/styles-file": "off" + "@griffel/styles-file": "off", + "no-restricted-globals": "off" } } From 6ca6b9d586a21ed0d8fa8fbce4d3f0c4a3cc8261 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 13:08:17 +0000 Subject: [PATCH 10/14] clean up a few lint stragglers --- apps/react-18-tests-v8/.eslintrc.json | 4 +++- packages/cra-template/template/src/index.tsx | 1 + packages/eslint-plugin/src/configs/react-legacy.js | 1 + packages/eslint-plugin/src/utils/configHelpers.js | 2 +- packages/public-docsite-setup/.eslintrc.json | 3 ++- packages/react-window-provider/src/WindowProvider.tsx | 1 + packages/set-version/.eslintrc.json | 3 ++- 7 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/react-18-tests-v8/.eslintrc.json b/apps/react-18-tests-v8/.eslintrc.json index 92f2e74b606c9..b2f318c6b6a1e 100644 --- a/apps/react-18-tests-v8/.eslintrc.json +++ b/apps/react-18-tests-v8/.eslintrc.json @@ -1,5 +1,7 @@ { "extends": ["plugin:@fluentui/eslint-plugin/react"], "root": true, - "rules": {} + "rules": { + "no-restricted-globals": "off" + } } diff --git a/packages/cra-template/template/src/index.tsx b/packages/cra-template/template/src/index.tsx index 90113a51c9827..7e39450d98bf5 100644 --- a/packages/cra-template/template/src/index.tsx +++ b/packages/cra-template/template/src/index.tsx @@ -13,6 +13,7 @@ mergeStyles({ }, }); +// eslint-disable-next-line no-restricted-globals ReactDOM.render(, document.getElementById('root')); // If you want to start measuring performance in your app, pass a function diff --git a/packages/eslint-plugin/src/configs/react-legacy.js b/packages/eslint-plugin/src/configs/react-legacy.js index 8d696ec41bfa1..108f202b0d9a7 100644 --- a/packages/eslint-plugin/src/configs/react-legacy.js +++ b/packages/eslint-plugin/src/configs/react-legacy.js @@ -9,6 +9,7 @@ module.exports = { rules: { 'jsdoc/check-tag-names': 'off', '@griffel/no-shorthands': 'off', + 'no-restricted-globals': 'off', }, overrides: [], }; diff --git a/packages/eslint-plugin/src/utils/configHelpers.js b/packages/eslint-plugin/src/utils/configHelpers.js index 496ef038a2dc5..37af2f6c4f7c0 100644 --- a/packages/eslint-plugin/src/utils/configHelpers.js +++ b/packages/eslint-plugin/src/utils/configHelpers.js @@ -31,7 +31,7 @@ function getProjectMetadata(options) { } const testFiles = [ - '**/*{.,-}{test,spec,e2e}.{ts,tsx}', + '**/*{.,-}{test,spec,e2e,cy}.{ts,tsx}', '**/{test,tests}/**', '**/testUtilities.{ts,tsx}', '**/common/{isConformant,snapshotSerializers}.{ts,tsx}', diff --git a/packages/public-docsite-setup/.eslintrc.json b/packages/public-docsite-setup/.eslintrc.json index 5c7aa8ffa91c0..cae3998301ac6 100644 --- a/packages/public-docsite-setup/.eslintrc.json +++ b/packages/public-docsite-setup/.eslintrc.json @@ -5,7 +5,8 @@ { "files": ["bin/*.js", "src/loadSite.ts"], "rules": { - "no-console": "off" + "no-console": "off", + "no-restricted-globals": "off" } }, { diff --git a/packages/react-window-provider/src/WindowProvider.tsx b/packages/react-window-provider/src/WindowProvider.tsx index 61758d0c12ddf..4b03b2d7ceb21 100644 --- a/packages/react-window-provider/src/WindowProvider.tsx +++ b/packages/react-window-provider/src/WindowProvider.tsx @@ -16,6 +16,7 @@ export type WindowProviderProps = { */ // eslint-disable-next-line @fluentui/no-context-default-value export const WindowContext = React.createContext({ + // eslint-disable-next-line no-restricted-globals window: typeof window === 'object' ? window : undefined, }); diff --git a/packages/set-version/.eslintrc.json b/packages/set-version/.eslintrc.json index 242cf7dcccffb..636059d5b036f 100644 --- a/packages/set-version/.eslintrc.json +++ b/packages/set-version/.eslintrc.json @@ -3,6 +3,7 @@ "root": true, "rules": { "deprecation/deprecation": "off", - "prefer-const": "off" + "prefer-const": "off", + "no-restricted-globals": "off" } } From 9e79bbc1c9b04cc81860e10c0148f39e2bf0ad04 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 13:16:07 +0000 Subject: [PATCH 11/14] change files --- ...-cra-template-49db9598-b35e-4d1c-901b-ead2f5a354e0.json | 7 +++++++ ...eslint-plugin-ec3bdd41-2624-4271-bda6-b13ed5f7d0c5.json | 7 +++++++ ...lobal-context-1e3db17a-f6cc-40b8-a367-feabee08ad3b.json | 7 +++++++ ...lendar-compat-0d185f2c-2c07-45d3-a65a-11a19f4ae6ba.json | 7 +++++++ ...otion-preview-5c6d53e5-4c7e-4418-a389-54ff5bceaf66.json | 7 +++++++ ...ared-contexts-a56a4c13-fffd-4819-a2ca-0334abbc53a9.json | 7 +++++++ ...act-utilities-c5034c4b-aba2-4c9d-b59c-54708e33539c.json | 7 +++++++ ...ndow-provider-5257f709-976b-4616-9470-013dfe88e991.json | 7 +++++++ 8 files changed, 56 insertions(+) create mode 100644 change/@fluentui-cra-template-49db9598-b35e-4d1c-901b-ead2f5a354e0.json create mode 100644 change/@fluentui-eslint-plugin-ec3bdd41-2624-4271-bda6-b13ed5f7d0c5.json create mode 100644 change/@fluentui-global-context-1e3db17a-f6cc-40b8-a367-feabee08ad3b.json create mode 100644 change/@fluentui-react-calendar-compat-0d185f2c-2c07-45d3-a65a-11a19f4ae6ba.json create mode 100644 change/@fluentui-react-motion-preview-5c6d53e5-4c7e-4418-a389-54ff5bceaf66.json create mode 100644 change/@fluentui-react-shared-contexts-a56a4c13-fffd-4819-a2ca-0334abbc53a9.json create mode 100644 change/@fluentui-react-utilities-c5034c4b-aba2-4c9d-b59c-54708e33539c.json create mode 100644 change/@fluentui-react-window-provider-5257f709-976b-4616-9470-013dfe88e991.json diff --git a/change/@fluentui-cra-template-49db9598-b35e-4d1c-901b-ead2f5a354e0.json b/change/@fluentui-cra-template-49db9598-b35e-4d1c-901b-ead2f5a354e0.json new file mode 100644 index 0000000000000..f9e92f127f9ae --- /dev/null +++ b/change/@fluentui-cra-template-49db9598-b35e-4d1c-901b-ead2f5a354e0.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "chore: disallow `window` and `document` access", + "packageName": "@fluentui/cra-template", + "email": "seanmonahan@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-eslint-plugin-ec3bdd41-2624-4271-bda6-b13ed5f7d0c5.json b/change/@fluentui-eslint-plugin-ec3bdd41-2624-4271-bda6-b13ed5f7d0c5.json new file mode 100644 index 0000000000000..10bead64bbd14 --- /dev/null +++ b/change/@fluentui-eslint-plugin-ec3bdd41-2624-4271-bda6-b13ed5f7d0c5.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "chore: disallow `window` and `document` access for @fluentui/react-components", + "packageName": "@fluentui/eslint-plugin", + "email": "seanmonahan@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-global-context-1e3db17a-f6cc-40b8-a367-feabee08ad3b.json b/change/@fluentui-global-context-1e3db17a-f6cc-40b8-a367-feabee08ad3b.json new file mode 100644 index 0000000000000..8f952325fc222 --- /dev/null +++ b/change/@fluentui-global-context-1e3db17a-f6cc-40b8-a367-feabee08ad3b.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "chore: disallow `window` and `document` access", + "packageName": "@fluentui/global-context", + "email": "seanmonahan@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-calendar-compat-0d185f2c-2c07-45d3-a65a-11a19f4ae6ba.json b/change/@fluentui-react-calendar-compat-0d185f2c-2c07-45d3-a65a-11a19f4ae6ba.json new file mode 100644 index 0000000000000..3253bf30a954d --- /dev/null +++ b/change/@fluentui-react-calendar-compat-0d185f2c-2c07-45d3-a65a-11a19f4ae6ba.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "chore: disallow `window` and `document` access", + "packageName": "@fluentui/react-calendar-compat", + "email": "seanmonahan@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-motion-preview-5c6d53e5-4c7e-4418-a389-54ff5bceaf66.json b/change/@fluentui-react-motion-preview-5c6d53e5-4c7e-4418-a389-54ff5bceaf66.json new file mode 100644 index 0000000000000..e36a0abab7592 --- /dev/null +++ b/change/@fluentui-react-motion-preview-5c6d53e5-4c7e-4418-a389-54ff5bceaf66.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "chore: disallow `window` and `document` access", + "packageName": "@fluentui/react-motion-preview", + "email": "seanmonahan@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-shared-contexts-a56a4c13-fffd-4819-a2ca-0334abbc53a9.json b/change/@fluentui-react-shared-contexts-a56a4c13-fffd-4819-a2ca-0334abbc53a9.json new file mode 100644 index 0000000000000..ea37e72866d6d --- /dev/null +++ b/change/@fluentui-react-shared-contexts-a56a4c13-fffd-4819-a2ca-0334abbc53a9.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "chore: disallow `window` and `document` access", + "packageName": "@fluentui/react-shared-contexts", + "email": "seanmonahan@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-utilities-c5034c4b-aba2-4c9d-b59c-54708e33539c.json b/change/@fluentui-react-utilities-c5034c4b-aba2-4c9d-b59c-54708e33539c.json new file mode 100644 index 0000000000000..7581a62e820c9 --- /dev/null +++ b/change/@fluentui-react-utilities-c5034c4b-aba2-4c9d-b59c-54708e33539c.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "chore: disallow `window` and `document` access", + "packageName": "@fluentui/react-utilities", + "email": "seanmonahan@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-window-provider-5257f709-976b-4616-9470-013dfe88e991.json b/change/@fluentui-react-window-provider-5257f709-976b-4616-9470-013dfe88e991.json new file mode 100644 index 0000000000000..6ea7c4abe99fd --- /dev/null +++ b/change/@fluentui-react-window-provider-5257f709-976b-4616-9470-013dfe88e991.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": " `window` and `document` access", + "packageName": "@fluentui/react-window-provider", + "email": "seanmonahan@microsoft.com", + "dependentChangeType": "patch" +} From af0c8c4da1c79fd69e71c0e6a5e4bd0856bfbd86 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 17:11:13 +0000 Subject: [PATCH 12/14] PR feedback --- .../src/scenarios/FluentProviderWithTheme.tsx | 2 -- packages/eslint-plugin/src/configs/restricted-globals.js | 1 + .../src/components/Calendar/Calendar.tsx | 6 +++--- .../react-utilities/src/ssr/canUseDOM.ts | 9 ++------- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/apps/perf-test-react-components/src/scenarios/FluentProviderWithTheme.tsx b/apps/perf-test-react-components/src/scenarios/FluentProviderWithTheme.tsx index d371eff22d9a6..6c9a02c6a7112 100644 --- a/apps/perf-test-react-components/src/scenarios/FluentProviderWithTheme.tsx +++ b/apps/perf-test-react-components/src/scenarios/FluentProviderWithTheme.tsx @@ -5,11 +5,9 @@ import { teamsLightTheme } from '@fluentui/react-theme'; const LayoutShift: React.FunctionComponent = ({ children }) => { // eslint-disable-next-line no-restricted-properties React.useLayoutEffect(() => { - // eslint-disable-next-line no-restricted-globals if (document.body) { // Accessing the offsetWidth forces reflow (browser synchronously calculates style and layout. // This allows us to measure theme impact on the rendering performance. - // eslint-disable-next-line no-restricted-globals document.body.offsetWidth; } }); diff --git a/packages/eslint-plugin/src/configs/restricted-globals.js b/packages/eslint-plugin/src/configs/restricted-globals.js index d97d02e4ee674..b8870e2883ecc 100644 --- a/packages/eslint-plugin/src/configs/restricted-globals.js +++ b/packages/eslint-plugin/src/configs/restricted-globals.js @@ -1,4 +1,5 @@ // These will be enabled in a follow up PR. +// https://github.com/microsoft/fluentui/issues/29964 // Via: https://developer.mozilla.org/en-US/docs/Web/API/Window // const windowKeys = [ diff --git a/packages/react-components/react-calendar-compat/src/components/Calendar/Calendar.tsx b/packages/react-components/react-calendar-compat/src/components/Calendar/Calendar.tsx index a3af73849ad4a..62638ff4d4084 100644 --- a/packages/react-components/react-calendar-compat/src/components/Calendar/Calendar.tsx +++ b/packages/react-components/react-calendar-compat/src/components/Calendar/Calendar.tsx @@ -85,7 +85,7 @@ function useVisibilityState({ showMonthPickerAsOverlay, }: CalendarProps) { /** State used to show/hide month picker */ - const showMonthPickerAsOverlayState = useShowMonthPickerAsOverloay({ + const showMonthPickerAsOverlayState = useShowMonthPickerAsOverlay({ isDayPickerVisible: isDayPickerVisibleProp, showMonthPickerAsOverlay, }); @@ -243,7 +243,7 @@ export const Calendar: React.FunctionComponent = React.forwardRef navigateDay(date); }; - const showMonthPickerAsOverlay = useShowMonthPickerAsOverloay({ + const showMonthPickerAsOverlay = useShowMonthPickerAsOverlay({ isDayPickerVisible: isDayPickerVisibleProp, showMonthPickerAsOverlay: showMonthPickerAsOverlayProp, }); @@ -411,7 +411,7 @@ export const Calendar: React.FunctionComponent = React.forwardRef ); Calendar.displayName = 'Calendar'; -const useShowMonthPickerAsOverloay = ({ isDayPickerVisible, showMonthPickerAsOverlay }: CalendarProps) => { +const useShowMonthPickerAsOverlay = ({ isDayPickerVisible, showMonthPickerAsOverlay }: CalendarProps) => { const { targetDocument } = useFluent(); const win = targetDocument?.defaultView; return showMonthPickerAsOverlay || (isDayPickerVisible && win && win.innerWidth <= MIN_SIZE_FORCE_OVERLAY); diff --git a/packages/react-components/react-utilities/src/ssr/canUseDOM.ts b/packages/react-components/react-utilities/src/ssr/canUseDOM.ts index ee7d26eab76e3..97a67ead443ed 100644 --- a/packages/react-components/react-utilities/src/ssr/canUseDOM.ts +++ b/packages/react-components/react-utilities/src/ssr/canUseDOM.ts @@ -3,12 +3,7 @@ */ export function canUseDOM(): boolean { return ( - // eslint-disable-next-line no-restricted-globals - typeof window !== 'undefined' && - !!( - window.document && // eslint-disable-line no-restricted-globals - // eslint-disable-next-line deprecation/deprecation, no-restricted-globals - window.document.createElement - ) + // eslint-disable-next-line deprecation/deprecation, no-restricted-globals + typeof window !== 'undefined' && !!(window.document && window.document.createElement) ); } From 1908ee5d7ca646b993c96a1681b7edc2fa3bdced Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Wed, 29 Nov 2023 19:17:06 +0000 Subject: [PATCH 13/14] PR feedback --- .../global-context/src/global-context-selector.ts | 6 ++---- .../react-components/global-context/src/global-context.ts | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/react-components/global-context/src/global-context-selector.ts b/packages/react-components/global-context/src/global-context-selector.ts index 1ad1982ebc2dc..591a1544925d7 100644 --- a/packages/react-components/global-context/src/global-context-selector.ts +++ b/packages/react-components/global-context/src/global-context-selector.ts @@ -5,10 +5,8 @@ import { getMajorVersion } from './utils'; import { GlobalObject } from './types'; const isBrowser = canUseDOM(); -const globalObject: GlobalObject = isBrowser - ? // eslint-disable-next-line no-restricted-globals - window - : global; +// eslint-disable-next-line no-restricted-globals +const globalObject: GlobalObject = isBrowser ? window : global; // Identifier for the symbol, for easy idenfitifaction of symbols created by this util // Useful for clearning global object during SSR reloads diff --git a/packages/react-components/global-context/src/global-context.ts b/packages/react-components/global-context/src/global-context.ts index ad117ce1b8f3e..39e3b8471fe0c 100644 --- a/packages/react-components/global-context/src/global-context.ts +++ b/packages/react-components/global-context/src/global-context.ts @@ -4,10 +4,8 @@ import { GlobalObject } from './types'; import { getMajorVersion } from './utils'; const isBrowser = canUseDOM(); -const globalObject: GlobalObject = isBrowser - ? // eslint-disable-next-line no-restricted-globals - window - : global; +// eslint-disable-next-line no-restricted-globals +const globalObject: GlobalObject = isBrowser ? window : global; // Identifier for the symbol, for easy idenfitifaction of symbols created by this util // Useful for clearning global object during SSR reloads From 9ead8d5de293a4a4c255e41380c5ef9d49eb5294 Mon Sep 17 00:00:00 2001 From: Sean Monahan Date: Mon, 4 Dec 2023 10:45:19 -0800 Subject: [PATCH 14/14] Apply suggestions from code review Co-authored-by: Makoto Morimoto --- apps/perf-test-react-components/src/scenarios/MakeStyles.tsx | 1 - .../Migration/FromV0/Components/IconCatalog/useDebounce.ts | 1 - apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx | 1 - ...ct-window-provider-5257f709-976b-4616-9470-013dfe88e991.json | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/perf-test-react-components/src/scenarios/MakeStyles.tsx b/apps/perf-test-react-components/src/scenarios/MakeStyles.tsx index 2447150b1b09a..5375ef92490bf 100644 --- a/apps/perf-test-react-components/src/scenarios/MakeStyles.tsx +++ b/apps/perf-test-react-components/src/scenarios/MakeStyles.tsx @@ -1,7 +1,6 @@ import { mergeClasses, makeStyles, createDOMRenderer } from '@griffel/core'; import * as React from 'react'; -// eslint-disable-next-line no-restricted-globals const renderer = createDOMRenderer(document); const useStyles = makeStyles({ diff --git a/apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/IconCatalog/useDebounce.ts b/apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/IconCatalog/useDebounce.ts index 21854c7aade79..c00486012917c 100644 --- a/apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/IconCatalog/useDebounce.ts +++ b/apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/IconCatalog/useDebounce.ts @@ -6,7 +6,6 @@ export const useDebounce = (fn: (...args: unknown[]) => void, duration: number) return React.useCallback( (...args: unknown[]) => { clearTimeout(timeoutRef.current); - // eslint-disable-next-line no-restricted-globals timeoutRef.current = window.setTimeout(() => { fn(...args); }, duration); diff --git a/apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx b/apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx index 5356d38fbf1f1..91c12bd7cd2cb 100644 --- a/apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx +++ b/apps/public-docsite-v9/src/DocsComponents/Toc.stories.tsx @@ -99,7 +99,6 @@ export const Toc = ({ stories }: { stories: TocItem[] }) => { ); stories.forEach(link => { - // eslint-disable-next-line no-restricted-globals const element = document.getElementById(nameToHash(link.name)); if (element) { observer.observe(element); diff --git a/change/@fluentui-react-window-provider-5257f709-976b-4616-9470-013dfe88e991.json b/change/@fluentui-react-window-provider-5257f709-976b-4616-9470-013dfe88e991.json index 6ea7c4abe99fd..218346cc9426d 100644 --- a/change/@fluentui-react-window-provider-5257f709-976b-4616-9470-013dfe88e991.json +++ b/change/@fluentui-react-window-provider-5257f709-976b-4616-9470-013dfe88e991.json @@ -1,6 +1,6 @@ { "type": "patch", - "comment": " `window` and `document` access", + "comment": "chore: disallow `window` and `document` access", "packageName": "@fluentui/react-window-provider", "email": "seanmonahan@microsoft.com", "dependentChangeType": "patch"