Make RCE StatusBar behave like a toolbar

closes CORE-2903

test plan:
  - load a page with the rce
  - TAB into the RCE and into the StatusBar
  > expect right/left arrows to move focus from one button to
    the next.
  > expect focus to cycle back to the other
    end when you go too far
  - tab out of the status bar
  - click one of the buttons to give it focus
  - use the arrow keys again
  > expect focus to move right|left from the starting point
  - give he drag handle focus
  > expect up/down arrows to resize the RCE w/o scrolling the page
  - fire up a screenreader
  > expect the button area of the status bar to be announced as a
    toolbar

Change-Id: I00e5a761ebc25ae784267c57bb5a653b68ccacba
Reviewed-on: https://gerrit.instructure.com/197059
Tested-by: Jenkins
Reviewed-by: Jon Willesen <jonw+gerrit@instructure.com>
QA-Review: Jon Willesen <jonw+gerrit@instructure.com>
Product-Review: Ed Schiebel <eschiebel@instructure.com>
This commit is contained in:
Ed Schiebel 2019-06-10 10:54:31 -04:00
parent 46c18d059f
commit a690a93c6d
8 changed files with 475 additions and 98 deletions

View File

@ -111,7 +111,7 @@
"@instructure/ui-elements": "6",
"@instructure/ui-forms": "6",
"@instructure/ui-icons": "6",
"@instructure/ui-layout": "6",
"@instructure/ui-layout": "6.3.1-rc.1+2dd401cc",
"@instructure/ui-overlays": "6",
"@instructure/ui-react-utils": "6",
"@instructure/ui-svg-images": "6",

View File

@ -17,35 +17,69 @@
*/
import React, {useState} from 'react'
import {func} from 'prop-types'
import {func, string} from 'prop-types'
import {DraggableCore} from 'react-draggable'
import keycode from 'keycode'
import {Focusable} from '@instructure/ui-focusable'
import {View} from '@instructure/ui-layout'
import IconDragHandle from '@instructure/ui-icons/lib/Line/IconDragHandle'
import DraggingBlocker from './DraggingBlocker'
import formatMessage from '../format-message'
const RESIZE_STEP = 16
export default function ResizeHandle(props) {
function handleKey(event) {
if (event.keyCode === keycode.codes.up) {
event.preventDefault()
event.stopPropagation()
props.onDrag(event, {deltaY: -RESIZE_STEP})
} else if(event.keyCode === keycode.codes.down) {
event.preventDefault()
event.stopPropagation()
props.onDrag(event, {deltaY: RESIZE_STEP})
}
}
const [dragging, setDragging] = useState(false)
return (
<>
<DraggableCore
offsetParent={document.body}
onDrag={props.onDrag}
onStart={() => setDragging(true)}
onStop={() => setDragging(false)}
>
<View cursor="ns-resize">
<IconDragHandle />
<Focusable>
{({focused}) => (
<View
aria-label={formatMessage("Drag handle. Use up and down arrows to resize")}
as="span"
borderRadius="medium"
display="inline-block"
focused={focused}
padding="0 0 0 xx-small"
position="relative"
role="button"
tabIndex={props.tabIndex}
onKeyDown={handleKey}
>
<DraggableCore
offsetParent={document.body}
onDrag={props.onDrag}
onStart={() => setDragging(true)}
onStop={() => setDragging(false)}
>
<View cursor="ns-resize">
<IconDragHandle />
</View>
</DraggableCore>
<DraggingBlocker dragging={dragging} />
</View>
</DraggableCore>
<DraggingBlocker dragging={dragging} />
</>
)}
</Focusable>
)
}
ResizeHandle.propTypes = {
onDrag: func
onDrag: func,
tabIndex: string
}
ResizeHandle.defaultProps = {
onDrag: () => {}
onDrag: () => {},
tabIndex: '-1'
}

View File

@ -16,13 +16,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import React, {useRef, useState} from 'react'
import {arrayOf, bool, func, number, string} from 'prop-types'
import {StyleSheet, css} from 'aphrodite'
import {Button} from '@instructure/ui-buttons'
import {Flex, View} from '@instructure/ui-layout'
import {ScreenReaderContent} from '@instructure/ui-a11y'
import {Text} from '@instructure/ui-elements'
import keycode from 'keycode'
import { Button } from '@instructure/ui-buttons'
import { Flex, View } from '@instructure/ui-layout'
import {findFocusable} from '@instructure/ui-a11y'
import { ScreenReaderContent } from '@instructure/ui-a11y'
import { Text } from '@instructure/ui-elements'
import {SVGIcon} from '@instructure/ui-svg-images'
import {IconA11yLine, IconKeyboardShortcutsLine, IconMiniArrowEndLine} from '@instructure/ui-icons'
import formatMessage from '../format-message'
@ -36,7 +38,7 @@ StatusBar.propTypes = {
onResize: func // react-draggable onDrag handler.
}
function renderPath({path}) {
function renderPathString({path}) {
return path.reduce((result, pathName, index) => {
return result.concat(
<span key={`${pathName}-${index}`}>
@ -62,36 +64,53 @@ function emptyTagIcon() {
}
export default function StatusBar(props) {
function handleKey(event) {
const buttons = findFocusable(statusBarRef.current)
if (event.keyCode === keycode.codes.right) {
buttons[(focusedIndex + 1) % buttons.length].focus()
} else if(event.keyCode === keycode.codes.left) {
buttons[(focusedIndex + buttons.length - 1) % buttons.length].focus()
}
}
function handleFocus(event) {
const buttons = findFocusable(statusBarRef.current)
const fidx = buttons.findIndex(b => b === event.target)
setFocusedIndex(fidx)
}
function tabIndexForPosition(itemIndex) {
return focusedIndex === itemIndex ? '0' : '-1'
}
const [focusedIndex, setFocusedIndex] = useState(0)
const statusBarRef = useRef(null);
/* eslint-disable react/prop-types */
function renderPathFlexItem() {
function renderPath() {
if (props.isHtmlView) return null
return (
<Flex.Item grow>
<View data-testid="whole-status-bar-path">{renderPath(props)}</View>
</Flex.Item>
<View data-testid="whole-status-bar-path">{renderPathString(props)}</View>
)
}
function renderIconButtonFlexItem() {
function renderIconButtons() {
if (props.isHtmlView) return null
const kbshortcut = formatMessage('View keyboard shortcuts')
const a11y = formatMessage('Accessibility Checker')
return (
<Flex.Item>
<View display="inline-block" padding="0 x-small">
<Button variant="link" icon={IconKeyboardShortcutsLine} title={kbshortcut}>
<ScreenReaderContent>{kbshortcut}</ScreenReaderContent>
</Button>
<Button variant="link" icon={IconA11yLine} title={a11y}>
<ScreenReaderContent>{a11y}</ScreenReaderContent>
</Button>
</View>
<div className={css(styles.separator)} />
</Flex.Item>
<View display="inline-block" padding="0 x-small">
<Button variant="link" icon={IconKeyboardShortcutsLine} title={kbshortcut} tabIndex={tabIndexForPosition(0)}>
<ScreenReaderContent>{kbshortcut}</ScreenReaderContent>
</Button>
<Button variant="link" icon={IconA11yLine} title={a11y} tabIndex={tabIndexForPosition(1)}>
<ScreenReaderContent>{a11y}</ScreenReaderContent>
</Button>
</View>
)
}
function renderWordCountFlexItem() {
function renderWordCount() {
if (props.isHtmlView) return null
const wordCount = formatMessage(
`{count, plural,
@ -102,56 +121,65 @@ export default function StatusBar(props) {
{count: props.wordCount}
)
return (
<Flex.Item>
<View
display="inline-block"
padding="0 small xx-small small"
data-testid="status-bar-word-count"
>
<Text>{wordCount}</Text>
</View>
<div className={css(styles.separator)} />
</Flex.Item>
<View
display="inline-block"
padding="0 small"
data-testid="status-bar-word-count"
>
<Text>{wordCount}</Text>
</View>
)
}
function renderToggleHtmlFlexItem() {
function renderToggleHtml() {
const toggleToHtml = formatMessage('Switch to raw html editor')
const toggleToRich = formatMessage('Switch to rich text editor')
const toggleText = props.isHtmlView ? toggleToRich : toggleToHtml
return (
<Flex.Item>
<View display="inline-block" padding="0 0 0 small">
<Button
variant="link"
icon={emptyTagIcon()}
onClick={props.onToggleHtml}
title={toggleText}
>
<ScreenReaderContent>{toggleText}</ScreenReaderContent>
</Button>
</View>
</Flex.Item>
<View display="inline-block" padding="0 0 0 x-small">
<Button
variant="link"
icon={emptyTagIcon()}
onClick={props.onToggleHtml}
title={toggleText}
tabIndex={tabIndexForPosition(2)}
>
<ScreenReaderContent>{toggleText}</ScreenReaderContent>
</Button>
</View>
)
}
function renderResizeHandleFlexItem() {
function renderResizeHandle() {
return (
<Flex.Item>
<ResizeHandle onDrag={props.onResize} />
</Flex.Item>
<ResizeHandle onDrag={props.onResize} tabIndex={tabIndexForPosition(3)} />
)
}
/* eslint-enable react/prop-types */
const flexJustify = props.isHtmlView ? 'end' : 'start'
return (
<Flex margin="x-small 0 x-small x-small" data-testid="RCEStatusBar" justifyItems={flexJustify}>
{renderPathFlexItem()}
{renderIconButtonFlexItem()}
{renderWordCountFlexItem()}
{renderToggleHtmlFlexItem()}
{renderResizeHandleFlexItem()}
<Flex
margin="x-small 0 x-small x-small"
data-testid="RCEStatusBar"
justifyItems={flexJustify}
ref={statusBarRef}
onKeyDown={handleKey}
onFocus={handleFocus}
role="status"
>
<Flex.Item grow>
{renderPath()}
</Flex.Item>
<Flex.Item role="toolbar">
{renderIconButtons()}
<div className={css(styles.separator)} />
{renderWordCount()}
<div className={css(styles.separator)} />
{renderToggleHtml()}
{renderResizeHandle()}
</Flex.Item>
</Flex>
)
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2019 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import 'jest-dom/extend-expect'
import {render, cleanup, fireEvent} from 'react-testing-library'
import keycode from 'keycode'
import ResizeHandle from '../ResizeHandle'
afterEach(cleanup)
describe('RCE StatusBar', () => {
it('simulates drag using the keyboard', () => {
const onDrag = jest.fn()
const {container} = render(
<ResizeHandle onDrag={onDrag} />
)
const theHandle = container.firstElementChild
theHandle.focus()
fireEvent.keyDown(theHandle, {keyCode: keycode.codes.up})
expect(onDrag).toHaveBeenCalledTimes(1)
fireEvent.keyDown(theHandle, {keyCode: keycode.codes.down})
expect(onDrag).toHaveBeenCalledTimes(2)
})
})

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2019 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import 'jest-dom/extend-expect'
import {render, cleanup, fireEvent} from 'react-testing-library'
import keycode from 'keycode'
import StatusBar from '../StatusBar'
afterEach(cleanup)
function renderStatusBar() {
return render(
<StatusBar
onToggleHtml={() => {}}
path={[]}
wordCount={0}
isHtmlView={false}
onResize={() => {}}
onKBShortcutModalOpen={() => {}}
/>
)
}
describe('RCE StatusBar', () => {
it('cycles focus with right arrow keys', () => {
const {container} = renderStatusBar()
const buttons = container.querySelectorAll('button, *[tabindex]')
expect(buttons.length).toEqual(4)
buttons[0].focus()
expect(document.activeElement === buttons[0])
// wraps to the right
for(let i = 0; i === buttons.length; ++i) {
fireEvent.keyDown(container, {keyCode: keycode.codes.right})
expect(document.activeElement === buttons[i % buttons.length])
}
expect(document.activeElement === buttons[0]) // back to the beginning
})
it('cycles focus with left arrow keys', () => {
const {container} = renderStatusBar()
const buttons = container.querySelectorAll('button, *[tabindex]')
expect(buttons.length).toEqual(4)
buttons[3].focus()
expect(document.activeElement === buttons[3])
// wraps to the left
for(let i = 0; i < buttons.length; ++i) {
fireEvent.keyDown(container, {keyCode: keycode.codes.left})
expect(document.activeElement === buttons[(3 - i + buttons.length) % buttons.length])
}
expect(document.activeElement === buttons[3])
})
})

View File

@ -282,6 +282,7 @@ describe("RCEWrapper", () => {
describe('insertImagePlaceholder', () => {
let globalImage
let contentInsertionStub
function mockImage() {
// jsdom doesn't support Image
// mock enough for RCEWrapper.insertImagePlaceholder
@ -294,10 +295,15 @@ describe("RCEWrapper", () => {
}
}
}
function restoreImage() {
global.Image = globalImage
}
beforeEach(() => {
contentInsertionStub = sinon.stub(contentInsertion, 'insertContent')
})
afterEach(() => {
contentInsertion.insertContent.restore()
})
it('inserts a placeholder image with the proper metadata', () => {
mockImage()
@ -317,10 +323,8 @@ describe("RCEWrapper", () => {
data-placeholder-for="green_square"
style="width: 10px; height: 10px; border: solid 1px #8B969E;"
/>`;
const stub = sinon.stub(contentInsertion, 'insertContent')
instance.insertImagePlaceholder(props)
sinon.assert.calledWith(stub, editor, imageMarkup)
contentInsertion.insertContent.restore()
sinon.assert.calledWith(contentInsertionStub, editor, imageMarkup)
restoreImage()
})
@ -339,10 +343,8 @@ describe("RCEWrapper", () => {
data-placeholder-for="file.txt"
style="width: 8rem; height: 1rem; border: solid 1px #8B969E;"
/>`;
const stub = sinon.stub(contentInsertion, 'insertContent')
instance.insertImagePlaceholder(props)
sinon.assert.calledWith(stub, editor, imageMarkup)
contentInsertion.insertContent.restore()
sinon.assert.calledWith(contentInsertionStub, editor, imageMarkup)
})
})

View File

@ -118,7 +118,6 @@ test('can create a link', async t => {
.typeText(labeledBy('URL'), 'https://instructure.com')
.click(Selector('button').withText('Save'))
.switchToIframe(tinyIframe)
.debug()
.expect(Selector('a').withAttribute('href', 'https://instructure.com').withAttribute('target', '_blank').exists).ok()
})

235
yarn.lock
View File

@ -824,6 +824,18 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
"@emotion/is-prop-valid@^0.7.3":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz#a6bf4fa5387cbba59d44e698a4680f481a8da6cc"
integrity sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==
dependencies:
"@emotion/memoize" "0.7.1"
"@emotion/memoize@0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.1.tgz#e93c13942592cf5ef01aa8297444dc192beee52f"
integrity sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==
"@gulp-sourcemaps/identity-map@1.X":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz#1e6fe5d8027b1f285dc0d31762f566bccd73d5a9"
@ -972,6 +984,15 @@
resolved "https://registry.yarnpkg.com/@instructure/config-loader/-/config-loader-6.2.0.tgz#3157ce21d51f4520302d0d348165b8cce4a6b721"
integrity sha512-gRIp5PMjGYBqwyMsHu7T4Bqyr8SlpWHmMqjyUJGDgo1GIhQHwXBODjaOkbH9W3v566ahd5Kr4HA1JqtFV5iUtQ==
"@instructure/console@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/console/-/console-6.3.1-rc.1.tgz#91a4ebbbf0fa43aa147f47a9e01e8cdb5ff4f150"
integrity sha512-S6hci0wc9tvbC37lSsrITW/9oEcVQbXkAcSdlkQ+AkZYFiIR3WhnTdef+qv1yba3FN2f7p4TMrh/yQJgXUqv5A==
dependencies:
"@babel/helper-annotate-as-pure" "^7.0.0"
"@babel/helper-module-imports" "^7.0.0"
babel-plugin-macros "^2.5.1"
"@instructure/console@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/console/-/console-5.52.3.tgz#b3eba8c535010d57bff18bd5c1d18f1cf779023f"
@ -990,6 +1011,13 @@
"@babel/helper-module-imports" "^7.0.0"
babel-plugin-macros "^2.5.1"
"@instructure/debounce@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/debounce/-/debounce-6.3.1-rc.1.tgz#a882497079d96e3f55fbb13eb9d04a30b2bff37b"
integrity sha512-FNKKDQ8RgyQO1uuROxD+viJO7nEp+vOO6dgedS10L874CnsL9b3SoEmnJvaPuC3aKuF5v7zeDI03SAg72HEYFQ==
dependencies:
"@babel/runtime" "^7"
"@instructure/debounce@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/debounce/-/debounce-5.52.3.tgz#a872473e3a72f51be5cd9016b7044fe5f6b53cbe"
@ -1084,6 +1112,21 @@
keycode "^2"
prop-types "^15"
"@instructure/ui-a11y@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-a11y/-/ui-a11y-6.3.1-rc.1.tgz#44b8997d286f937486c6ba80e406c37bca8565a1"
integrity sha512-G0UwXjeaRyIynk0yICuYkrQIUmAWdDCsS4xrwruXIqxePxKqDUsf/5tJzpFm0ul04G4WKUsdAdI6USQiLn7j8A==
dependencies:
"@babel/runtime" "^7"
"@instructure/console" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-dom-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-react-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-themeable" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/uid" "6.3.1-rc.1+2dd401cc"
keycode "^2"
prop-types "^15"
"@instructure/ui-a11y@^5", "@instructure/ui-a11y@^5.52.0", "@instructure/ui-a11y@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-a11y/-/ui-a11y-5.52.3.tgz#cccc02c0e89dcd3d85e3fdcaf6129a202786ddfe"
@ -1285,6 +1328,14 @@
"@babel/runtime" "^7"
tinycolor2 "^1.4.1"
"@instructure/ui-color-utils@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-color-utils/-/ui-color-utils-6.3.1-rc.1.tgz#f61a0111ce117bc31dc4f92770e8ce6609675055"
integrity sha512-Iy/h4S11vKwHIkKGZIoTmiutYOVJfSVWuxoaNp4GFZdWYdxPwMcXJwDUCPM0SCIUetxy88rCF0/fylmGtSKKfQ==
dependencies:
"@babel/runtime" "^7"
tinycolor2 "^1.4.1"
"@instructure/ui-container@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-container/-/ui-container-5.52.3.tgz#0c60a0c16ada533d20f119673c949094aab9c427"
@ -1329,6 +1380,13 @@
keycode "^2.1.8"
prop-types "^15"
"@instructure/ui-decorator@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-decorator/-/ui-decorator-6.3.1-rc.1.tgz#6780f5f9df3613720a9f77bd83814b2373dfdbe0"
integrity sha512-KN5Piv+iR7IgtVW5QnZ7FsG6RltLpvAcQwq6Y4JP75hYpHD7g0gHwPTur7CHNNjVFrJbWvq31DGaq+oxZwymNg==
dependencies:
"@babel/runtime" "^7"
"@instructure/ui-decorator@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-decorator/-/ui-decorator-5.52.3.tgz#1f715000cd6043d5abd87d1684c687f58699e3c6"
@ -1343,6 +1401,14 @@
dependencies:
"@babel/runtime" "^7"
"@instructure/ui-dom-utils@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-dom-utils/-/ui-dom-utils-6.3.1-rc.1.tgz#dc6bfaece59727e9aedf5642995f798bdff16ffc"
integrity sha512-GA6xSK+sKPQFU35TZZo8c+dvW/Fhb6rmlagFsJdir/D2X+tAt/10daCcmCqsrjpe5SZaCi8sc+8ui/1yRnLqMQ==
dependencies:
"@babel/runtime" "^7"
"@instructure/console" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-dom-utils@^6.2.0":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@instructure/ui-dom-utils/-/ui-dom-utils-6.2.0.tgz#0ed3d9bfc332edc0f4c5d80830971942ec86acfc"
@ -1537,6 +1603,21 @@
keycode "^2"
prop-types "^15"
"@instructure/ui-i18n@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-i18n/-/ui-i18n-6.3.1-rc.1.tgz#24783a2006ad13b4357945ed7309db894e071609"
integrity sha512-RklcYl0Mf/LJCtUvHsQWU8x5MGyWpQgc2PcEDV2SeG3Ar60HGW9fjnCOZ6g6iXZftwpU8glTq5Ye9Mg3dTtBUA==
dependencies:
"@babel/runtime" "^7"
"@instructure/ui-decorator" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-dom-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-prop-types" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-react-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-utils" "6.3.1-rc.1+2dd401cc"
decimal.js "^10"
moment-timezone "^0.5"
prop-types "^15"
"@instructure/ui-i18n@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-i18n/-/ui-i18n-5.52.3.tgz#06290b2e57bc4a649a40f5ff192389192018f22c"
@ -1583,26 +1664,26 @@
"@instructure/ui-svg-images" "^5.52.3"
prop-types "^15"
"@instructure/ui-layout@6", "@instructure/ui-layout@^6.2.0":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@instructure/ui-layout/-/ui-layout-6.2.0.tgz#b5aca5ee9f8c973e53554aac7739a25ace15c5cc"
integrity sha512-K6atlH/ykHDJG4kaRgHrFkUXxSiCLnaEgq7zFu56yHaFTjU92bIU6/FAFkpSWZfcQ+f3HS3d7kX7JMftQchLjw==
"@instructure/ui-layout@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-layout/-/ui-layout-6.3.1-rc.1.tgz#77d0285322b013964cd0d084f52ac4eef70c5908"
integrity sha512-98BxHfP6SFADgp9YNymJz2PNycFBB5x0TBZXsTwaMd1W3gtDy30TZt0DIy4EdhYP9qHwEzGZvZPa7lBaviescg==
dependencies:
"@babel/runtime" "^7"
"@instructure/console" "^6.2.0"
"@instructure/debounce" "^6.2.0"
"@instructure/ui-a11y" "^6.2.0"
"@instructure/ui-color-utils" "^6.2.0"
"@instructure/ui-dom-utils" "^6.2.0"
"@instructure/ui-i18n" "^6.2.0"
"@instructure/ui-motion" "^6.2.0"
"@instructure/ui-portal" "^6.2.0"
"@instructure/ui-prop-types" "^6.2.0"
"@instructure/ui-react-utils" "^6.2.0"
"@instructure/ui-testable" "^6.2.0"
"@instructure/ui-themeable" "^6.2.0"
"@instructure/ui-utils" "^6.2.0"
"@instructure/uid" "^6.2.0"
"@instructure/console" "6.3.1-rc.1+2dd401cc"
"@instructure/debounce" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-a11y" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-color-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-dom-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-i18n" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-motion" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-portal" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-prop-types" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-react-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-testable" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-themeable" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/uid" "6.3.1-rc.1+2dd401cc"
classnames "^2"
prop-types "^15"
@ -1626,6 +1707,29 @@
classnames "^2"
prop-types "^15"
"@instructure/ui-layout@^6.2.0":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@instructure/ui-layout/-/ui-layout-6.2.0.tgz#b5aca5ee9f8c973e53554aac7739a25ace15c5cc"
integrity sha512-K6atlH/ykHDJG4kaRgHrFkUXxSiCLnaEgq7zFu56yHaFTjU92bIU6/FAFkpSWZfcQ+f3HS3d7kX7JMftQchLjw==
dependencies:
"@babel/runtime" "^7"
"@instructure/console" "^6.2.0"
"@instructure/debounce" "^6.2.0"
"@instructure/ui-a11y" "^6.2.0"
"@instructure/ui-color-utils" "^6.2.0"
"@instructure/ui-dom-utils" "^6.2.0"
"@instructure/ui-i18n" "^6.2.0"
"@instructure/ui-motion" "^6.2.0"
"@instructure/ui-portal" "^6.2.0"
"@instructure/ui-prop-types" "^6.2.0"
"@instructure/ui-react-utils" "^6.2.0"
"@instructure/ui-testable" "^6.2.0"
"@instructure/ui-themeable" "^6.2.0"
"@instructure/ui-utils" "^6.2.0"
"@instructure/uid" "^6.2.0"
classnames "^2"
prop-types "^15"
"@instructure/ui-media-player@^5":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@instructure/ui-media-player/-/ui-media-player-5.53.0.tgz#b3d3ecc909c8f37644a3fcf7bd1a45071eaf433a"
@ -1690,6 +1794,19 @@
keycode "^2"
prop-types "^15"
"@instructure/ui-motion@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-motion/-/ui-motion-6.3.1-rc.1.tgz#57b3924701d35090627488c9cb7565f53b04b7f9"
integrity sha512-6I3rGRvB6WjBlA0I4X47G2VAgcWpkf3e9w75gytD66ksI+ZeRgj1LQZz+YpKeU54ZEDOBhFKymw80nAHdD4xNw==
dependencies:
"@babel/runtime" "^7"
"@instructure/ui-dom-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-react-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-testable" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-themeable" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-utils" "6.3.1-rc.1+2dd401cc"
prop-types "^15"
"@instructure/ui-motion@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-motion/-/ui-motion-5.52.3.tgz#0ba1cacb32525b5ccfc9c47a348871f448bc0d05"
@ -1817,6 +1934,18 @@
"@instructure/uid" "^5.52.3"
prop-types "^15"
"@instructure/ui-portal@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-portal/-/ui-portal-6.3.1-rc.1.tgz#76f4d59dff96126d8267634b6bbde44fc050ff12"
integrity sha512-664pRm+yx+eRGpAS3wG438TU6SS5RXwAWTU1Yto82G1xtNXFGFIrJjlDM9XDf7nOYUNT6CK2/3B5jW11VCFOWQ==
dependencies:
"@babel/runtime" "^7"
"@emotion/is-prop-valid" "^0.7.3"
"@instructure/ui-i18n" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-prop-types" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-utils" "6.3.1-rc.1+2dd401cc"
prop-types "^15"
"@instructure/ui-portal@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-portal/-/ui-portal-5.52.3.tgz#44286ffd81fdeaa3efffd1cfe169aa54fd8053bc"
@ -1883,6 +2012,14 @@
postcss-reporter "^6.0.1"
postcss-simple-vars "^5.0.1"
"@instructure/ui-prop-types@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-prop-types/-/ui-prop-types-6.3.1-rc.1.tgz#32990264d43eb08803e8126600d02b1a23e5a889"
integrity sha512-Ji2jeeHR00x+gSq3slmP6VYpuzBaeHQPUmTgudplNSf2DiuZI5nJK5wpfdOc+6lo4SpJEC4kXVzUgdV6q1NFWw==
dependencies:
"@babel/runtime" "^7"
prop-types ">= 15.7.0"
"@instructure/ui-prop-types@^5", "@instructure/ui-prop-types@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-prop-types/-/ui-prop-types-5.52.3.tgz#aaa1945c9312449acbd20b00607f732301e12ff3"
@ -1911,6 +2048,26 @@
"@instructure/ui-utils" "^6.2.0"
prop-types "^15"
"@instructure/ui-react-utils@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-react-utils/-/ui-react-utils-6.3.1-rc.1.tgz#d04330ac21e08678eea0addfdef7e8f23a702988"
integrity sha512-NZww6Q4A8UnBXYJJVZLR3C6bDhX8cYDvkWOy+xdZ3dTl2TBEt/VBAqnCAD2Uxxo/AC9XWbU2OGR3jjKajVIUrQ==
dependencies:
"@babel/runtime" "^7"
"@instructure/console" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-decorator" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-dom-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-utils" "6.3.1-rc.1+2dd401cc"
prop-types "^15"
"@instructure/ui-stylesheet@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-stylesheet/-/ui-stylesheet-6.3.1-rc.1.tgz#4558d3cdd19da027b74f53de5253beb70dee5b5a"
integrity sha512-UBq7S3vk9lrz/4Uct3bxK5vS5dKQYHy63HT9rRJgA/Jiu4m7bBQl+Bkth1EVioJpW66owF1QfiXQt/yDgd2u8w==
dependencies:
"@babel/runtime" "^7"
glamor "^2.20.40"
"@instructure/ui-stylesheet@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-stylesheet/-/ui-stylesheet-5.52.3.tgz#4f35efb7ed6ceb3442a5efbf9ce80d9916e46322"
@ -2010,6 +2167,13 @@
keycode "^2"
prop-types "^15"
"@instructure/ui-testable@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-testable/-/ui-testable-6.3.1-rc.1.tgz#3f346675bd0a5a2c018780950610ec1669071d04"
integrity sha512-z05iSKLNssdE5Ck8lFDBxLoDyAXKzfc1K/p1gU8ja4kmFReZSNG+dXlkvUlv8Ay5j6BBohV/qyLePzaDmPbX4g==
dependencies:
"@instructure/ui-decorator" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-testable@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-testable/-/ui-testable-5.52.3.tgz#62deb9fcbca77df3151444e1eeed699d42196fe9"
@ -2060,6 +2224,22 @@
"@instructure/uid" "^6.2.0"
prop-types "^15"
"@instructure/ui-themeable@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-themeable/-/ui-themeable-6.3.1-rc.1.tgz#068ea40f4152c11059c6ff9eef3f3467a17311e6"
integrity sha512-TCRvjepKczZk3WxKxya7582iAdL/RdSmpr3op16t/8HA/GDkdWQxCRpoGY70gEYPj2c5C5z+NCutZPtp5kaIqw==
dependencies:
"@babel/runtime" "^7"
"@instructure/console" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-color-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-decorator" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-dom-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-react-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-stylesheet" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-utils" "6.3.1-rc.1+2dd401cc"
"@instructure/uid" "6.3.1-rc.1+2dd401cc"
prop-types "^15"
"@instructure/ui-themeable@^5", "@instructure/ui-themeable@^5.52.0", "@instructure/ui-themeable@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-themeable/-/ui-themeable-5.52.3.tgz#57d6feb3c0681fdfcba4a7a5b3f599e85a015b63"
@ -2150,6 +2330,18 @@
keycode "^2"
prop-types "^15"
"@instructure/ui-utils@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/ui-utils/-/ui-utils-6.3.1-rc.1.tgz#415ff20f2ce2934f5dcfe67293c8a985b6abc7f5"
integrity sha512-w/DYTzR+A5glVUg/ZbNK+OWlV98JKjooJF6Hdr4JDTWwIyEoM9LhtZcbSbTZgC/AhSFVaosoOTyVKIPgN0E9Wg==
dependencies:
"@babel/runtime" "^7"
"@instructure/console" "6.3.1-rc.1+2dd401cc"
"@instructure/ui-dom-utils" "6.3.1-rc.1+2dd401cc"
bowser "^1.9.4"
fast-deep-equal "^2"
keycode "^2"
"@instructure/ui-utils@^5", "@instructure/ui-utils@^5.52.0", "@instructure/ui-utils@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-utils/-/ui-utils-5.52.3.tgz#02d80fed992b6f34628db67554cffacae5787609"
@ -2188,6 +2380,13 @@
dependencies:
"@babel/runtime" "^7"
"@instructure/uid@6.3.1-rc.1+2dd401cc":
version "6.3.1-rc.1"
resolved "https://registry.yarnpkg.com/@instructure/uid/-/uid-6.3.1-rc.1.tgz#bc2a0456dcb8764875572b466d55631c043e1e36"
integrity sha512-SDqEIumFcuHXFaI1JOKbxmN/c9ghTnPnWmp0AOo/4rlafJT4C5heP8PO04K518ZK+/XMnoNK3i0t0mNXz+bgzw==
dependencies:
"@babel/runtime" "^7"
"@instructure/uid@^5.52.0", "@instructure/uid@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/uid/-/uid-5.52.3.tgz#4a0f2a739598cef40feca6b18fcb8ce795f82f76"