mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-24 01:08:50 -05:00
chore: Migrate AssertionsOptions menu to Vue. (#24286)
* React to vue * Goodbye dom. * Use event modifier. * Remove leading underscore in names * Use modifier. * Add flip, shift options. * Use createPopper instead of floating-ui. * Remove unnecessary dependencies. * addAssertion to event. * setPopperElement to event. * Strong types. * clarify test. Co-authored-by: Blue F <blue@cypress.io>
This commit is contained in:
@@ -255,4 +255,27 @@ it('visits a basic html page', () => {
|
||||
// Cypress in Cypress, it redirects us the the spec page, which is not what normally
|
||||
// would happen in production.
|
||||
})
|
||||
|
||||
it('shows menu and submenu correctly', () => {
|
||||
launchStudio()
|
||||
|
||||
cy.getAutIframe().within(() => {
|
||||
// Show menu
|
||||
cy.get('h1').realClick({
|
||||
button: 'right',
|
||||
})
|
||||
|
||||
cy.get('.__cypress-studio-assertions-menu').shadow()
|
||||
.find('.assertions-menu').should('be.visible')
|
||||
|
||||
// Show submenu
|
||||
cy.get('.__cypress-studio-assertions-menu').shadow()
|
||||
.find('.assertion-type-text:first').realHover()
|
||||
|
||||
cy.get('.__cypress-studio-assertions-menu').shadow()
|
||||
.find('.assertion-option')
|
||||
.should('have.text', 'Hello, Studio!')
|
||||
.should('be.visible')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"@intlify/vite-plugin-vue-i18n": "2.4.0",
|
||||
"@packages/frontend-shared": "0.0.0-development",
|
||||
"@percy/cypress": "^3.1.0",
|
||||
"@popperjs/core": "2.11.6",
|
||||
"@testing-library/cypress": "BlueWinds/cypress-testing-library#119054b5963b0d2e064b13c5cc6fc9db32c8b7b5",
|
||||
"@types/faker": "5.5.8",
|
||||
"@urql/core": "2.4.4",
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div
|
||||
ref="popper"
|
||||
class="assertion-options"
|
||||
>
|
||||
<div
|
||||
v-for="{ name, value } in options"
|
||||
:key="`${name}${value}`"
|
||||
class="assertion-option"
|
||||
@click.stop="() => onClick(name, value)"
|
||||
>
|
||||
<span
|
||||
v-if="name"
|
||||
class="assertion-option-name"
|
||||
>
|
||||
{{ truncate(name) }}:{{ ' ' }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="assertion-option-value"
|
||||
>
|
||||
{{ typeof value === 'string' && truncate(value) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createPopper } from '@popperjs/core'
|
||||
import { onMounted, ref, nextTick, Ref } from 'vue'
|
||||
import type { AssertionOption } from './types'
|
||||
|
||||
const props = defineProps<{
|
||||
type: string
|
||||
options: AssertionOption[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(eventName: 'addAssertion', value: { type: string, name: string, value: string })
|
||||
(eventName: 'setPopperElement', value: HTMLElement)
|
||||
}>()
|
||||
|
||||
const truncate = (str: string) => {
|
||||
if (str && str.length > 80) {
|
||||
return `${str.substr(0, 77)}...`
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
const popper: Ref<HTMLElement | null> = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const popperEl = popper.value as HTMLElement
|
||||
const reference = popperEl.parentElement as HTMLElement
|
||||
|
||||
createPopper(reference, popperEl, {
|
||||
placement: 'right-start',
|
||||
})
|
||||
|
||||
emit('setPopperElement', popperEl)
|
||||
})
|
||||
})
|
||||
|
||||
const onClick = (name, value) => {
|
||||
emit('addAssertion', { type: props.type, name, value })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './assertions-style.scss';
|
||||
|
||||
.assertion-options {
|
||||
@include menu-style;
|
||||
|
||||
font-size: 14px;
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
overflow-wrap: break-word;
|
||||
position: absolute;
|
||||
|
||||
.assertion-option {
|
||||
cursor: pointer;
|
||||
padding: 0.4rem 0.6rem;
|
||||
|
||||
&:hover {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
.assertion-option-value {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div
|
||||
:class="['assertion-type', { 'single-assertion': !hasOptions }]"
|
||||
@click.stop="onClick"
|
||||
@mouseover.stop="onOpen"
|
||||
@mouseout.stop="onClose"
|
||||
>
|
||||
<div class="assertion-type-text">
|
||||
<span>
|
||||
{{ type.replace(/\./g, ' ') }}
|
||||
</span>
|
||||
<span
|
||||
v-if="hasOptions"
|
||||
class="dropdown-arrow"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="12"
|
||||
height="12"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<AssertionOptions
|
||||
v-if="hasOptions && isOpen"
|
||||
:type="type"
|
||||
:options="options"
|
||||
@set-popper-element="setPopperElement"
|
||||
@add-assertion="addAssertion"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Ref, ref } from 'vue'
|
||||
import AssertionOptions from './AssertionOptions.ce.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
type: string
|
||||
options: any
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(eventName: 'addAssertion', value: { type: string, name?: string, value?: string })
|
||||
}>()
|
||||
|
||||
const isOpen = ref(false)
|
||||
const hasOptions = props.options && !!props.options.length
|
||||
const popperElement: Ref<HTMLElement | null> = ref(null)
|
||||
|
||||
const onOpen = () => {
|
||||
isOpen.value = true
|
||||
}
|
||||
|
||||
const onClose = (e: MouseEvent) => {
|
||||
if (e.relatedTarget instanceof Element &&
|
||||
popperElement.value && popperElement.value.contains(e.relatedTarget)) {
|
||||
return
|
||||
}
|
||||
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
const onClick = () => {
|
||||
if (!hasOptions) {
|
||||
emit('addAssertion', { type: props.type })
|
||||
}
|
||||
}
|
||||
|
||||
const setPopperElement = (el: HTMLElement) => {
|
||||
popperElement.value = el
|
||||
}
|
||||
|
||||
const addAssertion = ({ type, name, value }) => {
|
||||
emit('addAssertion', { type, name, value })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './assertions-style.scss';
|
||||
|
||||
.assertion-type {
|
||||
color: #202020;
|
||||
cursor: default;
|
||||
font-size: 14px;
|
||||
padding: 0.4rem 0.4rem 0.4rem 0.7rem;
|
||||
position: static;
|
||||
|
||||
&:first-of-type {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
border-bottom-left-radius: $border-radius;
|
||||
border-bottom-right-radius: $border-radius;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
&.single-assertion {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.assertion-type-text {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
.dropdown-arrow {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div
|
||||
ref="highlight"
|
||||
class="highlight"
|
||||
:style="highlightStyle"
|
||||
/>
|
||||
<div
|
||||
ref="assertionsMenu"
|
||||
class="assertions-menu"
|
||||
>
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span>Add Assertion</span>
|
||||
</div>
|
||||
<div class="close-wrapper">
|
||||
<a
|
||||
class="close"
|
||||
@click.stop="onClose"
|
||||
>×</a>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="subtitle"
|
||||
>
|
||||
expect
|
||||
{{ ' ' }}
|
||||
<code>
|
||||
{{ tagName }}
|
||||
</code>
|
||||
{{ ' ' }}
|
||||
to
|
||||
</div>
|
||||
<div
|
||||
class="assertions-list"
|
||||
>
|
||||
<AssertionType
|
||||
v-for="(assertion) in possibleAssertions"
|
||||
:key="assertion.type"
|
||||
:type="assertion.type"
|
||||
:options="assertion.options"
|
||||
@add-assertion="onAddAssertion"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createPopper } from '@popperjs/core'
|
||||
import AssertionType from './AssertionType.ce.vue'
|
||||
import _ from 'lodash'
|
||||
import { nextTick, onMounted, Ref, ref, StyleValue } from 'vue'
|
||||
import type { PossibleAssertions, AddAssertion, AssertionArgs } from './types'
|
||||
|
||||
const props = defineProps <{
|
||||
jqueryElement: JQuery<HTMLElement>
|
||||
possibleAssertions: PossibleAssertions
|
||||
addAssertion: AddAssertion
|
||||
closeMenu: () => void
|
||||
highlightStyle: StyleValue
|
||||
}>()
|
||||
|
||||
const onAddAssertion = ({ type, name, value }: {
|
||||
type: string
|
||||
name?: string
|
||||
value?: string
|
||||
}) => {
|
||||
let args = [type, name, value]
|
||||
|
||||
args = _.compact(args)
|
||||
props.addAssertion(props.jqueryElement, ...args as AssertionArgs)
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
props.closeMenu()
|
||||
}
|
||||
|
||||
const tagName = `<${props.jqueryElement.prop('tagName').toLowerCase()}>`
|
||||
|
||||
const highlight: Ref<HTMLElement | null> = ref(null)
|
||||
const assertionsMenu: Ref<HTMLElement | null> = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const highlightEl = highlight.value as HTMLElement
|
||||
const assertionsMenuEl = assertionsMenu.value as HTMLElement
|
||||
|
||||
createPopper(highlightEl, assertionsMenuEl, {
|
||||
modifiers: [
|
||||
{
|
||||
name: 'preventOverflow',
|
||||
options: {
|
||||
altAxis: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./assertions-style.scss";
|
||||
|
||||
.highlight {
|
||||
background: rgba(159, 196, 231, 0.6);
|
||||
border: solid 2px #9FC4E7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.assertions-menu {
|
||||
@include menu-style;
|
||||
|
||||
font-family: 'Helvetica Neue', 'Arial', sans-serif;
|
||||
z-index: 2147483647;
|
||||
width: 175px;
|
||||
position: absolute;
|
||||
|
||||
.header {
|
||||
align-items: center;
|
||||
background: #07b282;
|
||||
border-top-left-radius: $border-radius;
|
||||
border-top-right-radius: $border-radius;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
padding: 0.5rem 0.7rem;
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.close-wrapper {
|
||||
margin-left: auto;
|
||||
margin-top: -2.5px;
|
||||
|
||||
.close {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
cursor: pointer;
|
||||
color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
border-bottom: 1px solid #c4c4c4;
|
||||
color: #6b6b6b;
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
padding: 0.5rem 0.7rem;
|
||||
|
||||
code {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,8 @@
|
||||
$border-radius: 4px;
|
||||
|
||||
@mixin menu-style {
|
||||
background: #fff;
|
||||
border: 1px solid #DDD;
|
||||
box-shadow: 2px 5px 12px rgba(0, 0, 0, 0.2);
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import { App, createApp, StyleValue } from 'vue'
|
||||
import AssertionsMenu from './AssertionsMenu.ce.vue'
|
||||
import AssertionType from './AssertionType.ce.vue'
|
||||
import AssertionOptions from './AssertionOptions.ce.vue'
|
||||
import { getOrCreateHelperDom, getSelectorHighlightStyles } from '../dom'
|
||||
import type { PossibleAssertions, AddAssertion } from './types'
|
||||
|
||||
function getStudioAssertionsMenuDom (body) {
|
||||
return getOrCreateHelperDom({
|
||||
body,
|
||||
className: '__cypress-studio-assertions-menu',
|
||||
css: `${AssertionsMenu.styles}\n${AssertionType.styles}\n${AssertionOptions.styles}`,
|
||||
})
|
||||
}
|
||||
|
||||
interface StudioAssertionsMenuArgs {
|
||||
$el: JQuery<HTMLElement>
|
||||
$body: JQuery<HTMLElement>
|
||||
props: {
|
||||
possibleAssertions: PossibleAssertions
|
||||
addAssertion: AddAssertion
|
||||
closeMenu: () => void
|
||||
}
|
||||
}
|
||||
|
||||
export function openStudioAssertionsMenu ({ $el, $body, props }: StudioAssertionsMenuArgs) {
|
||||
const { vueContainer } = getStudioAssertionsMenuDom($body.get(0))
|
||||
|
||||
vueContainerListeners(vueContainer)
|
||||
|
||||
const selectorHighlightStyles = getSelectorHighlightStyles([$el.get(0)])[0]
|
||||
|
||||
mountAssertionsMenu(vueContainer, $el, props.possibleAssertions, props.addAssertion, props.closeMenu, selectorHighlightStyles)
|
||||
}
|
||||
|
||||
export function closeStudioAssertionsMenu ($body) {
|
||||
const { container } = getStudioAssertionsMenuDom($body.get(0))
|
||||
|
||||
unmountAssertionsMenu()
|
||||
container.remove()
|
||||
}
|
||||
|
||||
let app: App<Element> | null = null
|
||||
|
||||
const mountAssertionsMenu = (
|
||||
container: Element,
|
||||
jqueryElement: any,
|
||||
possibleAssertions: any[],
|
||||
addAssertion: any,
|
||||
closeMenu: any,
|
||||
highlightStyle: StyleValue,
|
||||
) => {
|
||||
app = createApp(AssertionsMenu, {
|
||||
jqueryElement,
|
||||
possibleAssertions,
|
||||
addAssertion,
|
||||
closeMenu,
|
||||
highlightStyle,
|
||||
})
|
||||
|
||||
app.mount(container)
|
||||
}
|
||||
|
||||
const unmountAssertionsMenu = () => {
|
||||
if (app) {
|
||||
app.unmount()
|
||||
app = null
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove these.
|
||||
// For some reason, the root div of our AssertionsMenu app usually gets
|
||||
// all the events and does not distribute the events to the children.
|
||||
// So, we're manually distributing the events.
|
||||
// But it causes duplicated events are sent to the same object, so we're filtering them.
|
||||
// I failed to prove it's our problem or Vue's problem.
|
||||
let lastTarget = null
|
||||
let lastTimeStamp = -1
|
||||
|
||||
function vueContainerListeners (vueContainer) {
|
||||
vueContainer.addEventListener('click', (e) => {
|
||||
const paths = e.composedPath()
|
||||
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
const el = paths[i] as HTMLElement
|
||||
|
||||
if (classIncludes(el, 'single-assertion') ||
|
||||
classIncludes(el, 'assertion-option') ||
|
||||
(el.tagName === 'A' && classIncludes(el, 'close'))) {
|
||||
el.dispatchEvent(new MouseEvent('click', e))
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
vueContainer.addEventListener('mouseover', (e) => {
|
||||
const paths = e.composedPath()
|
||||
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
const el = paths[i] as HTMLElement
|
||||
|
||||
if (classIncludes(el, 'assertion-type')) {
|
||||
el.dispatchEvent(new MouseEvent('mouseover', e))
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
vueContainer.addEventListener('mouseout', (e) => {
|
||||
// Sometimes, there is maximum call stack size exceeded error.
|
||||
if (lastTarget === e.target && lastTimeStamp - e.timeStamp < 100) {
|
||||
return
|
||||
}
|
||||
|
||||
lastTarget = e.target
|
||||
lastTimeStamp = e.timeStamp
|
||||
|
||||
const paths = e.composedPath()
|
||||
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
const el = paths[i] as HTMLElement
|
||||
|
||||
if (classIncludes(el, 'assertion-type')) {
|
||||
el.dispatchEvent(new MouseEvent('mouseout', e))
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function classIncludes (el, className) {
|
||||
return typeof el.className === 'string' && el.className.includes(className)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export interface AssertionOption {
|
||||
name?: string
|
||||
value?: string | number | string[]
|
||||
}
|
||||
|
||||
export type PossibleAssertions = Array<{ type: string, options?: AssertionOption[] }>
|
||||
|
||||
// Single argument assertion: ['be.visible']
|
||||
type AssertionArgs_1 = [string]
|
||||
// Two argument assertion: ['have.text', '<some text>']
|
||||
type AssertionArgs_2 = [string, string]
|
||||
// Three argument assertion: ['have.attr', 'href', '<some value>']
|
||||
type AssertionArgs_3 = [string, string, string]
|
||||
|
||||
export type AssertionArgs = AssertionArgs_1 | AssertionArgs_2 | AssertionArgs_3
|
||||
|
||||
export type AddAssertion = ($el: HTMLElement | JQuery<HTMLElement>, ...args: AssertionArgs) => void
|
||||
@@ -3,7 +3,9 @@ import { defineStore } from 'pinia'
|
||||
|
||||
import { getEventManager } from '../runner'
|
||||
import type { StudioSavePayload } from '../runner/event-manager-types'
|
||||
import { closeStudioAssertionsMenu, openStudioAssertionsMenu } from '../runner/studio/mounter'
|
||||
import { useAutStore } from './aut-store'
|
||||
import type { PossibleAssertions, AssertionArgs } from '../runner/studio/types'
|
||||
|
||||
function getCypress () {
|
||||
const eventManager = getEventManager()
|
||||
@@ -86,15 +88,6 @@ const tagNamesWithValue = [
|
||||
'TEXTAREA',
|
||||
]
|
||||
|
||||
// Single argument assertion: ['be.visible']
|
||||
type AssertionArgs_1 = [string]
|
||||
// Two argument assertion: ['have.text', '<some text>']
|
||||
type AssertionArgs_2 = [string, string]
|
||||
// Three argument assertion: ['have.attr', 'href', '<some value>']
|
||||
type AssertionArgs_3 = [string, string, string]
|
||||
|
||||
type AssertionArgs = AssertionArgs_1 | AssertionArgs_2 | AssertionArgs_3
|
||||
|
||||
export interface StudioLog {
|
||||
id?: number
|
||||
name: string
|
||||
@@ -402,7 +395,7 @@ export const useStudioStore = defineStore('studioRecorder', {
|
||||
})
|
||||
},
|
||||
|
||||
_addAssertion ($el: HTMLElement, ...args: AssertionArgs) {
|
||||
_addAssertion ($el: HTMLElement | JQuery<HTMLElement>, ...args: AssertionArgs) {
|
||||
const id = this._getId()
|
||||
const selector = getCypress().SelectorPlayground.getSelector($el)
|
||||
|
||||
@@ -420,7 +413,7 @@ export const useStudioStore = defineStore('studioRecorder', {
|
||||
id,
|
||||
selector,
|
||||
name: 'assert',
|
||||
message: this._generateAssertionMessage($el, ...args),
|
||||
message: this._generateAssertionMessage($el as HTMLElement, ...args),
|
||||
}
|
||||
|
||||
this._generateBothLogs(reporterLog).forEach((commandLog) => {
|
||||
@@ -774,7 +767,7 @@ export const useStudioStore = defineStore('studioRecorder', {
|
||||
|
||||
this._closeAssertionsMenu()
|
||||
|
||||
window.UnifiedRunner.dom.openStudioAssertionsMenu({
|
||||
openStudioAssertionsMenu({
|
||||
$el,
|
||||
$body: window.UnifiedRunner.CypressJQuery(this._body),
|
||||
props: {
|
||||
@@ -790,13 +783,13 @@ export const useStudioStore = defineStore('studioRecorder', {
|
||||
throw Error('this._body was not defined')
|
||||
}
|
||||
|
||||
window.UnifiedRunner.dom.closeStudioAssertionsMenu(window.UnifiedRunner.CypressJQuery(this._body))
|
||||
closeStudioAssertionsMenu(window.UnifiedRunner.CypressJQuery(this._body))
|
||||
},
|
||||
|
||||
_generatePossibleAssertions ($el: JQuery<Element>) {
|
||||
const tagName = $el.prop('tagName')
|
||||
|
||||
const possibleAssertions: Array<{ type: string, options?: unknown[] }> = []
|
||||
const possibleAssertions: PossibleAssertions = []
|
||||
|
||||
if (!tagNamesWithoutText.includes(tagName)) {
|
||||
const text = $el.text()
|
||||
|
||||
@@ -14,29 +14,9 @@
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/react-tooltip": "0.5.3",
|
||||
"@fontsource/mulish": "4.3.0",
|
||||
"@fontsource/open-sans": "4.3.0",
|
||||
"@fortawesome/fontawesome-free": "6.0.0",
|
||||
"@packages/driver": "0.0.0-development",
|
||||
"@packages/icons": "0.0.0-development",
|
||||
"@packages/reporter": "0.0.0-development",
|
||||
"@packages/web-config": "0.0.0-development",
|
||||
"@popperjs/core": "2.9.2",
|
||||
"babel-plugin-prismjs": "1.0.2",
|
||||
"bluebird": "3.5.3",
|
||||
"classnames": "2.3.1",
|
||||
"cross-env": "6.0.3",
|
||||
"jquery": "3.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mobx": "5.15.4",
|
||||
"mobx-react": "6.1.8",
|
||||
"prismjs": "1.21.0",
|
||||
"prop-types": "15.7.2",
|
||||
"react": "16.8.6",
|
||||
"react-dom": "16.8.6",
|
||||
"react-popper": "2.2.5",
|
||||
"react-shadow-dom-retarget-events": "1.0.11",
|
||||
"rimraf": "3.0.2",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "3.3.2"
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
import retargetEvents from 'react-shadow-dom-retarget-events'
|
||||
|
||||
import $Cypress from '@packages/driver'
|
||||
import { studioAssertionsMenu } from '../studio/assertions-menu'
|
||||
// The '!' tells webpack to disable normal loaders, and keep loaders with `enforce: 'pre'` and `enforce: 'post'`
|
||||
// This disables the CSSExtractWebpackPlugin and allows us to get the CSS as a raw string instead of saving it to a separate file.
|
||||
import studioAssertionsMenuCSS from '!../studio/assertions-menu.scss'
|
||||
|
||||
const $ = $Cypress.$
|
||||
|
||||
function getOrCreateHelperDom ({ $body, className, css }) {
|
||||
let $container = $body.find(`.${className}`)
|
||||
|
||||
if ($container.length) {
|
||||
const shadowRoot = $container[0].shadowRoot
|
||||
|
||||
return {
|
||||
$container,
|
||||
shadowRoot,
|
||||
$reactContainer: $(shadowRoot).find('.react-container'),
|
||||
}
|
||||
}
|
||||
|
||||
$container = $('<div />')
|
||||
.addClass(className)
|
||||
.css({ position: 'static' })
|
||||
.appendTo($body)
|
||||
|
||||
const shadowRoot = $container[0].attachShadow({ mode: 'open' })
|
||||
|
||||
const $reactContainer = $('<div />')
|
||||
.addClass('react-container')
|
||||
.appendTo(shadowRoot)
|
||||
|
||||
$('<style />', { html: css.toString() }).prependTo(shadowRoot)
|
||||
|
||||
return { $container, shadowRoot, $reactContainer }
|
||||
}
|
||||
|
||||
function getSelectorHighlightStyles ($el) {
|
||||
const borderSize = 2
|
||||
|
||||
return $el.map((__, el) => {
|
||||
const $el = $(el)
|
||||
const offset = $el.offset()
|
||||
|
||||
return {
|
||||
position: 'absolute',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
width: $el.outerWidth(),
|
||||
height: $el.outerHeight(),
|
||||
top: offset.top - borderSize,
|
||||
left: offset.left - borderSize,
|
||||
transform: $el.css('transform'),
|
||||
zIndex: getZIndex($el),
|
||||
}
|
||||
}).get()
|
||||
}
|
||||
|
||||
function getStudioAssertionsMenuDom ($body) {
|
||||
return getOrCreateHelperDom({
|
||||
$body,
|
||||
className: '__cypress-studio-assertions-menu',
|
||||
css: studioAssertionsMenuCSS,
|
||||
})
|
||||
}
|
||||
|
||||
function openStudioAssertionsMenu ({ $el, $body, props }) {
|
||||
const { shadowRoot, $reactContainer } = getStudioAssertionsMenuDom($body)
|
||||
|
||||
const selectorHighlightStyles = getSelectorHighlightStyles($el)[0]
|
||||
|
||||
studioAssertionsMenu.render($reactContainer[0], {
|
||||
$el,
|
||||
selectorHighlightStyles,
|
||||
...props,
|
||||
})
|
||||
|
||||
retargetEvents(shadowRoot)
|
||||
}
|
||||
|
||||
function closeStudioAssertionsMenu ($body) {
|
||||
const { $container, $reactContainer } = getStudioAssertionsMenuDom($body)
|
||||
|
||||
studioAssertionsMenu.unmount($reactContainer[0])
|
||||
$container.remove()
|
||||
}
|
||||
|
||||
function getZIndex (el) {
|
||||
if (/^(auto|0)$/.test(el.css('zIndex'))) {
|
||||
return 2147483647
|
||||
}
|
||||
|
||||
return _.toNumber(el.css('zIndex'))
|
||||
}
|
||||
|
||||
export const dom = {
|
||||
openStudioAssertionsMenu,
|
||||
closeStudioAssertionsMenu,
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from './dom'
|
||||
@@ -1,8 +1,6 @@
|
||||
@import 'lib/variables';
|
||||
@import 'lib/mixins';
|
||||
@import 'lib/fonts';
|
||||
$cy-tooltip-class: 'cy-tooltip';
|
||||
@import '~@cypress/react-tooltip/dist/tooltip.scss';
|
||||
@import 'lib/base';
|
||||
// import all other scss files in src except if they are in lib
|
||||
// or their file name is `main`
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { render, unmountComponentAtNode } from 'react-dom'
|
||||
import { usePopper } from 'react-popper'
|
||||
import _ from 'lodash'
|
||||
import cs from 'classnames'
|
||||
|
||||
const AssertionType = ({ addAssertion, type, options }) => {
|
||||
const [isOpen, setOpen] = useState(false)
|
||||
const [referenceElement, setReferenceElement] = useState(null)
|
||||
const [popperElement, setPopperElement] = useState(null)
|
||||
|
||||
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
||||
placement: 'right-start',
|
||||
})
|
||||
|
||||
function _open () {
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
function _close (e) {
|
||||
// don't close menu if mouse out to sub menu
|
||||
if (popperElement && popperElement.contains(e.relatedTarget)) {
|
||||
return
|
||||
}
|
||||
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
function _truncate (str) {
|
||||
if (str && str.length > 80) {
|
||||
return `${str.substr(0, 77)}...`
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
const hasOptions = options && !!options.length
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={setReferenceElement}
|
||||
className={cs('assertion-type', { 'single-assertion': !hasOptions })}
|
||||
onClick={!hasOptions ? () => addAssertion(type) : null}
|
||||
// onMouseEnter and onMouseLeave events do not work properly inside shadow dom
|
||||
onMouseOver={_open}
|
||||
onMouseOut={_close}
|
||||
>
|
||||
<div className='assertion-type-text'>
|
||||
<span>
|
||||
{type.replace(/\./g, ' ')}
|
||||
</span>
|
||||
{hasOptions && (
|
||||
<span className='dropdown-arrow'>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fillRule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z" />
|
||||
</svg>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{hasOptions && isOpen && (
|
||||
<div ref={setPopperElement} className='assertion-options' style={styles.popper} {...attributes.popper}>
|
||||
{options.map(({ name, value }) => (
|
||||
<div
|
||||
key={`${name}${value}`}
|
||||
className='assertion-option'
|
||||
onClick={() => addAssertion(type, name, value)}
|
||||
>
|
||||
{name && (
|
||||
<span className='assertion-option-name'>
|
||||
{_truncate(name)}
|
||||
:
|
||||
{' '}
|
||||
</span>
|
||||
)}
|
||||
<span className='assertion-option-value'>
|
||||
{_truncate(value)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const AssertionsMenu = ({ $el, possibleAssertions, addAssertion, closeMenu, selectorHighlightStyles }) => {
|
||||
const [referenceElement, setReferenceElement] = useState(null)
|
||||
const [popperElement, setPopperElement] = useState(null)
|
||||
|
||||
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
||||
modifiers: [{
|
||||
name: 'preventOverflow',
|
||||
options: {
|
||||
altAxis: true,
|
||||
},
|
||||
}],
|
||||
})
|
||||
|
||||
function _addAssertion (...args) {
|
||||
args = _.compact(args)
|
||||
|
||||
addAssertion($el, ...args)
|
||||
}
|
||||
|
||||
function _close (event) {
|
||||
event.preventDefault()
|
||||
|
||||
closeMenu()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div ref={setReferenceElement} className='highlight' style={selectorHighlightStyles} />
|
||||
<div ref={setPopperElement} className='assertions-menu' style={styles.popper} {...attributes.popper}>
|
||||
<div className='header'>
|
||||
<div className='title'>
|
||||
<span>Add Assertion</span>
|
||||
</div>
|
||||
<div className='close-wrapper'>
|
||||
<a className='close' onClick={_close}>×</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='subtitle'>
|
||||
expect
|
||||
{' '}
|
||||
<code>
|
||||
{`<${$el.prop('tagName').toLowerCase()}>`}
|
||||
</code>
|
||||
{' '}
|
||||
to
|
||||
</div>
|
||||
<div className='assertions-list'>
|
||||
{possibleAssertions.map((assertion) => (
|
||||
<AssertionType key={assertion.type} addAssertion={_addAssertion} {...assertion} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const renderAssertionsMenu = (container, props) => {
|
||||
render(<AssertionsMenu {...props} />, container)
|
||||
}
|
||||
|
||||
export const studioAssertionsMenu = {
|
||||
render: renderAssertionsMenu,
|
||||
unmount: unmountComponentAtNode,
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/**
|
||||
* This is a standalone file that gets included with the assertions menu
|
||||
* in the user's app html
|
||||
*/
|
||||
|
||||
$border-radius: 4px;
|
||||
|
||||
@mixin menu-style {
|
||||
background: #fff;
|
||||
border: 1px solid #DDD;
|
||||
box-shadow: 2px 5px 12px rgba(0, 0, 0, 0.2);
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: rgba(159, 196, 231, 0.6);
|
||||
border: solid 2px #9FC4E7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.assertions-menu {
|
||||
@include menu-style;
|
||||
|
||||
font-family: 'Helvetica Neue', 'Arial', sans-serif;
|
||||
z-index: 2147483647;
|
||||
width: 175px;
|
||||
|
||||
.header {
|
||||
align-items: center;
|
||||
background: #07b282;
|
||||
border-top-left-radius: $border-radius;
|
||||
border-top-right-radius: $border-radius;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
padding: 0.5rem 0.7rem;
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.close-wrapper {
|
||||
margin-left: auto;
|
||||
margin-top: -2.5px;
|
||||
|
||||
.close {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
cursor: pointer;
|
||||
color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
border-bottom: 1px solid #c4c4c4;
|
||||
color: #6b6b6b;
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
padding: 0.5rem 0.7rem;
|
||||
|
||||
code {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.assertions-list {
|
||||
.assertion-type {
|
||||
color: #202020;
|
||||
cursor: default;
|
||||
font-size: 14px;
|
||||
padding: 0.4rem 0.4rem 0.4rem 0.7rem;
|
||||
position: relative;
|
||||
|
||||
&:first-of-type {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
border-bottom-left-radius: $border-radius;
|
||||
border-bottom-right-radius: $border-radius;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
&.single-assertion {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.assertion-type-text {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
.dropdown-arrow {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.assertion-options {
|
||||
@include menu-style;
|
||||
|
||||
font-size: 14px;
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
.assertion-option {
|
||||
cursor: pointer;
|
||||
padding: 0.4rem 0.6rem;
|
||||
|
||||
&:hover {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
.assertion-option-value {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -5,15 +5,11 @@ import { Reporter } from '@packages/reporter/src/main'
|
||||
import shortcuts from '@packages/reporter/src/lib/shortcuts'
|
||||
import * as MobX from 'mobx'
|
||||
|
||||
import { dom } from './src/dom'
|
||||
|
||||
export const UnifiedRunner = {
|
||||
CypressJQuery: $Cypress.$,
|
||||
|
||||
CypressDriver: $Cypress,
|
||||
|
||||
dom,
|
||||
|
||||
shortcuts,
|
||||
|
||||
React,
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
diff --git a/node_modules/@popperjs/core/lib/modifiers/preventOverflow.js b/node_modules/@popperjs/core/lib/modifiers/preventOverflow.js
|
||||
index 1776c09..e08aad1 100644
|
||||
--- a/node_modules/@popperjs/core/lib/modifiers/preventOverflow.js
|
||||
+++ b/node_modules/@popperjs/core/lib/modifiers/preventOverflow.js
|
||||
@@ -52,26 +52,27 @@ function preventOverflow(_ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
- if (checkMainAxis || checkAltAxis) {
|
||||
- var mainSide = mainAxis === 'y' ? top : left;
|
||||
- var altSide = mainAxis === 'y' ? bottom : right;
|
||||
- var len = mainAxis === 'y' ? 'height' : 'width';
|
||||
- var offset = popperOffsets[mainAxis];
|
||||
- var min = popperOffsets[mainAxis] + overflow[mainSide];
|
||||
- var max = popperOffsets[mainAxis] - overflow[altSide];
|
||||
+ function setOffset(axis) {
|
||||
+ var isMainAxis = axis === mainAxis;
|
||||
+ var mainSide = axis === 'y' ? top : left;
|
||||
+ var altSide = axis === 'y' ? bottom : right;
|
||||
+ var len = axis === 'y' ? 'height' : 'width';
|
||||
+ var offset = popperOffsets[axis];
|
||||
+ var min = popperOffsets[axis] + overflow[mainSide];
|
||||
+ var max = popperOffsets[axis] - overflow[altSide];
|
||||
var additive = tether ? -popperRect[len] / 2 : 0;
|
||||
var minLen = variation === start ? referenceRect[len] : popperRect[len];
|
||||
var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go
|
||||
- // outside the reference bounds
|
||||
+ // outside the reference bounds when on the main axis
|
||||
|
||||
var arrowElement = state.elements.arrow;
|
||||
- var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
|
||||
+ var arrowRect = tether && arrowElement && isMainAxis ? getLayoutRect(arrowElement) : {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();
|
||||
- var arrowPaddingMin = arrowPaddingObject[mainSide];
|
||||
- var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want
|
||||
+ var arrowPaddingMin = isMainAxis ? arrowPaddingObject[mainSide] : 0;
|
||||
+ var arrowPaddingMax = isMainAxis ? arrowPaddingObject[altSide] : 0; // If the reference length is smaller than the arrow length, we don't want
|
||||
// to include its full size in the calculation. If the reference is small
|
||||
// and near the edge of a boundary, the popper can overflow even if the
|
||||
// reference is not overflowing as well (e.g. virtual elements with no
|
||||
@@ -81,33 +82,22 @@ function preventOverflow(_ref) {
|
||||
var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue;
|
||||
var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue;
|
||||
var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
|
||||
- var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
|
||||
- var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0;
|
||||
- var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset;
|
||||
- var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue;
|
||||
-
|
||||
- if (checkMainAxis) {
|
||||
- var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);
|
||||
- popperOffsets[mainAxis] = preventedOffset;
|
||||
- data[mainAxis] = preventedOffset - offset;
|
||||
- }
|
||||
-
|
||||
- if (checkAltAxis) {
|
||||
- var _mainSide = mainAxis === 'x' ? top : left;
|
||||
-
|
||||
- var _altSide = mainAxis === 'x' ? bottom : right;
|
||||
-
|
||||
- var _offset = popperOffsets[altAxis];
|
||||
-
|
||||
- var _min = _offset + overflow[_mainSide];
|
||||
-
|
||||
- var _max = _offset - overflow[_altSide];
|
||||
+ var clientOffset = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
|
||||
+ var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][axis] : 0;
|
||||
+ var referenceRectEnd = referenceRect[axis] + referenceRect[len];
|
||||
+ var tetherMin = !isMainAxis && referenceRect[axis] < popperRect[axis] ? popperOffsets[axis] + minOffset - offsetModifierValue - clientOffset : referenceRectEnd;
|
||||
+ var tetherMax = !isMainAxis && referenceRectEnd < popperRect[axis] ? popperOffsets[axis] + maxOffset - offsetModifierValue : referenceRect[axis];
|
||||
+ var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);
|
||||
+ popperOffsets[axis] = preventedOffset;
|
||||
+ data[axis] = preventedOffset - offset;
|
||||
+ }
|
||||
|
||||
- var _preventedOffset = within(tether ? mathMin(_min, tetherMin) : _min, _offset, tether ? mathMax(_max, tetherMax) : _max);
|
||||
+ if (checkMainAxis) {
|
||||
+ setOffset(mainAxis);
|
||||
+ }
|
||||
|
||||
- popperOffsets[altAxis] = _preventedOffset;
|
||||
- data[altAxis] = _preventedOffset - _offset;
|
||||
- }
|
||||
+ if (checkAltAxis) {
|
||||
+ setOffset(altAxis);
|
||||
}
|
||||
|
||||
state.modifiersData[name] = data;
|
||||
@@ -5768,10 +5768,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.20.tgz#111b5db0f501aa89b05076fa31f0ea0e0c292cd3"
|
||||
integrity sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q==
|
||||
|
||||
"@popperjs/core@2.9.2":
|
||||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353"
|
||||
integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==
|
||||
"@popperjs/core@2.11.6":
|
||||
version "2.11.6"
|
||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
|
||||
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
|
||||
|
||||
"@purge-icons/generated@0.8.1":
|
||||
version "0.8.1"
|
||||
@@ -28632,11 +28632,6 @@ react-error-overlay@^6.0.3:
|
||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6"
|
||||
integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==
|
||||
|
||||
react-fast-compare@^3.0.1:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
|
||||
|
||||
react-focus-lock@^2.3.1:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.5.0.tgz#12e3a3940e897c26e2c2a0408cd25ea3c99b3709"
|
||||
@@ -28654,14 +28649,6 @@ react-is@^16.12.0, react-is@^16.13.1, react-is@^16.8.1, react-is@^16.8.6:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-popper@2.2.5:
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.2.5.tgz#1214ef3cec86330a171671a4fbcbeeb65ee58e96"
|
||||
integrity sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==
|
||||
dependencies:
|
||||
react-fast-compare "^3.0.1"
|
||||
warning "^4.0.2"
|
||||
|
||||
react-refresh@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.12.0.tgz#28ac0a2c30ef2bb3433d5fd0621e69a6d774c3a4"
|
||||
@@ -28763,11 +28750,6 @@ react-scripts@3.2:
|
||||
optionalDependencies:
|
||||
fsevents "2.0.7"
|
||||
|
||||
react-shadow-dom-retarget-events@1.0.11:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/react-shadow-dom-retarget-events/-/react-shadow-dom-retarget-events-1.0.11.tgz#e57ce3ba0bc8159fec4861778daf02161440f156"
|
||||
integrity sha512-4ExKxKEWUCEmVBZmtly5lgHd9vz/NDKv5H7KmFZZxHZW/W6EmmzyOA928OqeWPxcfXUjfNG8q3hpwCD9O7CRRg==
|
||||
|
||||
react-style-singleton@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
|
||||
@@ -34609,7 +34591,7 @@ walker@^1.0.7, walker@~1.0.5:
|
||||
dependencies:
|
||||
makeerror "1.0.x"
|
||||
|
||||
warning@^4.0.2, warning@^4.0.3:
|
||||
warning@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
|
||||
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
|
||||
|
||||
Reference in New Issue
Block a user