diff --git a/packages/next/src/build/output/index.ts b/packages/next/src/build/output/index.ts index dbbe95513de5e..d676e16768ad0 100644 --- a/packages/next/src/build/output/index.ts +++ b/packages/next/src/build/output/index.ts @@ -2,7 +2,7 @@ import { bold, red, yellow } from '../../lib/picocolors' import stripAnsi from 'next/dist/compiled/strip-ansi' import textTable from 'next/dist/compiled/text-table' import createStore from 'next/dist/compiled/unistore' -import formatWebpackMessages from '../../client/components/react-dev-overlay/internal/helpers/format-webpack-messages' +import formatWebpackMessages from '../../client/components/react-dev-overlay/_experimental/internal/helpers/format-webpack-messages' import { store as consoleStore } from './store' import type { OutputState } from './store' import type { webpack } from 'next/dist/compiled/webpack/webpack' diff --git a/packages/next/src/build/webpack-build/impl.ts b/packages/next/src/build/webpack-build/impl.ts index afc62313e14be..9388f3e0408e1 100644 --- a/packages/next/src/build/webpack-build/impl.ts +++ b/packages/next/src/build/webpack-build/impl.ts @@ -1,7 +1,7 @@ import type { webpack } from 'next/dist/compiled/webpack/webpack' import { stringBufferUtils } from 'next/dist/compiled/webpack-sources3' import { red } from '../../lib/picocolors' -import formatWebpackMessages from '../../client/components/react-dev-overlay/internal/helpers/format-webpack-messages' +import formatWebpackMessages from '../../client/components/react-dev-overlay/_experimental/internal/helpers/format-webpack-messages' import { nonNullable } from '../../lib/non-nullable' import type { COMPILER_INDEXES } from '../../shared/lib/constants' import { diff --git a/packages/next/src/cli/next-info.ts b/packages/next/src/cli/next-info.ts index 0e2c36df3f8bb..506c43c869872 100755 --- a/packages/next/src/cli/next-info.ts +++ b/packages/next/src/cli/next-info.ts @@ -8,7 +8,7 @@ import { PHASE_INFO } from '../shared/lib/constants' import loadConfig from '../server/config' import { getRegistry } from '../lib/helpers/get-registry' import { parseVersionInfo } from '../server/dev/parse-version-info' -import { getStaleness } from '../client/components/react-dev-overlay/internal/components/VersionStalenessInfo/VersionStalenessInfo' +import { getStaleness } from '../client/components/react-dev-overlay/_experimental/internal/components/version-staleness-info/version-staleness-info' import { warn } from '../build/output/log' export type NextInfoOptions = { diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.tsx index 428146d23a9db..f4b1cfc12c80e 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.tsx @@ -1,9 +1,9 @@ import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' -import type { OriginalStackFrame } from '../../../../internal/helpers/stack-frame' +import type { OriginalStackFrame } from '../../helpers/stack-frame' import { HotlinkedText } from '../hot-linked-text' import { ExternalIcon } from '../../icons/external' -import { getFrameSource } from '../../../../internal/helpers/stack-frame' +import { getFrameSource } from '../../helpers/stack-frame' import { useOpenInEditor } from '../../helpers/use-open-in-editor' import { noop as css } from '../../helpers/noop-template' diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx index 8f7e914a3ea4f..8cbd6802d478d 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx @@ -5,7 +5,7 @@ import stripAnsi from 'next/dist/compiled/strip-ansi' import { useMemo } from 'react' import { HotlinkedText } from '../hot-linked-text' -import { getFrameSource } from '../../../../internal/helpers/stack-frame' +import { getFrameSource } from '../../helpers/stack-frame' import { useOpenInEditor } from '../../helpers/use-open-in-editor' import { noop as css } from '../../helpers/noop-template' import { ExternalIcon } from '../../icons/external' diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/call-stack/call-stack.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/call-stack/call-stack.tsx index 79f3365341a31..c5c4a1d79e211 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/call-stack/call-stack.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/call-stack/call-stack.tsx @@ -1,4 +1,4 @@ -import type { OriginalStackFrame } from '../../../../../internal/helpers/stack-frame' +import type { OriginalStackFrame } from '../../../helpers/stack-frame' import { useMemo, useState, useRef } from 'react' import { CallStackFrame } from '../../call-stack-frame/call-stack-frame' import { noop as css } from '../../../helpers/noop-template' diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/internal/next-logo.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/internal/next-logo.tsx index 91ad664b3dbbe..cf581954e8396 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/internal/next-logo.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/internal/next-logo.tsx @@ -1,5 +1,5 @@ import { forwardRef, useEffect, useRef, useState } from 'react' -import { noop as css } from '../../../../../../internal/helpers/noop-template' +import { noop as css } from '../../../../helpers/noop-template' import mergeRefs from '../../../../helpers/merge-refs' import { useMinimumLoadingTimeMultiple } from './use-minimum-loading-time-multiple' diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-layout/error-overlay-layout.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-layout/error-overlay-layout.tsx index 582a4e9fa44bc..40abb81329498 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-layout/error-overlay-layout.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-layout/error-overlay-layout.tsx @@ -32,7 +32,7 @@ import { CALL_STACK_STYLES } from '../call-stack/call-stack' import { OVERLAY_STYLES, ErrorOverlayOverlay } from '../overlay/overlay' import { ErrorOverlayBottomStack } from '../error-overlay-bottom-stack' import type { ErrorBaseProps } from '../error-overlay/error-overlay' -import type { ReadyRuntimeError } from '../../../../../internal/helpers/get-error-by-type' +import type { ReadyRuntimeError } from '../../../helpers/get-error-by-type' import { EnvironmentNameLabel } from '../environment-name-label/environment-name-label' interface ErrorOverlayLayoutProps extends ErrorBaseProps { diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-nav/error-overlay-nav.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-nav/error-overlay-nav.tsx index bf7cc109f124e..f5e20bc8a8e31 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-nav/error-overlay-nav.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-nav/error-overlay-nav.tsx @@ -3,7 +3,7 @@ import type { VersionInfo } from '../../../../../../../../server/dev/parse-versi import { ErrorOverlayPagination } from '../error-overlay-pagination/error-overlay-pagination' import { VersionStalenessInfo } from '../../version-staleness-info/version-staleness-info' import { noop as css } from '../../../helpers/noop-template' -import type { ReadyRuntimeError } from '../../../../../internal/helpers/get-error-by-type' +import type { ReadyRuntimeError } from '../../../helpers/get-error-by-type' type ErrorOverlayNavProps = { runtimeErrors?: ReadyRuntimeError[] diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-pagination/error-overlay-pagination.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-pagination/error-overlay-pagination.tsx index 5c9a2576957fb..b3a50b36e0f27 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-pagination/error-overlay-pagination.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-pagination/error-overlay-pagination.tsx @@ -8,7 +8,7 @@ import { import { noop as css } from '../../../helpers/noop-template' import { LeftArrow } from '../../../icons/left-arrow' import { RightArrow } from '../../../icons/right-arrow' -import type { ReadyRuntimeError } from '../../../../../internal/helpers/get-error-by-type' +import type { ReadyRuntimeError } from '../../../helpers/get-error-by-type' type ErrorPaginationProps = { runtimeErrors: ReadyRuntimeError[] diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay/error-overlay.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay/error-overlay.tsx index 350645849404f..f5685ba3577e4 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay/error-overlay.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay/error-overlay.tsx @@ -4,7 +4,7 @@ import { BuildError } from '../../../container/build-error' import { Errors } from '../../../container/errors' import { RootLayoutMissingTagsError } from '../../../container/root-layout-missing-tags-error' import { useDelayedRender } from '../../../hooks/use-delayed-render' -import type { ReadyRuntimeError } from '../../../../../internal/helpers/get-error-by-type' +import type { ReadyRuntimeError } from '../../../helpers/get-error-by-type' const transitionDurationMs = 200 diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/terminal/terminal.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/terminal/terminal.tsx index c0d500a5447ac..02934f62fa2ce 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/terminal/terminal.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/terminal/terminal.tsx @@ -4,7 +4,7 @@ import { HotlinkedText } from '../hot-linked-text' import { EditorLink } from './editor-link' import { ExternalIcon } from '../../icons/external' import { noop as css } from '../../helpers/noop-template' -import { getFrameSource } from '../../../../internal/helpers/stack-frame' +import { getFrameSource } from '../../helpers/stack-frame' import { useOpenInEditor } from '../../helpers/use-open-in-editor' import { FileIcon } from '../../icons/file' diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.stories.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.stories.tsx index 34ac7997d015a..37a12f779336f 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.stories.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.stories.tsx @@ -2,8 +2,8 @@ import type { Meta, StoryObj } from '@storybook/react' import { Errors } from './errors' import { withShadowPortal } from '../storybook/with-shadow-portal' -import type { ReadyRuntimeError } from '../../../internal/helpers/get-error-by-type' -import { lorem } from '../../../internal/utils/lorem' +import type { ReadyRuntimeError } from '../helpers/get-error-by-type' +import { lorem } from '../utils/lorem' const meta: Meta = { component: Errors, diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.tsx index 785f7db98547d..038309ab1ca52 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.tsx @@ -16,7 +16,7 @@ import { } from '../../../../errors/console-error' import { extractNextErrorCode } from '../../../../../../lib/error-telemetry-utils' import { ErrorOverlayLayout } from '../components/errors/error-overlay-layout/error-overlay-layout' -import type { ReadyRuntimeError } from '../../../internal/helpers/get-error-by-type' +import type { ReadyRuntimeError } from '../helpers/get-error-by-type' import type { ErrorBaseProps } from '../components/errors/error-overlay/error-overlay' export interface ErrorsProps extends ErrorBaseProps { diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/runtime-error/index.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/runtime-error/index.tsx index a10bd127f444f..7b0ce64f452a4 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/runtime-error/index.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/runtime-error/index.tsx @@ -6,7 +6,7 @@ import { PSEUDO_HTML_DIFF_STYLES } from './component-stack-pseudo-html' import { useFrames, type ReadyRuntimeError, -} from '../../../../internal/helpers/get-error-by-type' +} from '../../helpers/get-error-by-type' export type RuntimeErrorProps = { error: ReadyRuntimeError diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/runtime-error/render-error.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/runtime-error/render-error.tsx index 260897f34f290..3cfa9ddb9e4f5 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/runtime-error/render-error.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/runtime-error/render-error.tsx @@ -12,7 +12,7 @@ import { import { getErrorByType, type ReadyRuntimeError, -} from '../../../../internal/helpers/get-error-by-type' +} from '../../helpers/get-error-by-type' export type SupportedErrorEvent = { id: number diff --git a/packages/next/src/client/components/react-dev-overlay/internal/helpers/get-error-by-type.ts b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/helpers/get-error-by-type.ts similarity index 94% rename from packages/next/src/client/components/react-dev-overlay/internal/helpers/get-error-by-type.ts rename to packages/next/src/client/components/react-dev-overlay/_experimental/internal/helpers/get-error-by-type.ts index 50ec9eeba6fbc..1ae83d9c72d85 100644 --- a/packages/next/src/client/components/react-dev-overlay/internal/helpers/get-error-by-type.ts +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/helpers/get-error-by-type.ts @@ -1,12 +1,12 @@ import { ACTION_UNHANDLED_ERROR, ACTION_UNHANDLED_REJECTION, -} from '../../shared' -import type { SupportedErrorEvent } from '../container/Errors' +} from '../../../shared' +import type { SupportedErrorEvent } from '../container/runtime-error/render-error' import { getOriginalStackFrames } from './stack-frame' import type { OriginalStackFrame } from './stack-frame' import type { ComponentStackFrame } from './parse-component-stack' -import { getErrorSource } from '../../../../../shared/lib/error-source' +import { getErrorSource } from '../../../../../../shared/lib/error-source' import React from 'react' export type ReadyRuntimeError = { diff --git a/packages/next/src/client/components/react-dev-overlay/internal/helpers/stack-frame.ts b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/helpers/stack-frame.ts similarity index 99% rename from packages/next/src/client/components/react-dev-overlay/internal/helpers/stack-frame.ts rename to packages/next/src/client/components/react-dev-overlay/_experimental/internal/helpers/stack-frame.ts index 6d1f86d22734c..a07f99f9127a4 100644 --- a/packages/next/src/client/components/react-dev-overlay/internal/helpers/stack-frame.ts +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/helpers/stack-frame.ts @@ -3,7 +3,7 @@ import type { OriginalStackFrameResponse, OriginalStackFrameResponseResult, OriginalStackFramesRequest, -} from '../../server/shared' +} from '../../../server/shared' import { isWebpackInternalResource, formatFrameSourceFile, diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/close-icon.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/close-icon.tsx deleted file mode 100644 index e5a51a44a3eb5..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/close-icon.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from 'react' - -const CloseIcon = () => { - return ( - - - - - ) -} - -export { CloseIcon } diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/lightning-bolt.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/lightning-bolt.tsx deleted file mode 100644 index debf0181551f5..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/lightning-bolt.tsx +++ /dev/null @@ -1,16 +0,0 @@ -export const LightningBolt = (props: React.SVGProps) => ( - - - -) diff --git a/packages/next/src/client/components/react-dev-overlay/internal/utils/lorem.ts b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/utils/lorem.ts similarity index 100% rename from packages/next/src/client/components/react-dev-overlay/internal/utils/lorem.ts rename to packages/next/src/client/components/react-dev-overlay/_experimental/internal/utils/lorem.ts diff --git a/packages/next/src/client/components/react-dev-overlay/app/client-entry.tsx b/packages/next/src/client/components/react-dev-overlay/app/client-entry.tsx index b4f3e9b3d97a3..8a748e5733999 100644 --- a/packages/next/src/client/components/react-dev-overlay/app/client-entry.tsx +++ b/packages/next/src/client/components/react-dev-overlay/app/client-entry.tsx @@ -1,6 +1,6 @@ import React from 'react' import ReactDevOverlay from './react-dev-overlay' -import { getSocketUrl } from '../internal/helpers/get-socket-url' +import { getSocketUrl } from '../_experimental/internal/helpers/get-socket-url' import { INITIAL_OVERLAY_STATE } from '../shared' import { HMR_ACTIONS_SENT_TO_BROWSER } from '../../../../server/dev/hot-reloader-types' import GlobalError from '../../error-boundary' diff --git a/packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx b/packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx index def8ffa9ad65f..c1095644449b0 100644 --- a/packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx +++ b/packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx @@ -8,7 +8,7 @@ import { useSyncExternalStore, } from 'react' import stripAnsi from 'next/dist/compiled/strip-ansi' -import formatWebpackMessages from '../internal/helpers/format-webpack-messages' +import formatWebpackMessages from '../_experimental/internal/helpers/format-webpack-messages' import { useRouter } from '../../navigation' import { ACTION_BEFORE_REFRESH, @@ -22,7 +22,7 @@ import { ACTION_VERSION_INFO, useErrorOverlayReducer, } from '../shared' -import { parseStack } from '../internal/helpers/parse-stack' +import { parseStack } from '../_experimental/internal/helpers/parse-stack' import ReactDevOverlay from './react-dev-overlay' import { useErrorHandler } from '../../errors/use-error-handler' import { RuntimeErrorHandler } from '../../errors/runtime-error-handler' @@ -31,8 +31,8 @@ import { useTurbopack, useWebsocket, useWebsocketPing, -} from '../internal/helpers/use-websocket' -import { parseComponentStack } from '../internal/helpers/parse-component-stack' +} from '../_experimental/internal/helpers/use-websocket' +import { parseComponentStack } from '../_experimental/internal/helpers/parse-component-stack' import type { VersionInfo } from '../../../../server/dev/parse-version-info' import { HMR_ACTIONS_SENT_TO_BROWSER } from '../../../../server/dev/hot-reloader-types' import type { diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/CodeFrame.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/CodeFrame.tsx deleted file mode 100644 index 299787dea29af..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/CodeFrame.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import Anser from 'next/dist/compiled/anser' -import * as React from 'react' -import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' -import stripAnsi from 'next/dist/compiled/strip-ansi' -import { getFrameSource } from '../../helpers/stack-frame' -import { useOpenInEditor } from '../../helpers/use-open-in-editor' -import { HotlinkedText } from '../hot-linked-text' - -export type CodeFrameProps = { stackFrame: StackFrame; codeFrame: string } - -export const CodeFrame: React.FC = function CodeFrame({ - stackFrame, - codeFrame, -}) { - // Strip leading spaces out of the code frame: - const formattedFrame = React.useMemo(() => { - const lines = codeFrame.split(/\r?\n/g) - - // Find the minimum length of leading spaces after `|` in the code frame - const miniLeadingSpacesLength = lines - .map((line) => - /^>? +\d+ +\| [ ]+/.exec(stripAnsi(line)) === null - ? null - : /^>? +\d+ +\| ( *)/.exec(stripAnsi(line)) - ) - .filter(Boolean) - .map((v) => v!.pop()!) - .reduce((c, n) => (isNaN(c) ? n.length : Math.min(c, n.length)), NaN) - - // When the minimum length of leading spaces is greater than 1, remove them - // from the code frame to help the indentation looks better when there's a lot leading spaces. - if (miniLeadingSpacesLength > 1) { - return lines - .map((line, a) => - ~(a = line.indexOf('|')) - ? line.substring(0, a) + - line.substring(a).replace(`^\\ {${miniLeadingSpacesLength}}`, '') - : line - ) - .join('\n') - } - return lines.join('\n') - }, [codeFrame]) - - const decoded = React.useMemo(() => { - return Anser.ansiToJson(formattedFrame, { - json: true, - use_classes: true, - remove_empty: true, - }) - }, [formattedFrame]) - - const open = useOpenInEditor({ - file: stackFrame.file, - lineNumber: stackFrame.lineNumber, - column: stackFrame.column, - }) - - // TODO: make the caret absolute - return ( -
-
-

- - {getFrameSource(stackFrame)} @{' '} - - - - - - - -

-
-
-        {decoded.map((entry, index) => (
-          
-            {entry.content}
-          
-        ))}
-      
-
- ) -} diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/index.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/index.tsx deleted file mode 100644 index 59818df56eddb..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { CodeFrame } from './CodeFrame' diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/styles.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/styles.tsx deleted file mode 100644 index 2b86f7652ba14..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/CodeFrame/styles.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { noop as css } from '../../helpers/noop-template' - -const styles = css` - [data-nextjs-codeframe] { - overflow: auto; - border-radius: var(--size-gap-half); - background-color: var(--color-ansi-bg); - color: var(--color-ansi-fg); - margin-bottom: var(--size-gap-double); - } - [data-nextjs-codeframe]::selection, - [data-nextjs-codeframe] *::selection { - background-color: var(--color-ansi-selection); - } - [data-nextjs-codeframe] * { - color: inherit; - background-color: transparent; - font-family: var(--font-stack-monospace); - } - - [data-nextjs-codeframe] > * { - margin: 0; - padding: calc(var(--size-gap) + var(--size-gap-half)) - calc(var(--size-gap-double) + var(--size-gap-half)); - } - [data-nextjs-codeframe] > div { - display: inline-block; - width: auto; - min-width: 100%; - border-bottom: 1px solid var(--color-ansi-bright-black); - } - [data-nextjs-codeframe] > div > p { - display: flex; - align-items: center; - justify-content: space-between; - cursor: pointer; - margin: 0; - } - [data-nextjs-codeframe] > div > p:hover { - text-decoration: underline dotted; - } - [data-nextjs-codeframe] div > p > svg { - width: auto; - height: 1em; - margin-left: 8px; - } - [data-nextjs-codeframe] div > pre { - overflow: hidden; - display: inline-block; - } -` - -export { styles } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/Dialog.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/Dialog.tsx deleted file mode 100644 index 39c8005d16622..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/Dialog.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import * as React from 'react' -import { useOnClickOutside } from '../../hooks/use-on-click-outside' - -export type DialogProps = { - children?: React.ReactNode - type: 'error' | 'warning' - 'aria-labelledby': string - 'aria-describedby': string - onClose?: () => void -} - -const Dialog: React.FC = function Dialog({ - children, - type, - onClose, - ...props -}) { - const [dialog, setDialog] = React.useState(null) - const [role, setRole] = React.useState( - typeof document !== 'undefined' && document.hasFocus() - ? 'dialog' - : undefined - ) - const onDialog = React.useCallback((node: HTMLDivElement | null) => { - setDialog(node) - }, []) - useOnClickOutside(dialog, (e) => { - e.preventDefault() - return onClose?.() - }) - - // Make HTMLElements with `role=link` accessible to be triggered by the - // keyboard, i.e. [Enter]. - React.useEffect(() => { - if (dialog == null) { - return - } - - const root = dialog.getRootNode() - // Always true, but we do this for TypeScript: - if (!(root instanceof ShadowRoot)) { - return - } - const shadowRoot = root - function handler(e: KeyboardEvent) { - const el = shadowRoot.activeElement - if ( - e.key === 'Enter' && - el instanceof HTMLElement && - el.getAttribute('role') === 'link' - ) { - e.preventDefault() - e.stopPropagation() - - el.click() - } - } - - function handleFocus() { - // safari will force itself as the active application when a background page triggers any sort of autofocus - // this is a workaround to only set the dialog role if the document has focus - setRole(document.hasFocus() ? 'dialog' : undefined) - } - - shadowRoot.addEventListener('keydown', handler as EventListener) - window.addEventListener('focus', handleFocus) - window.addEventListener('blur', handleFocus) - return () => { - shadowRoot.removeEventListener('keydown', handler as EventListener) - window.removeEventListener('focus', handleFocus) - window.removeEventListener('blur', handleFocus) - } - }, [dialog]) - - return ( -
-
- {children} -
- ) -} - -export { Dialog } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogBody.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogBody.tsx deleted file mode 100644 index f46fb9957f4e5..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogBody.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react' - -export type DialogBodyProps = { - children?: React.ReactNode - className?: string -} - -const DialogBody: React.FC = function DialogBody({ - children, - className, -}) { - return ( -
- {children} -
- ) -} - -export { DialogBody } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogContent.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogContent.tsx deleted file mode 100644 index 85fcc83b2983e..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogContent.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react' - -export type DialogContentProps = { - children?: React.ReactNode - className?: string -} - -const DialogContent: React.FC = function DialogContent({ - children, - className, -}) { - return ( -
- {children} -
- ) -} - -export { DialogContent } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogHeader.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogHeader.tsx deleted file mode 100644 index c53a613cf9ebd..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/DialogHeader.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react' - -export type DialogHeaderProps = { - children?: React.ReactNode - className?: string -} - -const DialogHeader: React.FC = function DialogHeader({ - children, - className, -}) { - return ( -
- {children} -
- ) -} - -export { DialogHeader } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/index.ts b/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/index.ts deleted file mode 100644 index 15a3c57a88686..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { Dialog } from './Dialog' -export { DialogBody } from './DialogBody' -export { DialogContent } from './DialogContent' -export { DialogHeader } from './DialogHeader' -export { styles } from './styles' diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/styles.ts b/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/styles.ts deleted file mode 100644 index ac3544e63c799..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Dialog/styles.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { noop as css } from '../../helpers/noop-template' - -const styles = css` - [data-nextjs-dialog] { - display: flex; - flex-direction: column; - width: 100%; - margin-right: auto; - margin-left: auto; - outline: none; - background: var(--color-background); - border-radius: var(--size-gap); - box-shadow: 0 var(--size-gap-half) var(--size-gap-double) - rgba(0, 0, 0, 0.25); - max-height: calc(100% - 56px); - overflow-y: hidden; - } - - @media (max-height: 812px) { - [data-nextjs-dialog-overlay] { - max-height: calc(100% - 15px); - } - } - - @media (min-width: 576px) { - [data-nextjs-dialog] { - max-width: 540px; - box-shadow: 0 var(--size-gap) var(--size-gap-quad) rgba(0, 0, 0, 0.25); - } - } - - @media (min-width: 768px) { - [data-nextjs-dialog] { - max-width: 720px; - } - } - - @media (min-width: 992px) { - [data-nextjs-dialog] { - max-width: 960px; - } - } - - [data-nextjs-dialog-banner] { - position: relative; - } - [data-nextjs-dialog-banner].banner-warning { - border-color: var(--color-ansi-yellow); - } - [data-nextjs-dialog-banner].banner-error { - border-color: var(--color-ansi-red); - } - - [data-nextjs-dialog-banner]::after { - z-index: 2; - content: ''; - position: absolute; - top: 0; - right: 0; - width: 100%; - /* banner width: */ - border-top-width: var(--size-gap-half); - border-bottom-width: 0; - border-top-style: solid; - border-bottom-style: solid; - border-top-color: inherit; - border-bottom-color: transparent; - } - - [data-nextjs-dialog-content] { - overflow-y: auto; - border: none; - margin: 0; - /* calc(padding + banner width offset) */ - padding: calc(var(--size-gap-double) + var(--size-gap-half)) - var(--size-gap-double); - height: 100%; - display: flex; - flex-direction: column; - } - [data-nextjs-dialog-content] > [data-nextjs-dialog-header] { - flex-shrink: 0; - margin-bottom: var(--size-gap-double); - } - [data-nextjs-dialog-content] > [data-nextjs-dialog-body] { - position: relative; - flex: 1 1 auto; - } -` - -export { styles } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/LeftRightDialogHeader.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/LeftRightDialogHeader.tsx deleted file mode 100644 index 060a4f74b9dc9..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/LeftRightDialogHeader.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import * as React from 'react' -import { CloseIcon } from '../../icons/CloseIcon' - -export type LeftRightDialogHeaderProps = { - children?: React.ReactNode - className?: string - previous: (() => void) | null - next: (() => void) | null - close?: () => void -} - -const LeftRightDialogHeader: React.FC = - function LeftRightDialogHeader({ - children, - className, - previous, - next, - close, - }) { - const buttonLeft = React.useRef(null) - const buttonRight = React.useRef(null) - const buttonClose = React.useRef(null) - - const [nav, setNav] = React.useState(null) - const onNav = React.useCallback((el: HTMLElement) => { - setNav(el) - }, []) - - React.useEffect(() => { - if (nav == null) { - return - } - - const root = nav.getRootNode() - const d = self.document - - function handler(e: KeyboardEvent) { - if (e.key === 'ArrowLeft') { - e.preventDefault() - e.stopPropagation() - if (buttonLeft.current) { - buttonLeft.current.focus() - } - previous && previous() - } else if (e.key === 'ArrowRight') { - e.preventDefault() - e.stopPropagation() - if (buttonRight.current) { - buttonRight.current.focus() - } - next && next() - } else if (e.key === 'Escape') { - e.preventDefault() - e.stopPropagation() - if (root instanceof ShadowRoot) { - const a = root.activeElement - if (a && a !== buttonClose.current && a instanceof HTMLElement) { - a.blur() - return - } - } - - close?.() - } - } - - root.addEventListener('keydown', handler as EventListener) - if (root !== d) { - d.addEventListener('keydown', handler) - } - return function () { - root.removeEventListener('keydown', handler as EventListener) - if (root !== d) { - d.removeEventListener('keydown', handler) - } - } - }, [close, nav, next, previous]) - - // Unlock focus for browsers like Firefox, that break all user focus if the - // currently focused item becomes disabled. - React.useEffect(() => { - if (nav == null) { - return - } - - const root = nav.getRootNode() - // Always true, but we do this for TypeScript: - if (root instanceof ShadowRoot) { - const a = root.activeElement - - if (previous == null) { - if (buttonLeft.current && a === buttonLeft.current) { - buttonLeft.current.blur() - } - } else if (next == null) { - if (buttonRight.current && a === buttonRight.current) { - buttonRight.current.blur() - } - } - } - }, [nav, next, previous]) - - return ( -
- - {close ? ( - - ) : null} -
- ) - } - -export { LeftRightDialogHeader } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/index.ts b/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/index.ts deleted file mode 100644 index b63edb12ba22a..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { LeftRightDialogHeader } from './LeftRightDialogHeader' -export { styles } from './styles' diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/styles.ts b/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/styles.ts deleted file mode 100644 index 38762cf5bc70a..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/LeftRightDialogHeader/styles.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { noop as css } from '../../helpers/noop-template' - -const styles = css` - [data-nextjs-dialog-left-right] { - display: flex; - flex-direction: row; - align-content: center; - align-items: center; - justify-content: space-between; - } - [data-nextjs-dialog-left-right] > nav { - flex: 1; - display: flex; - align-items: center; - margin-right: var(--size-gap); - } - [data-nextjs-dialog-left-right] > nav > button { - display: inline-flex; - align-items: center; - justify-content: center; - - width: calc(var(--size-gap-double) + var(--size-gap)); - height: calc(var(--size-gap-double) + var(--size-gap)); - font-size: 0; - border: none; - background-color: rgba(255, 85, 85, 0.1); - color: var(--color-ansi-red); - cursor: pointer; - transition: background-color 0.25s ease; - } - [data-nextjs-dialog-left-right] > nav > button > svg { - width: auto; - height: calc(var(--size-gap) + var(--size-gap-half)); - } - [data-nextjs-dialog-left-right] > nav > button:hover { - background-color: rgba(255, 85, 85, 0.2); - } - [data-nextjs-dialog-left-right] > nav > button:disabled { - background-color: rgba(255, 85, 85, 0.1); - color: rgba(255, 85, 85, 0.4); - cursor: not-allowed; - } - - [data-nextjs-dialog-left-right] > nav > button:first-of-type { - border-radius: var(--size-gap-half) 0 0 var(--size-gap-half); - margin-right: 1px; - } - [data-nextjs-dialog-left-right] > nav > button:last-of-type { - border-radius: 0 var(--size-gap-half) var(--size-gap-half) 0; - } - - [data-nextjs-dialog-left-right] > button:last-of-type { - border: 0; - padding: 0; - - background-color: transparent; - appearance: none; - - opacity: 0.4; - transition: opacity 0.25s ease; - - color: var(--color-font); - } - [data-nextjs-dialog-left-right] > button:last-of-type:hover { - opacity: 0.7; - } -` - -export { styles } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/Overlay.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/Overlay.tsx deleted file mode 100644 index 70a670b6ff90b..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/Overlay.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import allyTrap from './maintain--tab-focus' -import * as React from 'react' -import { lock, unlock } from './body-locker' - -export type OverlayProps = { - children?: React.ReactNode - className?: string - fixed?: boolean -} - -const Overlay: React.FC = function Overlay({ - className, - children, - fixed, -}) { - React.useEffect(() => { - lock() - return () => { - unlock() - } - }, []) - - const [overlay, setOverlay] = React.useState(null) - const onOverlay = React.useCallback((el: HTMLDivElement) => { - setOverlay(el) - }, []) - - React.useEffect(() => { - if (overlay == null) { - return - } - - const handle2 = allyTrap({ context: overlay }) - return () => { - handle2.disengage() - } - }, [overlay]) - - return ( -
-
- {children} -
- ) -} - -export { Overlay } diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/body-locker.ts b/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/body-locker.ts deleted file mode 100644 index 8e33e1c8d9924..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/body-locker.ts +++ /dev/null @@ -1,41 +0,0 @@ -let previousBodyPaddingRight: string | undefined -let previousBodyOverflowSetting: string | undefined - -let activeLocks = 0 - -export function lock() { - setTimeout(() => { - if (activeLocks++ > 0) { - return - } - - const scrollBarGap = - window.innerWidth - document.documentElement.clientWidth - - if (scrollBarGap > 0) { - previousBodyPaddingRight = document.body.style.paddingRight - document.body.style.paddingRight = `${scrollBarGap}px` - } - - previousBodyOverflowSetting = document.body.style.overflow - document.body.style.overflow = 'hidden' - }) -} - -export function unlock() { - setTimeout(() => { - if (activeLocks === 0 || --activeLocks !== 0) { - return - } - - if (previousBodyPaddingRight !== undefined) { - document.body.style.paddingRight = previousBodyPaddingRight - previousBodyPaddingRight = undefined - } - - if (previousBodyOverflowSetting !== undefined) { - document.body.style.overflow = previousBodyOverflowSetting - previousBodyOverflowSetting = undefined - } - }) -} diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/index.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/index.tsx deleted file mode 100644 index 9f8311327322f..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { Overlay } from './Overlay' diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/maintain--tab-focus.ts b/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/maintain--tab-focus.ts deleted file mode 100644 index c206c254a4807..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Overlay/maintain--tab-focus.ts +++ /dev/null @@ -1,3569 +0,0 @@ -/* eslint-disable */ -// @ts-nocheck -// Copied from https://github.com/medialize/ally.js -// License: MIT -// Copyright (c) 2015 Rodney Rehm -// -// Entrypoint: ally.js/maintain/tab-focus - -import _platform from 'next/dist/compiled/platform' -import cssEscape from 'next/dist/compiled/css.escape' - -// input may be undefined, selector-tring, Node, NodeList, HTMLCollection, array of Nodes -// yes, to some extent this is a bad replica of jQuery's constructor function -function nodeArray(input) { - if (!input) { - return [] - } - - if (Array.isArray(input)) { - return input - } - - // instanceof Node - does not work with iframes - if (input.nodeType !== undefined) { - return [input] - } - - if (typeof input === 'string') { - input = document.querySelectorAll(input) - } - - if (input.length !== undefined) { - return [].slice.call(input, 0) - } - - throw new TypeError('unexpected input ' + String(input)) -} - -function contextToElement(_ref) { - var context = _ref.context, - _ref$label = _ref.label, - label = _ref$label === undefined ? 'context-to-element' : _ref$label, - resolveDocument = _ref.resolveDocument, - defaultToDocument = _ref.defaultToDocument - - var element = nodeArray(context)[0] - - if (resolveDocument && element && element.nodeType === Node.DOCUMENT_NODE) { - element = element.documentElement - } - - if (!element && defaultToDocument) { - return document.documentElement - } - - if (!element) { - throw new TypeError(label + ' requires valid options.context') - } - - if ( - element.nodeType !== Node.ELEMENT_NODE && - element.nodeType !== Node.DOCUMENT_FRAGMENT_NODE - ) { - throw new TypeError(label + ' requires options.context to be an Element') - } - - return element -} - -function getShadowHost() { - var _ref = - arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - context = _ref.context - - var element = contextToElement({ - label: 'get/shadow-host', - context: context, - }) - - // walk up to the root - var container = null - - while (element) { - container = element - element = element.parentNode - } - - // https://developer.mozilla.org/docs/Web/API/Node.nodeType - // NOTE: Firefox 34 does not expose ShadowRoot.host (but 37 does) - if ( - container.nodeType === container.DOCUMENT_FRAGMENT_NODE && - container.host - ) { - // the root is attached to a fragment node that has a host - return container.host - } - - return null -} - -function getDocument(node) { - if (!node) { - return document - } - - if (node.nodeType === Node.DOCUMENT_NODE) { - return node - } - - return node.ownerDocument || document -} - -function isActiveElement(context) { - var element = contextToElement({ - label: 'is/active-element', - resolveDocument: true, - context: context, - }) - - var _document = getDocument(element) - if (_document.activeElement === element) { - return true - } - - var shadowHost = getShadowHost({ context: element }) - if (shadowHost && shadowHost.shadowRoot.activeElement === element) { - return true - } - - return false -} - -// [elem, elem.parent, elem.parent.parent, …, html] -// will not contain the shadowRoot (DOCUMENT_FRAGMENT_NODE) and shadowHost -function getParents() { - var _ref = - arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - context = _ref.context - - var list = [] - var element = contextToElement({ - label: 'get/parents', - context: context, - }) - - while (element) { - list.push(element) - // IE does know support parentElement on SVGElement - element = element.parentNode - if (element && element.nodeType !== Node.ELEMENT_NODE) { - element = null - } - } - - return list -} - -// Element.prototype.matches may be available at a different name -// https://developer.mozilla.org/en/docs/Web/API/Element/matches - -var names = [ - 'matches', - 'webkitMatchesSelector', - 'mozMatchesSelector', - 'msMatchesSelector', -] -var name = null - -function findMethodName(element) { - names.some(function (_name) { - if (!element[_name]) { - return false - } - - name = _name - return true - }) -} - -function elementMatches(element, selector) { - if (!name) { - findMethodName(element) - } - - return element[name](selector) -} - -// deep clone of original platform -var platform = JSON.parse(JSON.stringify(_platform)) - -// operating system -var os = platform.os.family || '' -var ANDROID = os === 'Android' -var WINDOWS = os.slice(0, 7) === 'Windows' -var OSX = os === 'OS X' -var IOS = os === 'iOS' - -// layout -var BLINK = platform.layout === 'Blink' -var GECKO = platform.layout === 'Gecko' -var TRIDENT = platform.layout === 'Trident' -var EDGE = platform.layout === 'EdgeHTML' -var WEBKIT = platform.layout === 'WebKit' - -// browser version (not layout engine version!) -var version = parseFloat(platform.version) -var majorVersion = Math.floor(version) -platform.majorVersion = majorVersion - -platform.is = { - // operating system - ANDROID: ANDROID, - WINDOWS: WINDOWS, - OSX: OSX, - IOS: IOS, - // layout - BLINK: BLINK, // "Chrome", "Chrome Mobile", "Opera" - GECKO: GECKO, // "Firefox" - TRIDENT: TRIDENT, // "Internet Explorer" - EDGE: EDGE, // "Microsoft Edge" - WEBKIT: WEBKIT, // "Safari" - // INTERNET EXPLORERS - IE9: TRIDENT && majorVersion === 9, - IE10: TRIDENT && majorVersion === 10, - IE11: TRIDENT && majorVersion === 11, -} - -function before() { - var data = { - // remember what had focus to restore after test - activeElement: document.activeElement, - // remember scroll positions to restore after test - windowScrollTop: window.scrollTop, - windowScrollLeft: window.scrollLeft, - bodyScrollTop: document.body.scrollTop, - bodyScrollLeft: document.body.scrollLeft, - } - - // wrap tests in an element hidden from screen readers to prevent them - // from announcing focus, which can be quite irritating to the user - var iframe = document.createElement('iframe') - iframe.setAttribute( - 'style', - 'position:absolute; position:fixed; top:0; left:-2px; width:1px; height:1px; overflow:hidden;' - ) - iframe.setAttribute('aria-live', 'off') - iframe.setAttribute('aria-busy', 'true') - iframe.setAttribute('aria-hidden', 'true') - document.body.appendChild(iframe) - - var _window = iframe.contentWindow - var _document = _window.document - - _document.open() - _document.close() - var wrapper = _document.createElement('div') - _document.body.appendChild(wrapper) - - data.iframe = iframe - data.wrapper = wrapper - data.window = _window - data.document = _document - - return data -} - -// options.element: -// {string} element name -// {function} callback(wrapper, document) to generate an element -// options.mutate: (optional) -// {function} callback(element, wrapper, document) to manipulate element prior to focus-test. -// Can return DOMElement to define focus target (default: element) -// options.validate: (optional) -// {function} callback(element, focusTarget, document) to manipulate test-result -function test(data, options) { - // make sure we operate on a clean slate - data.wrapper.innerHTML = '' - // create dummy element to test focusability of - var element = - typeof options.element === 'string' - ? data.document.createElement(options.element) - : options.element(data.wrapper, data.document) - // allow callback to further specify dummy element - // and optionally define element to focus - var focus = - options.mutate && options.mutate(element, data.wrapper, data.document) - if (!focus && focus !== false) { - focus = element - } - // element needs to be part of the DOM to be focusable - !element.parentNode && data.wrapper.appendChild(element) - // test if the element with invalid tabindex can be focused - focus && focus.focus && focus.focus() - // validate test's result - return options.validate - ? options.validate(element, focus, data.document) - : data.document.activeElement === focus -} - -function after(data) { - // restore focus to what it was before test and cleanup - if (data.activeElement === document.body) { - document.activeElement && - document.activeElement.blur && - document.activeElement.blur() - if (platform.is.IE10) { - // IE10 does not redirect focus to when the activeElement is removed - document.body.focus() - } - } else { - data.activeElement && data.activeElement.focus && data.activeElement.focus() - } - - document.body.removeChild(data.iframe) - - // restore scroll position - window.scrollTop = data.windowScrollTop - window.scrollLeft = data.windowScrollLeft - document.body.scrollTop = data.bodyScrollTop - document.body.scrollLeft = data.bodyScrollLeft -} - -function detectFocus(tests) { - var data = before() - - var results = {} - Object.keys(tests).map(function (key) { - results[key] = test(data, tests[key]) - }) - - after(data) - return results -} - -// this file is overwritten by `npm run build:pre` -var version$1 = '1.4.1' - -/* - Facility to cache test results in localStorage. - - USAGE: - cache.get('key'); - cache.set('key', 'value'); - */ - -function readLocalStorage(key) { - // allow reading from storage to retrieve previous support results - // even while the document does not have focus - var data = void 0 - - try { - data = window.localStorage && window.localStorage.getItem(key) - data = data ? JSON.parse(data) : {} - } catch (e) { - data = {} - } - - return data -} - -function writeLocalStorage(key, value) { - if (!document.hasFocus()) { - // if the document does not have focus when tests are executed, focus() may - // not be handled properly and events may not be dispatched immediately. - // This can happen when a document is reloaded while Developer Tools have focus. - try { - window.localStorage && window.localStorage.removeItem(key) - } catch (e) { - // ignore - } - - return - } - - try { - window.localStorage && - window.localStorage.setItem(key, JSON.stringify(value)) - } catch (e) { - // ignore - } -} - -var userAgent = - (typeof window !== 'undefined' && window.navigator.userAgent) || '' -var cacheKey = 'ally-supports-cache' -var cache = readLocalStorage(cacheKey) - -// update the cache if ally or the user agent changed (newer version, etc) -if (cache.userAgent !== userAgent || cache.version !== version$1) { - cache = {} -} - -cache.userAgent = userAgent -cache.version = version$1 - -var cache$1 = { - get: function get() { - return cache - }, - set: function set(values) { - Object.keys(values).forEach(function (key) { - cache[key] = values[key] - }) - - cache.time = new Date().toISOString() - writeLocalStorage(cacheKey, cache) - }, -} - -function cssShadowPiercingDeepCombinator() { - var combinator = void 0 - - // see https://dev.w3.org/csswg/css-scoping-1/#deep-combinator - // https://bugzilla.mozilla.org/show_bug.cgi?id=1117572 - // https://code.google.com/p/chromium/issues/detail?id=446051 - try { - document.querySelector('html >>> :first-child') - combinator = '>>>' - } catch (noArrowArrowArrow) { - try { - // old syntax supported at least up to Chrome 41 - // https://code.google.com/p/chromium/issues/detail?id=446051 - document.querySelector('html /deep/ :first-child') - combinator = '/deep/' - } catch (noDeep) { - combinator = '' - } - } - - return combinator -} - -var gif = - 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' - -// https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-usemap -var focusAreaImgTabindex = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = - '' + - '' + - '' - - return element.querySelector('area') - }, -} - -// https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-usemap -var focusAreaTabindex = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = - '' + - '' + - '' - - return false - }, - validate: function validate(element, focusTarget, _document) { - if (platform.is.GECKO) { - // fixes https://github.com/medialize/ally.js/issues/35 - // Firefox loads the DataURI asynchronously, causing a false-negative - return true - } - - var focus = element.querySelector('area') - focus.focus() - return _document.activeElement === focus - }, -} - -// https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-usemap -var focusAreaWithoutHref = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = - '' + - '' + - '' - - return element.querySelector('area') - }, - validate: function validate(element, focusTarget, _document) { - if (platform.is.GECKO) { - // fixes https://github.com/medialize/ally.js/issues/35 - // Firefox loads the DataURI asynchronously, causing a false-negative - return true - } - - return _document.activeElement === focusTarget - }, -} - -var focusAudioWithoutControls = { - name: 'can-focus-audio-without-controls', - element: 'audio', - mutate: function mutate(element) { - try { - // invalid media file can trigger warning in console, data-uri to prevent HTTP request - element.setAttribute('src', gif) - } catch (e) { - // IE9 may throw "Error: Not implemented" - } - }, -} - -var invalidGif = - 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ' - -// NOTE: https://github.com/medialize/ally.js/issues/35 -// https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-usemap -var focusBrokenImageMap = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = - '' + - '' - - return element.querySelector('area') - }, -} - -// Children of focusable elements with display:flex are focusable in IE10-11 -var focusChildrenOfFocusableFlexbox = { - element: 'div', - mutate: function mutate(element) { - element.setAttribute('tabindex', '-1') - element.setAttribute( - 'style', - 'display: -webkit-flex; display: -ms-flexbox; display: flex;' - ) - element.innerHTML = 'hello' - return element.querySelector('span') - }, -} - -// fieldset[tabindex=0][disabled] should not be focusable, but Blink and WebKit disagree -// @specification https://www.w3.org/TR/html5/disabled-elements.html#concept-element-disabled -// @browser-issue Chromium https://crbug.com/453847 -// @browser-issue WebKit https://bugs.webkit.org/show_bug.cgi?id=141086 -var focusFieldsetDisabled = { - element: 'fieldset', - mutate: function mutate(element) { - element.setAttribute('tabindex', 0) - element.setAttribute('disabled', 'disabled') - }, -} - -var focusFieldset = { - element: 'fieldset', - mutate: function mutate(element) { - element.innerHTML = 'legend

content

' - }, -} - -// elements with display:flex are focusable in IE10-11 -var focusFlexboxContainer = { - element: 'span', - mutate: function mutate(element) { - element.setAttribute( - 'style', - 'display: -webkit-flex; display: -ms-flexbox; display: flex;' - ) - element.innerHTML = 'hello' - }, -} - -// form[tabindex=0][disabled] should be focusable as the -// specification doesn't know the disabled attribute on the form element -// @specification https://www.w3.org/TR/html5/forms.html#the-form-element -var focusFormDisabled = { - element: 'form', - mutate: function mutate(element) { - element.setAttribute('tabindex', 0) - element.setAttribute('disabled', 'disabled') - }, -} - -// NOTE: https://github.com/medialize/ally.js/issues/35 -// fixes https://github.com/medialize/ally.js/issues/20 -// https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-ismap -var focusImgIsmap = { - element: 'a', - mutate: function mutate(element) { - element.href = '#void' - element.innerHTML = '' - return element.querySelector('img') - }, -} - -// NOTE: https://github.com/medialize/ally.js/issues/35 -// https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-usemap -var focusImgUsemapTabindex = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = - '' + - '' - - return element.querySelector('img') - }, -} - -var focusInHiddenIframe = { - element: function element(wrapper, _document) { - var iframe = _document.createElement('iframe') - - // iframe must be part of the DOM before accessing the contentWindow is possible - wrapper.appendChild(iframe) - - // create the iframe's default document () - var iframeDocument = iframe.contentWindow.document - iframeDocument.open() - iframeDocument.close() - return iframe - }, - mutate: function mutate(iframe) { - iframe.style.visibility = 'hidden' - - var iframeDocument = iframe.contentWindow.document - var input = iframeDocument.createElement('input') - iframeDocument.body.appendChild(input) - return input - }, - validate: function validate(iframe) { - var iframeDocument = iframe.contentWindow.document - var focus = iframeDocument.querySelector('input') - return iframeDocument.activeElement === focus - }, -} - -var result = !platform.is.WEBKIT - -function focusInZeroDimensionObject() { - return result -} - -// Firefox allows *any* value and treats invalid values like tabindex="-1" -// @browser-issue Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054 -var focusInvalidTabindex = { - element: 'div', - mutate: function mutate(element) { - element.setAttribute('tabindex', 'invalid-value') - }, -} - -var focusLabelTabindex = { - element: 'label', - mutate: function mutate(element) { - element.setAttribute('tabindex', '-1') - }, - validate: function validate(element, focusTarget, _document) { - // force layout in Chrome 49, otherwise the element won't be focusable - /* eslint-disable no-unused-vars */ - var variableToPreventDeadCodeElimination = element.offsetHeight - /* eslint-enable no-unused-vars */ - element.focus() - return _document.activeElement === element - }, -} - -var svg = - 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtb' + - 'G5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBpZD0ic3ZnIj48dGV4dCB4PSIxMCIgeT0iMjAiIGlkPSJ' + - 'zdmctbGluay10ZXh0Ij50ZXh0PC90ZXh0Pjwvc3ZnPg==' - -// Note: IE10 on BrowserStack does not like this test - -var focusObjectSvgHidden = { - element: 'object', - mutate: function mutate(element) { - element.setAttribute('type', 'image/svg+xml') - element.setAttribute('data', svg) - element.setAttribute('width', '200') - element.setAttribute('height', '50') - element.style.visibility = 'hidden' - }, -} - -// Note: IE10 on BrowserStack does not like this test - -var focusObjectSvg = { - name: 'can-focus-object-svg', - element: 'object', - mutate: function mutate(element) { - element.setAttribute('type', 'image/svg+xml') - element.setAttribute('data', svg) - element.setAttribute('width', '200') - element.setAttribute('height', '50') - }, - validate: function validate(element, focusTarget, _document) { - if (platform.is.GECKO) { - // Firefox seems to be handling the object creation asynchronously and thereby produces a false negative test result. - // Because we know Firefox is able to focus object elements referencing SVGs, we simply cheat by sniffing the user agent string - return true - } - - return _document.activeElement === element - }, -} - -// Every Environment except IE9 considers SWF objects focusable -var result$1 = !platform.is.IE9 - -function focusObjectSwf() { - return result$1 -} - -var focusRedirectImgUsemap = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = - '' + - '' - - // focus the , not the
- return element.querySelector('img') - }, - validate: function validate(element, focusTarget, _document) { - var target = element.querySelector('area') - return _document.activeElement === target - }, -} - -// see https://jsbin.com/nenirisage/edit?html,js,console,output - -var focusRedirectLegend = { - element: 'fieldset', - mutate: function mutate(element) { - element.innerHTML = - 'legend' - // take care of focus in validate(); - return false - }, - validate: function validate(element, focusTarget, _document) { - var focusable = element.querySelector('input[tabindex="-1"]') - var tabbable = element.querySelector('input[tabindex="0"]') - - // Firefox requires this test to focus the
first, while this is not necessary in - // https://jsbin.com/nenirisage/edit?html,js,console,output - element.focus() - - element.querySelector('legend').focus() - return ( - (_document.activeElement === focusable && 'focusable') || - (_document.activeElement === tabbable && 'tabbable') || - '' - ) - }, -} - -// https://github.com/medialize/ally.js/issues/21 -var focusScrollBody = { - element: 'div', - mutate: function mutate(element) { - element.setAttribute('style', 'width: 100px; height: 50px; overflow: auto;') - element.innerHTML = - '
scrollable content
' - return element.querySelector('div') - }, -} - -// https://github.com/medialize/ally.js/issues/21 -var focusScrollContainerWithoutOverflow = { - element: 'div', - mutate: function mutate(element) { - element.setAttribute('style', 'width: 100px; height: 50px;') - element.innerHTML = - '
scrollable content
' - }, -} - -// https://github.com/medialize/ally.js/issues/21 -var focusScrollContainer = { - element: 'div', - mutate: function mutate(element) { - element.setAttribute('style', 'width: 100px; height: 50px; overflow: auto;') - element.innerHTML = - '
scrollable content
' - }, -} - -var focusSummary = { - element: 'details', - mutate: function mutate(element) { - element.innerHTML = 'foo

content

' - return element.firstElementChild - }, -} - -function makeFocusableForeignObject() { - // Constructs - // without raising a Trusted Types violation - var foreignObject = document.createElementNS( - 'http://www.w3.org/2000/svg', - 'foreignObject' - ) - foreignObject.width.baseVal.value = 30 - foreignObject.height.baseVal.value = 30 - foreignObject.appendChild(document.createElement('input')) - foreignObject.lastChild.type = 'text' - - return foreignObject -} - -function focusSvgForeignObjectHack(element) { - // Edge13, Edge14: foreignObject focus hack - // https://jsbin.com/kunehinugi/edit?html,js,output - // https://jsbin.com/fajagi/3/edit?html,js,output - var isSvgElement = - element.ownerSVGElement || element.nodeName.toLowerCase() === 'svg' - if (!isSvgElement) { - return false - } - - // inject and focus an element into the SVG element to receive focus - var foreignObject = makeFocusableForeignObject() - element.appendChild(foreignObject) - var input = foreignObject.querySelector('input') - input.focus() - - // upon disabling the activeElement, IE and Edge - // will not shift focus to like all the other - // browsers, but instead find the first focusable - // ancestor and shift focus to that - input.disabled = true - - // clean up - element.removeChild(foreignObject) - return true -} - -function generate(element) { - return ( - '' + - element + - '' - ) -} - -function focus(element) { - if (element.focus) { - return - } - - try { - HTMLElement.prototype.focus.call(element) - } catch (e) { - focusSvgForeignObjectHack(element) - } -} - -function validate(element, focusTarget, _document) { - focus(focusTarget) - return _document.activeElement === focusTarget -} - -var focusSvgFocusableAttribute = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = generate('a') - return element.querySelector('text') - }, - validate: validate, -} - -var focusSvgTabindexAttribute = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = generate('a') - return element.querySelector('text') - }, - validate: validate, -} - -var focusSvgNegativeTabindexAttribute = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = generate('a') - return element.querySelector('text') - }, - validate: validate, -} - -var focusSvgUseTabindex = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = generate( - [ - 'link', - '', - ].join('') - ) - - return element.querySelector('use') - }, - validate: validate, -} - -var focusSvgForeignobjectTabindex = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = generate( - '' - ) - // Safari 8's querySelector() can't identify foreignObject, but getElementsByTagName() can - return ( - element.querySelector('foreignObject') || - element.getElementsByTagName('foreignObject')[0] - ) - }, - validate: validate, -} - -// Firefox seems to be handling the SVG-document-in-iframe creation asynchronously -// and thereby produces a false negative test result. Thus the test is pointless -// and we resort to UA sniffing once again. -// see http://jsbin.com/vunadohoko/1/edit?js,console,output - -var result$2 = Boolean( - platform.is.GECKO && - typeof SVGElement !== 'undefined' && - SVGElement.prototype.focus -) - -function focusSvgInIframe() { - return result$2 -} - -var focusSvg = { - element: 'div', - mutate: function mutate(element) { - element.innerHTML = generate('') - return element.firstChild - }, - validate: validate, -} - -// Firefox allows *any* value and treats invalid values like tabindex="-1" -// @browser-issue Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054 -var focusTabindexTrailingCharacters = { - element: 'div', - mutate: function mutate(element) { - element.setAttribute('tabindex', '3x') - }, -} - -var focusTable = { - element: 'table', - mutate: function mutate(element, wrapper, _document) { - // IE9 has a problem replacing TBODY contents with innerHTML. - // https://stackoverflow.com/a/8097055/515124 - // element.innerHTML = 'cell'; - var fragment = _document.createDocumentFragment() - fragment.innerHTML = 'cell' - element.appendChild(fragment) - }, -} - -var focusVideoWithoutControls = { - element: 'video', - mutate: function mutate(element) { - try { - // invalid media file can trigger warning in console, data-uri to prevent HTTP request - element.setAttribute('src', gif) - } catch (e) { - // IE9 may throw "Error: Not implemented" - } - }, -} - -// https://jsbin.com/vafaba/3/edit?html,js,console,output -var result$3 = platform.is.GECKO || platform.is.TRIDENT || platform.is.EDGE - -function tabsequenceAreaAtImgPosition() { - return result$3 -} - -var testCallbacks = { - cssShadowPiercingDeepCombinator: cssShadowPiercingDeepCombinator, - focusInZeroDimensionObject: focusInZeroDimensionObject, - focusObjectSwf: focusObjectSwf, - focusSvgInIframe: focusSvgInIframe, - tabsequenceAreaAtImgPosition: tabsequenceAreaAtImgPosition, -} - -var testDescriptions = { - focusAreaImgTabindex: focusAreaImgTabindex, - focusAreaTabindex: focusAreaTabindex, - focusAreaWithoutHref: focusAreaWithoutHref, - focusAudioWithoutControls: focusAudioWithoutControls, - focusBrokenImageMap: focusBrokenImageMap, - focusChildrenOfFocusableFlexbox: focusChildrenOfFocusableFlexbox, - focusFieldsetDisabled: focusFieldsetDisabled, - focusFieldset: focusFieldset, - focusFlexboxContainer: focusFlexboxContainer, - focusFormDisabled: focusFormDisabled, - focusImgIsmap: focusImgIsmap, - focusImgUsemapTabindex: focusImgUsemapTabindex, - focusInHiddenIframe: focusInHiddenIframe, - focusInvalidTabindex: focusInvalidTabindex, - focusLabelTabindex: focusLabelTabindex, - focusObjectSvg: focusObjectSvg, - focusObjectSvgHidden: focusObjectSvgHidden, - focusRedirectImgUsemap: focusRedirectImgUsemap, - focusRedirectLegend: focusRedirectLegend, - focusScrollBody: focusScrollBody, - focusScrollContainerWithoutOverflow: focusScrollContainerWithoutOverflow, - focusScrollContainer: focusScrollContainer, - focusSummary: focusSummary, - focusSvgFocusableAttribute: focusSvgFocusableAttribute, - focusSvgTabindexAttribute: focusSvgTabindexAttribute, - focusSvgNegativeTabindexAttribute: focusSvgNegativeTabindexAttribute, - focusSvgUseTabindex: focusSvgUseTabindex, - focusSvgForeignobjectTabindex: focusSvgForeignobjectTabindex, - focusSvg: focusSvg, - focusTabindexTrailingCharacters: focusTabindexTrailingCharacters, - focusTable: focusTable, - focusVideoWithoutControls: focusVideoWithoutControls, -} - -function executeTests() { - var results = detectFocus(testDescriptions) - Object.keys(testCallbacks).forEach(function (key) { - results[key] = testCallbacks[key]() - }) - - return results -} - -var supportsCache = null - -function _supports() { - if (supportsCache) { - return supportsCache - } - - supportsCache = cache$1.get() - if (!supportsCache.time) { - cache$1.set(executeTests()) - supportsCache = cache$1.get() - } - - return supportsCache -} - -var supports = void 0 - -// https://www.w3.org/TR/html5/infrastructure.html#rules-for-parsing-integers -// NOTE: all browsers agree to allow trailing spaces as well -var validIntegerPatternNoTrailing = /^\s*(-|\+)?[0-9]+\s*$/ -var validIntegerPatternWithTrailing = /^\s*(-|\+)?[0-9]+.*$/ - -function isValidTabindex(context) { - if (!supports) { - supports = _supports() - } - - var validIntegerPattern = supports.focusTabindexTrailingCharacters - ? validIntegerPatternWithTrailing - : validIntegerPatternNoTrailing - - var element = contextToElement({ - label: 'is/valid-tabindex', - resolveDocument: true, - context: context, - }) - - // Edge 14 has a capitalization problem on SVG elements, - // see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/9282058/ - var hasTabindex = element.hasAttribute('tabindex') - var hasTabIndex = element.hasAttribute('tabIndex') - - if (!hasTabindex && !hasTabIndex) { - return false - } - - // older Firefox and Internet Explorer don't support tabindex on SVG elements - var isSvgElement = - element.ownerSVGElement || element.nodeName.toLowerCase() === 'svg' - if (isSvgElement && !supports.focusSvgTabindexAttribute) { - return false - } - - // @browser-issue Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054 - if (supports.focusInvalidTabindex) { - return true - } - - // an element matches the tabindex selector even if its value is invalid - var tabindex = element.getAttribute(hasTabindex ? 'tabindex' : 'tabIndex') - // IE11 parses tabindex="" as the value "-32768" - // @browser-issue Trident https://connect.microsoft.com/IE/feedback/details/1072965 - if (tabindex === '-32768') { - return false - } - - return Boolean(tabindex && validIntegerPattern.test(tabindex)) -} - -function tabindexValue(element) { - if (!isValidTabindex(element)) { - return null - } - - // Edge 14 has a capitalization problem on SVG elements, - // see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/9282058/ - var hasTabindex = element.hasAttribute('tabindex') - var attributeName = hasTabindex ? 'tabindex' : 'tabIndex' - - // @browser-issue Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054 - var tabindex = parseInt(element.getAttribute(attributeName), 10) - return isNaN(tabindex) ? -1 : tabindex -} - -// this is a shared utility file for focus-relevant.js and tabbable.js -// separate testing of this file's functions is not necessary, -// as they're implicitly tested by way of the consumers - -function isUserModifyWritable(style) { - // https://www.w3.org/TR/1999/WD-css3-userint-19990916#user-modify - // https://github.com/medialize/ally.js/issues/17 - var userModify = style.webkitUserModify || '' - return Boolean(userModify && userModify.indexOf('write') !== -1) -} - -function hasCssOverflowScroll(style) { - return [ - style.getPropertyValue('overflow'), - style.getPropertyValue('overflow-x'), - style.getPropertyValue('overflow-y'), - ].some(function (overflow) { - return overflow === 'auto' || overflow === 'scroll' - }) -} - -function hasCssDisplayFlex(style) { - return style.display.indexOf('flex') > -1 -} - -function isScrollableContainer(element, nodeName, parentNodeName, parentStyle) { - if (nodeName !== 'div' && nodeName !== 'span') { - // Internet Explorer advances scrollable containers and bodies to focusable - // only if the scrollable container is
or - this does *not* - // happen for
,
, … - return false - } - - if ( - parentNodeName && - parentNodeName !== 'div' && - parentNodeName !== 'span' && - !hasCssOverflowScroll(parentStyle) - ) { - return false - } - - return ( - element.offsetHeight < element.scrollHeight || - element.offsetWidth < element.scrollWidth - ) -} - -var supports$1 = void 0 - -function isFocusRelevantRules() { - var _ref = - arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - context = _ref.context, - _ref$except = _ref.except, - except = - _ref$except === undefined - ? { - flexbox: false, - scrollable: false, - shadow: false, - } - : _ref$except - - if (!supports$1) { - supports$1 = _supports() - } - - var element = contextToElement({ - label: 'is/focus-relevant', - resolveDocument: true, - context: context, - }) - - if (!except.shadow && element.shadowRoot) { - // a ShadowDOM host receives focus when the focus moves to its content - return true - } - - var nodeName = element.nodeName.toLowerCase() - - if (nodeName === 'input' && element.type === 'hidden') { - // input[type="hidden"] supports.cannot be focused - return false - } - - if ( - nodeName === 'input' || - nodeName === 'select' || - nodeName === 'button' || - nodeName === 'textarea' - ) { - return true - } - - if (nodeName === 'legend' && supports$1.focusRedirectLegend) { - // specifics filtered in is/focusable - return true - } - - if (nodeName === 'label') { - // specifics filtered in is/focusable - return true - } - - if (nodeName === 'area') { - // specifics filtered in is/focusable - return true - } - - if (nodeName === 'a' && element.hasAttribute('href')) { - return true - } - - if (nodeName === 'object' && element.hasAttribute('usemap')) { - // object[usemap] is not focusable in any browser - return false - } - - if (nodeName === 'object') { - var svgType = element.getAttribute('type') - if (!supports$1.focusObjectSvg && svgType === 'image/svg+xml') { - // object[type="image/svg+xml"] is not focusable in Internet Explorer - return false - } else if ( - !supports$1.focusObjectSwf && - svgType === 'application/x-shockwave-flash' - ) { - // object[type="application/x-shockwave-flash"] is not focusable in Internet Explorer 9 - return false - } - } - - if (nodeName === 'iframe' || nodeName === 'object') { - // browsing context containers - return true - } - - if (nodeName === 'embed' || nodeName === 'keygen') { - // embed is considered focus-relevant but not focusable - // see https://github.com/medialize/ally.js/issues/82 - return true - } - - if (element.hasAttribute('contenteditable')) { - // also see CSS property user-modify below - return true - } - - if ( - nodeName === 'audio' && - (supports$1.focusAudioWithoutControls || element.hasAttribute('controls')) - ) { - return true - } - - if ( - nodeName === 'video' && - (supports$1.focusVideoWithoutControls || element.hasAttribute('controls')) - ) { - return true - } - - if (supports$1.focusSummary && nodeName === 'summary') { - return true - } - - var validTabindex = isValidTabindex(element) - - if (nodeName === 'img' && element.hasAttribute('usemap')) { - // Gecko, Trident and Edge do not allow an image with an image map and tabindex to be focused, - // it appears the tabindex is overruled so focus is still forwarded to the - return ( - (validTabindex && supports$1.focusImgUsemapTabindex) || - supports$1.focusRedirectImgUsemap - ) - } - - if (supports$1.focusTable && (nodeName === 'table' || nodeName === 'td')) { - // IE10-11 supports.can focus and
- return true - } - - if (supports$1.focusFieldset && nodeName === 'fieldset') { - // IE10-11 supports.can focus
- return true - } - - var isSvgElement = nodeName === 'svg' - var isSvgContent = element.ownerSVGElement - var focusableAttribute = element.getAttribute('focusable') - var tabindex = tabindexValue(element) - - if ( - nodeName === 'use' && - tabindex !== null && - !supports$1.focusSvgUseTabindex - ) { - // cannot be made focusable by adding a tabindex attribute anywhere but Blink and WebKit - return false - } - - if (nodeName === 'foreignobject') { - // can only be made focusable in Blink and WebKit - return tabindex !== null && supports$1.focusSvgForeignobjectTabindex - } - - if (elementMatches(element, 'svg a') && element.hasAttribute('xlink:href')) { - return true - } - - if ( - (isSvgElement || isSvgContent) && - element.focus && - !supports$1.focusSvgNegativeTabindexAttribute && - tabindex < 0 - ) { - // Firefox 51 and 52 treat any natively tabbable SVG element with - // tabindex="-1" as tabbable and everything else as inert - // see https://bugzilla.mozilla.org/show_bug.cgi?id=1302340 - return false - } - - if (isSvgElement) { - return ( - validTabindex || - supports$1.focusSvg || - supports$1.focusSvgInIframe || - // Internet Explorer understands the focusable attribute introduced in SVG Tiny 1.2 - Boolean( - supports$1.focusSvgFocusableAttribute && - focusableAttribute && - focusableAttribute === 'true' - ) - ) - } - - if (isSvgContent) { - if (supports$1.focusSvgTabindexAttribute && validTabindex) { - return true - } - - if (supports$1.focusSvgFocusableAttribute) { - // Internet Explorer understands the focusable attribute introduced in SVG Tiny 1.2 - return focusableAttribute === 'true' - } - } - - // https://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute - if (validTabindex) { - return true - } - - var style = window.getComputedStyle(element, null) - if (isUserModifyWritable(style)) { - return true - } - - if ( - supports$1.focusImgIsmap && - nodeName === 'img' && - element.hasAttribute('ismap') - ) { - // IE10-11 considers the in focusable - // https://github.com/medialize/ally.js/issues/20 - var hasLinkParent = getParents({ context: element }).some( - function (parent) { - return ( - parent.nodeName.toLowerCase() === 'a' && parent.hasAttribute('href') - ) - } - ) - - if (hasLinkParent) { - return true - } - } - - // https://github.com/medialize/ally.js/issues/21 - if (!except.scrollable && supports$1.focusScrollContainer) { - if (supports$1.focusScrollContainerWithoutOverflow) { - // Internet Explorer does will consider the scrollable area focusable - // if the element is a
or a and it is in fact scrollable, - // regardless of the CSS overflow property - if (isScrollableContainer(element, nodeName)) { - return true - } - } else if (hasCssOverflowScroll(style)) { - // Firefox requires proper overflow setting, IE does not necessarily - // https://developer.mozilla.org/docs/Web/CSS/overflow - return true - } - } - - if ( - !except.flexbox && - supports$1.focusFlexboxContainer && - hasCssDisplayFlex(style) - ) { - // elements with display:flex are focusable in IE10-11 - return true - } - - var parent = element.parentElement - if (!except.scrollable && parent) { - var parentNodeName = parent.nodeName.toLowerCase() - var parentStyle = window.getComputedStyle(parent, null) - if ( - supports$1.focusScrollBody && - isScrollableContainer(parent, nodeName, parentNodeName, parentStyle) - ) { - // scrollable bodies are focusable Internet Explorer - // https://github.com/medialize/ally.js/issues/21 - return true - } - - // Children of focusable elements with display:flex are focusable in IE10-11 - if (supports$1.focusChildrenOfFocusableFlexbox) { - if (hasCssDisplayFlex(parentStyle)) { - return true - } - } - } - - // NOTE: elements marked as inert are not focusable, - // but that property is not exposed to the DOM - // https://www.w3.org/TR/html5/editing.html#inert - - return false -} - -// bind exceptions to an iterator callback -isFocusRelevantRules.except = function () { - var except = - arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {} - - var isFocusRelevant = function isFocusRelevant(context) { - return isFocusRelevantRules({ - context: context, - except: except, - }) - } - - isFocusRelevant.rules = isFocusRelevantRules - return isFocusRelevant -} - -// provide isFocusRelevant(context) as default iterator callback -var isFocusRelevant = isFocusRelevantRules.except({}) - -function findIndex(array, callback) { - // attempt to use native or polyfilled Array#findIndex first - if (array.findIndex) { - return array.findIndex(callback) - } - - var length = array.length - - // shortcut if the array is empty - if (length === 0) { - return -1 - } - - // otherwise loop over array - for (var i = 0; i < length; i++) { - if (callback(array[i], i, array)) { - return i - } - } - - return -1 -} - -function getContentDocument(node) { - try { - // works on and