diff --git a/packages/ui-overlays/package.json b/packages/ui-overlays/package.json
index 923c140e54..1d6fc42a45 100644
--- a/packages/ui-overlays/package.json
+++ b/packages/ui-overlays/package.json
@@ -80,11 +80,11 @@
"default": "./es/exports/a.js"
},
"./v11_7": {
- "src": "./src/exports/a.ts",
- "types": "./types/exports/a.d.ts",
- "import": "./es/exports/a.js",
- "require": "./lib/exports/a.js",
- "default": "./es/exports/a.js"
+ "src": "./src/exports/b.ts",
+ "types": "./types/exports/b.d.ts",
+ "import": "./es/exports/b.js",
+ "require": "./lib/exports/b.js",
+ "default": "./es/exports/b.js"
},
"./latest": {
"src": "./src/exports/a.ts",
diff --git a/packages/ui-overlays/src/Mask/v2/MaskCounter.ts b/packages/ui-overlays/src/Mask/v2/MaskCounter.ts
new file mode 100644
index 0000000000..5ea1525349
--- /dev/null
+++ b/packages/ui-overlays/src/Mask/v2/MaskCounter.ts
@@ -0,0 +1,47 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - present Instructure, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+const MaskCounter = (() => {
+ let counter = 0
+ const getCounter = () => counter
+ const setCounter = (value: number) => {
+ counter = value
+ }
+ const incrementCounter = () => {
+ setCounter(getCounter() + 1)
+ }
+
+ const decrementCounter = () => {
+ setCounter(getCounter() - 1)
+ }
+
+ return {
+ getCounter,
+ setCounter,
+ incrementCounter,
+ decrementCounter
+ }
+})()
+
+export default MaskCounter
diff --git a/packages/ui-overlays/src/Mask/v2/README.md b/packages/ui-overlays/src/Mask/v2/README.md
new file mode 100644
index 0000000000..8b1d4fb9f5
--- /dev/null
+++ b/packages/ui-overlays/src/Mask/v2/README.md
@@ -0,0 +1,56 @@
+---
+describes: Mask
+---
+
+A Mask component covers its closest positioned parent (either absolute or relative).
+
+```js
+---
+type: example
+---
+
+ Some content that is masked
+
+
+```
+
+The Mask component can be configured to cover the full screen if it is rendered inside a [Portal](Portal).
+
+```js
+---
+type: example
+---
+const Example = () => {
+ const [open, setOpen] = useState(false)
+
+ const handleButtonClick = () => {
+ setOpen(!open)
+ }
+
+ return (
+
+
+
+ {
+ setOpen(false)
+ }}
+ >
+ Click anywhere around this text to close the Mask
+
+
+
+ )
+}
+
+render()
+```
diff --git a/packages/ui-overlays/src/Mask/v1/__tests__/Mask.test.tsx b/packages/ui-overlays/src/Mask/v2/__tests__/Mask.test.tsx
similarity index 100%
rename from packages/ui-overlays/src/Mask/v1/__tests__/Mask.test.tsx
rename to packages/ui-overlays/src/Mask/v2/__tests__/Mask.test.tsx
diff --git a/packages/ui-overlays/src/Mask/v2/index.tsx b/packages/ui-overlays/src/Mask/v2/index.tsx
new file mode 100644
index 0000000000..6b0039295f
--- /dev/null
+++ b/packages/ui-overlays/src/Mask/v2/index.tsx
@@ -0,0 +1,119 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - present Instructure, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import { Component } from 'react'
+import noScroll from 'no-scroll'
+
+import { withStyle } from '@instructure/emotion'
+import type { ComponentStyle } from '@instructure/emotion'
+import { ensureSingleChild, omitProps } from '@instructure/ui-react-utils'
+
+import generateStyle from './styles'
+
+import type { MaskProps } from './props'
+import { allowedProps } from './props'
+import MaskCounter from './MaskCounter'
+
+/**
+---
+category: components/utilities
+---
+**/
+@withStyle(generateStyle)
+class Mask extends Component {
+ static readonly componentId = 'Mask'
+
+ static allowedProps = allowedProps
+
+ static defaultProps = {
+ placement: 'center',
+ fullscreen: false
+ }
+
+ componentDidMount() {
+ this.props.makeStyles?.()
+
+ if (this.props.fullscreen) {
+ noScroll.on()
+ MaskCounter.incrementCounter()
+ }
+ }
+
+ componentDidUpdate() {
+ this.props.makeStyles?.()
+ }
+
+ componentWillUnmount() {
+ if (this.props.fullscreen) {
+ MaskCounter.decrementCounter()
+ if (MaskCounter.getCounter() <= 0) {
+ noScroll.off()
+ }
+ }
+ }
+
+ ref: Element | null = null
+
+ handleElementRef = (el: Element | null) => {
+ const { elementRef } = this.props
+
+ this.ref = el
+
+ if (typeof elementRef === 'function') {
+ elementRef(el)
+ }
+ }
+
+ // It can be a ref for any type of child
+ _content: any
+
+ contentRef: React.LegacyRef = (el) => {
+ this._content = el
+ }
+
+ render() {
+ const content = ensureSingleChild(this.props.children, {
+ ref: this.contentRef
+ })
+
+ const props: React.ClassAttributes &
+ React.HTMLAttributes & {
+ css?: ComponentStyle<'mask'>['mask']
+ } = {
+ ...omitProps(this.props, Mask.allowedProps),
+ css: this.props.styles?.mask,
+ ref: this.handleElementRef
+ }
+
+ if (typeof this.props.onClick === 'function') {
+ props.onClick = this.props.onClick
+ props.tabIndex = -1
+ }
+
+ return {content}
+ }
+}
+
+export default Mask
+export { Mask }
diff --git a/packages/ui-overlays/src/Mask/v2/props.ts b/packages/ui-overlays/src/Mask/v2/props.ts
new file mode 100644
index 0000000000..e4830fccca
--- /dev/null
+++ b/packages/ui-overlays/src/Mask/v2/props.ts
@@ -0,0 +1,58 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - present Instructure, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import type { MaskTheme, OtherHTMLAttributes } from '@instructure/shared-types'
+import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
+
+type MaskOwnProps = {
+ children?: React.ReactNode
+ placement?: 'top' | 'center' | 'bottom' | 'stretch'
+ fullscreen?: boolean
+ onClick?: (event: React.MouseEvent) => void
+ /**
+ * provides a reference to the underlying html root element
+ */
+ elementRef?: (element: Element | null) => void
+}
+
+type PropKeys = keyof MaskOwnProps
+
+type AllowedPropKeys = Readonly>
+
+type MaskProps = MaskOwnProps &
+ WithStyleProps &
+ OtherHTMLAttributes
+
+type MaskStyle = ComponentStyle<'mask'>
+const allowedProps: AllowedPropKeys = [
+ 'placement',
+ 'fullscreen',
+ 'children',
+ 'onClick',
+ 'elementRef'
+]
+
+export type { MaskProps, MaskStyle }
+export { allowedProps }
diff --git a/packages/ui-overlays/src/Mask/v2/styles.ts b/packages/ui-overlays/src/Mask/v2/styles.ts
new file mode 100644
index 0000000000..3af10ebd1e
--- /dev/null
+++ b/packages/ui-overlays/src/Mask/v2/styles.ts
@@ -0,0 +1,76 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - present Instructure, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import type { NewComponentTypes } from '@instructure/ui-themes'
+import type { MaskProps, MaskStyle } from './props'
+
+/**
+ * ---
+ * private: true
+ * ---
+ * Generates the style object from the theme and provided additional information
+ * @param {Object} componentTheme The theme variable object.
+ * @param {Object} props the props of the component, the style is applied to
+ * @param {Object} sharedTokens Shared token object that stores common values for the theme.
+ * @param {Object} state the state of the component, the style is applied to
+ * @return {Object} The final style object, which will be used in the component
+ */
+const generateStyle = (
+ componentTheme: NewComponentTypes['Mask'],
+ props: MaskProps
+): MaskStyle => {
+ const { placement, fullscreen } = props
+
+ const positionStyles = fullscreen
+ ? { position: 'fixed' }
+ : { position: 'absolute' }
+
+ const placementStyles = {
+ top: { alignItems: 'flex-start' },
+ center: { alignItems: 'center' },
+ bottom: { alignItems: 'flex-end' },
+ stretch: { alignItems: 'stretch' }
+ }
+
+ return {
+ mask: {
+ label: 'mask',
+ boxSizing: 'border-box',
+ background: componentTheme.backgroundColor,
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ overflow: 'auto',
+ display: 'flex',
+ justifyContent: 'center',
+ outline: 'none',
+ zIndex: 9999,
+ ...positionStyles,
+ ...placementStyles[placement!]
+ }
+ }
+}
+
+export default generateStyle
diff --git a/packages/ui-overlays/src/exports/b.ts b/packages/ui-overlays/src/exports/b.ts
new file mode 100644
index 0000000000..ae3b00c193
--- /dev/null
+++ b/packages/ui-overlays/src/exports/b.ts
@@ -0,0 +1,28 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - present Instructure, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+export { Mask } from '../Mask/v2'
+export { Overlay } from '../Overlay/v1'
+
+export type { MaskProps } from '../Mask/v2/props'
+export type { OverlayProps } from '../Overlay/v1/props'