From 1eebfa60c17e988ddb29073aafd6c2c7c039780c Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:53:12 +0200 Subject: [PATCH 001/272] Easier grid drag animation (#6321) **Problem:** The grid drag animation is a bit jaggy. **Fix:** 1. Disable the element outline during the grid drag interaction 2. Make the animation use a more explicit tween definition 3. Remove unused/legacy experiment for a dedicated the snap animation ![Kapture 2024-09-05 at 17 18 20](https://github.com/user-attachments/assets/f1992e51-9052-4ad6-9b01-503c6d183728) **Note: the GIF does not make this justice, it should be smooth 60 fps IRL.** Fixes #6320 --- .../canvas/controls/grid-controls.tsx | 26 +++++-------------- .../canvas/controls/new-canvas-controls.tsx | 12 ++++++--- .../select-mode/select-mode-hooks.tsx | 25 ++++++++---------- .../left-pane/roll-your-own-pane.tsx | 2 -- 4 files changed, 26 insertions(+), 39 deletions(-) diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 2a9fbc4a3aa6..492055cd6152 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -134,7 +134,6 @@ function getLabelForAxis( return gridCSSNumberToLabel(defaultEither(fromDOM, fromPropsAtIndex)) } -const SHADOW_SNAP_ANIMATION = 'shadow-snap' const GRID_RESIZE_HANDLE_CONTAINER_SIZE = 30 // px const GRID_RESIZE_HANDLE_SIZE = 15 // px @@ -648,7 +647,7 @@ export const GridControls = controlForStrategyMemoized(({ tar return maybeGridFrame }, [gridPath, metadataRef]) - useSnapAnimation({ + useCellAnimation({ disabled: anyTargetAbsolute, targetRootCell: targetRootCell, controls: controls, @@ -946,15 +945,6 @@ export const GridControls = controlForStrategyMemoized(({ tar interactionData?.drag != null && hoveringStart != null ? ( (({ tar ) }) -function useSnapAnimation(params: { +function useCellAnimation(params: { disabled: boolean gridPath: ElementPath | null shadowFrame: CanvasRectangle | null @@ -985,7 +975,6 @@ function useSnapAnimation(params: { controls: AnimationControls }) { const { gridPath, targetRootCell, controls, shadowFrame, disabled } = params - const features = useRollYourOwnFeatures() const [lastTargetRootCellId, setLastTargetRootCellId] = React.useState(targetRootCell) const [lastSnapPoint, setLastSnapPoint] = React.useState(shadowFrame) @@ -1048,12 +1037,12 @@ function useSnapAnimation(params: { x: [moveFromPoint.x - snapPoint.x, 0], y: [moveFromPoint.y - snapPoint.y, 0], }, - { duration: CELL_ANIMATION_DURATION }, + { + duration: CELL_ANIMATION_DURATION, + type: 'tween', + ease: 'easeInOut', + }, ) - - if (features.Grid.animateShadowSnap) { - void controls.start(SHADOW_SNAP_ANIMATION) - } } } setLastSnapPoint(snapPoint) @@ -1061,7 +1050,6 @@ function useSnapAnimation(params: { }, [ targetRootCell, controls, - features.Grid.animateShadowSnap, lastSnapPoint, snapPoint, animate, diff --git a/editor/src/components/canvas/controls/new-canvas-controls.tsx b/editor/src/components/canvas/controls/new-canvas-controls.tsx index 53aa788e9c00..b6cead1192f7 100644 --- a/editor/src/components/canvas/controls/new-canvas-controls.tsx +++ b/editor/src/components/canvas/controls/new-canvas-controls.tsx @@ -36,6 +36,7 @@ import type { ResolveFn } from '../../custom-code/code-file' import { useColorTheme } from '../../../uuiui' import { isDragInteractionActive, + isGridDragInteractionActive, pickSelectionEnabled, useMaybeHighlightElement, useSelectAndHover, @@ -71,10 +72,8 @@ import { useSelectionArea } from './selection-area-hooks' import { RemixSceneLabelControl } from './select-mode/remix-scene-label' import { NO_OP } from '../../../core/shared/utils' import { useIsMyProject } from '../../editor/store/collaborative-editing' -import { useStatus } from '../../../../liveblocks.config' import { MultiplayerWrapper } from '../../../utils/multiplayer-wrapper' import { MultiplayerPresence } from '../multiplayer-presence' -import { isFeatureEnabled } from '../../../utils/feature-switches' export const CanvasControlsContainerID = 'new-canvas-controls-container' @@ -170,7 +169,7 @@ export const NewCanvasControls = React.memo((props: NewCanvasControlsProps) => { canDrop: () => true, } - const [_, drop] = useDrop(dropSpec) + const [, drop] = useDrop(dropSpec) const forwardedRef = React.useCallback( (node: ConnectableElement) => { @@ -295,6 +294,7 @@ const NewCanvasControlsInner = (props: NewCanvasControlsInnerProps) => { keysPressed, componentMetadata, dragInteractionActive, + gridDragInteractionActive, selectionEnabled, textEditor, editorMode, @@ -313,6 +313,7 @@ const NewCanvasControlsInner = (props: NewCanvasControlsInnerProps) => { keysPressed: store.editor.keysPressed, componentMetadata: getMetadata(store.editor), dragInteractionActive: isDragInteractionActive(store.editor), + gridDragInteractionActive: isGridDragInteractionActive(store.editor), selectionEnabled: pickSelectionEnabled(store.editor.canvas, store.editor.keysPressed), editorMode: store.editor.mode, textEditor: store.editor.canvas.textEditor, @@ -555,7 +556,10 @@ const NewCanvasControlsInner = (props: NewCanvasControlsInnerProps) => { <> {renderHighlightControls()} {unless(dragInteractionActive, )} - + {unless( + gridDragInteractionActive, + , + )} {when( diff --git a/editor/src/components/canvas/controls/select-mode/select-mode-hooks.tsx b/editor/src/components/canvas/controls/select-mode/select-mode-hooks.tsx index 2566bd81d97b..32852623061f 100644 --- a/editor/src/components/canvas/controls/select-mode/select-mode-hooks.tsx +++ b/editor/src/components/canvas/controls/select-mode/select-mode-hooks.tsx @@ -1,21 +1,13 @@ import React from 'react' import { MetadataUtils } from '../../../../core/model/element-metadata-utils' -import { mapArrayToDictionary, mapDropNulls, uniqBy } from '../../../../core/shared/array-utils' +import { uniqBy } from '../../../../core/shared/array-utils' import type { ElementInstanceMetadataMap } from '../../../../core/shared/element-template' import type { WindowPoint } from '../../../../core/shared/math-utils' -import { - boundingRectangleArray, - CanvasPoint, - distance, - isInfinityRectangle, - point, - windowPoint, -} from '../../../../core/shared/math-utils' +import { point, windowPoint } from '../../../../core/shared/math-utils' import type { ElementPath } from '../../../../core/shared/project-file-types' import * as EP from '../../../../core/shared/element-path' -import { NO_OP, assertNever, fastForEach } from '../../../../core/shared/utils' +import { assertNever } from '../../../../core/shared/utils' import type { KeysPressed } from '../../../../utils/keyboard' -import Keyboard, { isDigit } from '../../../../utils/keyboard' import Utils from '../../../../utils/utils' import { clearHighlightedViews, @@ -49,14 +41,12 @@ import { import { Modifier } from '../../../../utils/modifiers' import { pathsEqual } from '../../../../core/shared/element-path' import type { EditorAction } from '../../../../components/editor/action-types' -import { EditorDispatch } from '../../../../components/editor/action-types' -import { EditorModes, isInsertMode, isSelectModeWithArea } from '../../../editor/editor-modes' +import { isInsertMode, isSelectModeWithArea } from '../../../editor/editor-modes' import { scheduleTextEditForNextFrame, useTextEditModeSelectAndHover, } from '../text-edit-mode/text-edit-mode-hooks' import { useDispatch } from '../../../editor/store/dispatch-context' -import { isFeatureEnabled } from '../../../../utils/feature-switches' import { useSetAtom } from 'jotai' import type { CanvasControlWithProps } from '../../../inspector/common/inspector-atoms' import { @@ -73,6 +63,13 @@ export function isDragInteractionActive(editorState: EditorState): boolean { return editorState.canvas.interactionSession?.interactionData.type === 'DRAG' } +export function isGridDragInteractionActive(editorState: EditorState): boolean { + return ( + editorState.canvas.interactionSession?.interactionData.type === 'DRAG' && + editorState.canvas.interactionSession.activeControl.type === 'GRID_CELL_HANDLE' + ) +} + export function pickSelectionEnabled( canvas: EditorState['canvas'], keysPressed: KeysPressed, diff --git a/editor/src/components/navigator/left-pane/roll-your-own-pane.tsx b/editor/src/components/navigator/left-pane/roll-your-own-pane.tsx index f574bff73575..4c6f421ae995 100644 --- a/editor/src/components/navigator/left-pane/roll-your-own-pane.tsx +++ b/editor/src/components/navigator/left-pane/roll-your-own-pane.tsx @@ -14,7 +14,6 @@ type GridFeatures = { dragVerbatim: boolean dragMagnetic: boolean dragRatio: boolean - animateShadowSnap: boolean dotgrid: boolean shadow: boolean activeGridColor: string @@ -37,7 +36,6 @@ const defaultRollYourOwnFeatures: RollYourOwnFeatures = { dragVerbatim: false, dragMagnetic: false, dragRatio: true, - animateShadowSnap: false, dotgrid: true, shadow: true, activeGridColor: '#0099ff77', From 3443ee3c74e7106eec79b3d81a6e9f4540f9081d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20K=C3=B6rmendy?= Date: Mon, 9 Sep 2024 15:14:57 +0200 Subject: [PATCH 002/272] disable flaky tests related to focusing elements (#6336) ## Description This PR disables the following flaky tests: https://github.com/concrete-utopia/utopia/blob/1eebfa60c17e988ddb29073aafd6c2c7c039780c/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx#L419 https://github.com/concrete-utopia/utopia/blob/1eebfa60c17e988ddb29073aafd6c2c7c039780c/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx#L753 Tracker issue: https://github.com/concrete-utopia/utopia/issues/6337 --- .../canvas/controls/select-mode/select-mode.spec.browser2.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx b/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx index 572d9dbfb79b..1471339b2b49 100644 --- a/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx +++ b/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx @@ -416,7 +416,7 @@ describe('Select Mode Clicking', () => { checkFocusedPath(renderResult, desiredPaths[2]) checkSelectedPaths(renderResult, [desiredPaths[2]]) }) - it('Single click and five double clicks will focus a generated Card and select the Button inside', async function (this: Mocha.Context) { + xit('Single click and five double clicks will focus a generated Card and select the Button inside', async function (this: Mocha.Context) { this.timeout(TimeoutForThisFile) // prettier-ignore const desiredPaths = createConsecutivePaths( @@ -750,7 +750,7 @@ describe('Select Mode Double Clicking With Fragments', () => { checkSelectedPaths(renderResult, [desiredPaths[1]]) }) - it('Single click and three double clicks will focus a generated Card', async () => { + xit('Single click and three double clicks will focus a generated Card', async () => { // prettier-ignore const desiredPaths = createConsecutivePaths( 'sb' + // Skipped as it's the storyboard From 3cae9651e6a84e9ee38bb7ac9a4af6587189b848 Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Mon, 9 Sep 2024 18:16:41 +0300 Subject: [PATCH 003/272] fix(grid): show gaps and cells on gap resize (#6341) **Problem:** Today when changing grid gaps the grid cells (and gap handlers that rely on them) disappear: **Fix:** Draw the cell placeholders explicitly when resizing the gaps (similar to reparent into grid). **Manual Tests:** I hereby swear that: - [X] I opened a hydrogen project and it loaded - [X] I could navigate to various routes in Preview mode --- .../strategies/set-grid-gap-strategy.tsx | 39 ++++++++++++++----- .../controls/select-mode/grid-gap-control.tsx | 2 +- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx index 52dafc7bb7dd..e284b8d75aa0 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx @@ -30,7 +30,7 @@ import { } from '../../gap-utils' import type { CanvasStrategyFactory } from '../canvas-strategies' import { onlyFitWhenDraggingThisControl } from '../canvas-strategies' -import type { InteractionCanvasState } from '../canvas-strategy-types' +import type { ControlWithProps, InteractionCanvasState } from '../canvas-strategy-types' import { controlWithProps, emptyStrategyApplicationResult, @@ -40,7 +40,10 @@ import { import type { InteractionSession } from '../interaction-state' import { colorTheme } from '../../../../uuiui' import { activeFrameTargetPath, setActiveFrames } from '../../commands/set-active-frames-command' +import type { GridGapControlProps } from '../../controls/select-mode/grid-gap-control' import { GridGapControl } from '../../controls/select-mode/grid-gap-control' +import type { GridControlsProps } from '../../controls/grid-controls' +import { GridControls } from '../../controls/grid-controls' const SetGridGapStrategyId = 'SET_GRID_GAP_STRATEGY' @@ -101,7 +104,7 @@ export const setGridGapStrategy: CanvasStrategyFactory = ( column: offsetMeasurementByDelta(gridGap.column, dragDelta.x, adjustPrecision), } - const resizeControl = controlWithProps({ + const gridGapControl = controlWithProps({ control: GridGapControl, props: { selectedElement: selectedElement, @@ -116,21 +119,39 @@ export const setGridGapStrategy: CanvasStrategyFactory = ( const maybeIndicatorProps = gridGapValueIndicatorProps(interactionSession, gridGap) - const controlsToRender = optionalMap( - (props) => [ - resizeControl, + const controlsToRender: Array< + | ControlWithProps + | ControlWithProps + | ControlWithProps + > = [gridGapControl] + + // show indicator if needed + if (maybeIndicatorProps != null) { + controlsToRender.push( controlWithProps({ control: FloatingIndicator, props: { - ...props, + ...maybeIndicatorProps, color: colorTheme.brandNeonPink.value, }, key: 'padding-value-indicator-control', show: 'visible-except-when-other-strategy-is-active', }), - ], - maybeIndicatorProps, - ) ?? [resizeControl] + ) + } + + // when the drag is ongoing, keep showing the grid cells + if (isDragOngoing(interactionSession)) { + controlsToRender.push( + controlWithProps({ + control: GridControls, + props: { targets: [selectedElement] }, + key: `set-grid-gap-strategy-controls`, + show: 'always-visible', + priority: 'bottom', + }), + ) + } return { id: SetGridGapStrategyId, diff --git a/editor/src/components/canvas/controls/select-mode/grid-gap-control.tsx b/editor/src/components/canvas/controls/select-mode/grid-gap-control.tsx index e0601c4436db..ccf0049b9037 100644 --- a/editor/src/components/canvas/controls/select-mode/grid-gap-control.tsx +++ b/editor/src/components/canvas/controls/select-mode/grid-gap-control.tsx @@ -26,7 +26,7 @@ import { isZeroSizedElement } from '../outline-utils' import { createArrayWithLength } from '../../../../core/shared/array-utils' import { useGridData } from '../grid-controls' -interface GridGapControlProps { +export interface GridGapControlProps { selectedElement: ElementPath updatedGapValueRow: CSSNumberWithRenderedValue | null updatedGapValueColumn: CSSNumberWithRenderedValue | null From 3dd1c23101ac3799ecdb3a2cce8ca3acc3feb673 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Mon, 9 Sep 2024 17:19:07 +0200 Subject: [PATCH 004/272] Offset distance indicators for grid absolute move (#6339) **Problem:** When doing an absolute move on grid child elements, it would be good to have visual indicators for the current offset from the cell the element resides in. **Fix:** Add top/left indicators during the move. The indicators will follow the target root cell, and adjust their position so they don't go over each other. If the offset is outside of the cell boundaries, additional orthogonal lines will be displayed for clarity. https://github.com/user-attachments/assets/165ffd7b-50fc-4ae5-a146-39daf22acc71 Fixes #6338 --- .../canvas/controls/grid-controls.tsx | 357 +++++++++++++++++- 1 file changed, 350 insertions(+), 7 deletions(-) diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 492055cd6152..9ac6790706d7 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -5,6 +5,7 @@ import type { AnimationControls } from 'framer-motion' import { motion, useAnimationControls } from 'framer-motion' import type { CSSProperties } from 'react' import React from 'react' +import type { Sides } from 'utopia-api/core' import type { ElementPath } from 'utopia-shared/src/types' import type { GridDimension } from '../../../components/inspector/common/css-utils' import { @@ -23,8 +24,10 @@ import { import type { CanvasPoint, CanvasRectangle } from '../../../core/shared/math-utils' import { canvasPoint, + canvasRectangle, isFiniteRectangle, isInfinityRectangle, + nullIfInfinity, pointsEqual, scaleRect, windowPoint, @@ -39,9 +42,11 @@ import { } from '../../../core/shared/optics/optic-creators' import { toFirst } from '../../../core/shared/optics/optic-utilities' import type { Optic } from '../../../core/shared/optics/optics' +import { optionalMap } from '../../../core/shared/optional-utils' import { assertNever } from '../../../core/shared/utils' import { Modifier } from '../../../utils/modifiers' import { when } from '../../../utils/react-conditionals' +import { useColorTheme, UtopiaStyles } from '../../../uuiui' import { useDispatch } from '../../editor/store/dispatch-context' import { Substores, useEditorState, useRefEditorState } from '../../editor/store/store-hook' import { useRollYourOwnFeatures } from '../../navigator/left-pane/roll-your-own-pane' @@ -52,16 +57,13 @@ import type { GridResizeEdgeProperties, } from '../canvas-strategies/interaction-state' import { - GridResizeEdges, createInteractionViaMouse, gridAxisHandle, gridCellHandle, gridResizeEdgeProperties, + GridResizeEdges, gridResizeHandle, } from '../canvas-strategies/interaction-state' -import { windowToCanvasCoordinates } from '../dom-lookup' -import { CanvasOffsetWrapper } from './canvas-offset-wrapper' -import { useColorTheme, UtopiaStyles } from '../../../uuiui' import { gridCellTargetId } from '../canvas-strategies/strategies/grid-helpers' import { resizeBoundingBoxFromSide } from '../canvas-strategies/strategies/resize-helpers' import type { EdgePosition } from '../canvas-types' @@ -72,11 +74,11 @@ import { EdgePositionRight, EdgePositionTop, } from '../canvas-types' +import { windowToCanvasCoordinates } from '../dom-lookup' +import type { Axis } from '../gap-utils' import { useCanvasAnimation } from '../ui-jsx-canvas-renderer/animation-context' +import { CanvasOffsetWrapper } from './canvas-offset-wrapper' import { CanvasLabel } from './select-mode/controls-common' -import { optionalMap } from '../../../core/shared/optional-utils' -import type { Sides } from 'utopia-api/core' -import type { Axis } from '../gap-utils' import { useMaybeHighlightElement } from './select-mode/select-mode-hooks' const CELL_ANIMATION_DURATION = 0.15 // seconds @@ -962,11 +964,343 @@ export const GridControls = controlForStrategyMemoized(({ tar }} /> ) : null} + ) }) +const MIN_INDICATORS_DISTANCE = 32 // px + +const AbsoluteDistanceIndicators = React.memo( + (props: { targetRootCell: GridCellCoordinates | null }) => { + const colorTheme = useColorTheme() + + const cellFrame = useEditorState( + Substores.metadata, + (store) => { + if (store.editor.selectedViews.length !== 1) { + return null + } + + const meta = MetadataUtils.findElementByElementPath( + store.editor.jsxMetadata, + store.editor.selectedViews[0], + ) + if (!MetadataUtils.isPositionAbsolute(meta)) { + return null + } + + return nullIfInfinity(meta?.globalFrame) + }, + 'AbsoluteDistanceIndicators cellFrame', + ) + const canvasScale = useEditorState( + Substores.canvasOffset, + (store) => store.editor.canvas.scale, + 'AbsoluteDistanceIndicators canvasScale', + ) + + const canvasOffset = useEditorState( + Substores.canvasOffset, + (store) => store.editor.canvas.roundedCanvasOffset, + 'AbsoluteDistanceIndicators canvasOffset', + ) + + const targetCellBoundingBox = React.useMemo(() => { + if (props.targetRootCell == null) { + return null + } + const element = getGridPlaceholderDomElementFromCoordinates(props.targetRootCell) + const boundingBox = element?.getBoundingClientRect() + if (boundingBox == null) { + return null + } + + const canvasOrigin = windowToCanvasCoordinates( + canvasScale, + canvasOffset, + windowPoint({ x: boundingBox.left, y: boundingBox.top }), + ).canvasPositionRounded + const canvasRect = canvasRectangle({ + x: canvasOrigin.x, + y: canvasOrigin.y, + width: boundingBox.width * canvasScale, + height: boundingBox.height * canvasScale, + }) + + return canvasRect + }, [props.targetRootCell, canvasScale, canvasOffset]) + + const distanceTop = + targetCellBoundingBox == null || cellFrame == null ? 0 : cellFrame.y - targetCellBoundingBox.y + + const distanceLeft = + targetCellBoundingBox == null || cellFrame == null ? 0 : cellFrame.x - targetCellBoundingBox.x + + const positioning = React.useMemo(() => { + if (cellFrame == null || targetCellBoundingBox == null) { + return null + } + + function position( + wantedCoord: 'x' | 'y', + cell: CanvasRectangle, + root: CanvasRectangle, + dominantDistance: number, + otherDistance: number, + ): { left: number; top: number } { + const otherCoord = wantedCoord === 'x' ? 'y' : 'x' + const dimension = wantedCoord === 'x' ? 'width' : 'height' + const dominant = + cell[wantedCoord] < root[wantedCoord] || + dominantDistance < MIN_INDICATORS_DISTANCE || + otherDistance < 0 + ? root[wantedCoord] + root[dimension] / 2 + : Math.max(root[wantedCoord], cell[wantedCoord]) + const other = otherDistance < 0 ? cell[otherCoord] : root[otherCoord] + if (wantedCoord === 'x') { + return { + left: dominant, + top: other, + } + } else { + return { + left: other, + top: dominant, + } + } + } + + function compensationNegative( + wantedCoord: 'x' | 'y', + cell: CanvasRectangle, + root: CanvasRectangle, + dist: number, + ): { width: number; height: number; left: number; top: number } | null { + const otherCoord = wantedCoord === 'x' ? 'y' : 'x' + const dimension = wantedCoord === 'x' ? 'width' : 'height' + + const shouldCompensate = + dist < 0 && cell[wantedCoord] > root[wantedCoord] + root[dimension] / 2 + if (!shouldCompensate) { + return null + } + + const size = Math.abs(root[wantedCoord] + root[dimension] / 2 - cell[wantedCoord]) + const dominant = root[wantedCoord] + root[dimension] / 2 + const other = cell[otherCoord] + + return wantedCoord === 'x' + ? { + width: size, + height: 1, + top: other, + left: dominant, + } + : { + width: 1, + height: size, + top: dominant, + left: other, + } + } + + function compensationPositive( + wantedCoord: 'x' | 'y', + cell: CanvasRectangle, + root: CanvasRectangle, + dist: number, + ): { width: number; height: number; left: number; top: number } | null { + const otherCoord = wantedCoord === 'x' ? 'y' : 'x' + const dimension = wantedCoord === 'x' ? 'width' : 'height' + + const shouldCompensate = dist > 0 && cell[wantedCoord] > root[wantedCoord] + root[dimension] + if (!shouldCompensate) { + return null + } + + const size = Math.abs(root[wantedCoord] + root[dimension] / 2 - cell[wantedCoord]) + const other = root[otherCoord] + const dominant = root[wantedCoord] + root[dimension] / 2 + + return wantedCoord === 'x' + ? { + width: size, + height: 1, + top: other, + left: dominant, + } + : { + height: size, + width: 1, + left: other, + top: dominant, + } + } + + const topIndicator = { + ...position('x', cellFrame, targetCellBoundingBox, distanceLeft, distanceTop), + compensateNegative: compensationNegative( + 'x', + cellFrame, + targetCellBoundingBox, + distanceTop, + ), + compensatePositive: compensationPositive( + 'x', + cellFrame, + targetCellBoundingBox, + distanceTop, + ), + } + + const leftIndicator = { + ...position('y', cellFrame, targetCellBoundingBox, distanceLeft, distanceLeft), + compensateNegative: compensationNegative( + 'y', + cellFrame, + targetCellBoundingBox, + distanceLeft, + ), + compensatePositive: compensationPositive( + 'y', + cellFrame, + targetCellBoundingBox, + distanceLeft, + ), + } + + return { topIndicator, leftIndicator } + }, [cellFrame, targetCellBoundingBox, distanceLeft, distanceTop]) + + if (targetCellBoundingBox == null || cellFrame == null || positioning == null) { + return null + } + + const backgroundColor = colorTheme.brandNeonPink.value + const dashedBorder = `1px dashed ${backgroundColor}` + + return ( + + {/* top distance */} + +
+ + {distanceTop} + +
+ {/* compensate */} + {positioning.topIndicator.compensateNegative != null ? ( +
+ ) : null} + {positioning.topIndicator.compensatePositive != null ? ( +
+ ) : null} + + + {/* left distance */} + +
+ + {distanceLeft} + +
+ {/* compensate */} + {positioning.leftIndicator.compensateNegative != null ? ( +
+ ) : null} + {positioning.leftIndicator.compensatePositive != null ? ( +
+ ) : null} + + + ) + }, +) + function useCellAnimation(params: { disabled: boolean gridPath: ElementPath | null @@ -1356,4 +1690,13 @@ export function getGridPlaceholderDomElement(elementPath: ElementPath): HTMLElem return document.getElementById(gridKeyFromPath(elementPath)) } +export function getGridPlaceholderDomElementFromCoordinates(params: { + row: number + column: number +}): HTMLElement | null { + return document.querySelector( + `[data-grid-row="${params.row}"]` + `[data-grid-column="${params.column}"]`, + ) +} + const gridPlaceholderBorder = (color: string) => `2px solid ${color}` From b2994d21bf470eef5fae9c3b4b654c4746169b9a Mon Sep 17 00:00:00 2001 From: RheeseyB <1044774+Rheeseyb@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:32:09 +0100 Subject: [PATCH 005/272] Fix an issue with updatePackageJsonInEditorState (#6333) **Problem:** `updatePackageJsonInEditorState` was providing incorrect arguments to the `codeFile` factory function when updating the package.json file. **Fix:** Fix it. **Side note:** IMO the `codeFile` function should always be `RevisionsState.CodeAheadButPleaseTellVSCodeAboutIt` by default, since it is typically used as a convenient way to create a new `TextFile` from the design side of Utopia. However, I tried making that change and it broke far too much of the editor, somehow resulting in the project contents being entirely wiped, so I'd rather just leave it be for the moment. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode Fixes #6328 --- editor/src/components/editor/store/editor-state.ts | 5 ++++- editor/src/components/editor/store/editor-update.spec.tsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/editor/src/components/editor/store/editor-state.ts b/editor/src/components/editor/store/editor-state.ts index b874154f03d2..aa3231f356da 100644 --- a/editor/src/components/editor/store/editor-state.ts +++ b/editor/src/components/editor/store/editor-state.ts @@ -3278,14 +3278,17 @@ export function updatePackageJsonInEditorState( // There is a package.json file, we should update it. updatedPackageJsonFile = codeFile( transformPackageJson(packageJsonFile.fileContents.code), - RevisionsState.CodeAhead, + null, packageJsonFile.versionNumber + 1, + RevisionsState.CodeAheadButPleaseTellVSCodeAboutIt, ) } else { // There is something else called package.json, we should bulldoze over it. updatedPackageJsonFile = codeFile( transformPackageJson(JSON.stringify(DefaultPackageJson)), null, + 0, + RevisionsState.CodeAheadButPleaseTellVSCodeAboutIt, ) } } diff --git a/editor/src/components/editor/store/editor-update.spec.tsx b/editor/src/components/editor/store/editor-update.spec.tsx index 62d35e4ec115..855542efe4d1 100644 --- a/editor/src/components/editor/store/editor-update.spec.tsx +++ b/editor/src/components/editor/store/editor-update.spec.tsx @@ -1030,7 +1030,7 @@ describe('updating package.json', () => { "parsed": Object { "type": "UNPARSED", }, - "revisionsState": "CODE_AHEAD", + "revisionsState": "CODE_AHEAD_BUT_PLEASE_TELL_VSCODE_ABOUT_IT", } `) } From 55c5ab3214393427c60b4a9a39a8422c47755e0a Mon Sep 17 00:00:00 2001 From: RheeseyB <1044774+Rheeseyb@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:32:24 +0100 Subject: [PATCH 006/272] Send message to utopia when a file is saved in vs code (#6334) **Problem:** When saving a file in the code editor it was still marked as unsaved in Utopia. **Fix:** This was just because we weren't informing Utopia that the file had been saved, so it was simply a case of sending the right message when the file is saved. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- utopia-vscode-extension/src/utopia-fs.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utopia-vscode-extension/src/utopia-fs.ts b/utopia-vscode-extension/src/utopia-fs.ts index c03971029194..fb3592783ed5 100644 --- a/utopia-vscode-extension/src/utopia-fs.ts +++ b/utopia-vscode-extension/src/utopia-fs.ts @@ -50,7 +50,7 @@ import { isNotDirectoryError, pathIsFile, } from './in-mem-fs' -import { appendToPath, dirname, vsCodeFileDelete } from 'utopia-vscode-common' +import { appendToPath, dirname, vsCodeFileChange, vsCodeFileDelete } from 'utopia-vscode-common' import type { ProjectFile } from 'utopia-vscode-common' import { addSchemeToPath, allPathsUpToPath } from './path-utils' @@ -219,6 +219,7 @@ export class UtopiaFSExtension const path = uri.path createDirectory(path) this.notifyFileCreated(path) + // TODO Add a message for when a directory is created / renamed } readFile(uri: Uri): Uint8Array { @@ -243,6 +244,9 @@ export class UtopiaFSExtension } else { this.notifyFileCreated(path) } + + const updatedFile = readFileAsUTF8(path) + commands.executeCommand('utopia.toUtopiaMessage', vsCodeFileChange(path, updatedFile)) } ensureDirectoryExists(pathToEnsure: string) { From ac76e57f3432964ddcbefbac2b1403efe4931c53 Mon Sep 17 00:00:00 2001 From: RheeseyB <1044774+Rheeseyb@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:56:27 +0100 Subject: [PATCH 007/272] Disable another failing clicking test (#6343) Follow up to #6336 with another failing test --- .../canvas/controls/select-mode/select-mode.spec.browser2.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx b/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx index 1471339b2b49..aba628750c29 100644 --- a/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx +++ b/editor/src/components/canvas/controls/select-mode/select-mode.spec.browser2.tsx @@ -325,7 +325,7 @@ describe('Select Mode Clicking', () => { checkSelectedPaths(renderResult, [desiredPath]) }) - it('Single click and then double click to select Button on a Card Scene Root', async () => { + xit('Single click and then double click to select Button on a Card Scene Root', async () => { // prettier-ignore const desiredPaths = createConsecutivePaths( 'sb' + // Skipped as it's the storyboard @@ -703,7 +703,7 @@ describe('Select Mode Double Clicking With Fragments', () => { checkSelectedPaths(renderResult, [desiredPath]) }) - it('Single click and then double click to select Button on a Card Scene Root', async () => { + xit('Single click and then double click to select Button on a Card Scene Root', async () => { FOR_TESTS_setNextGeneratedUids([ 'cardlistfragment', 'manuallistfragment', From 74db368ff208e3a6e44a5d85c769784a33161f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20K=C3=B6rmendy?= Date: Tue, 10 Sep 2024 14:20:17 +0200 Subject: [PATCH 008/272] x for grids (#6332) https://github.com/user-attachments/assets/7627f89e-c87b-4246-9ac5-1f70ca4e254d ## Problem The x shortcut isn't aware of grids ## Fix Special case grid elements in the x shortcut. ### How it works If an element is a grid child and it's absolute positioned (for example after a reparent or drawing), pressing x removes the `position: absolute`, absolute positioning prop, and any explicit width/height props on the element, and sets `gridRow`/`gridColumn`/`gridRowStart`/gridRowEnd`/`gridColumnStart`/gridColumnEnd` in way that snaps the element into the grid cells it occupies. When an element is a non-position-absolute grid child, and x is pressed, `position: absolute` is set, the element is sized to its visual dimensions with `width`/`height`, and `top: 0` / `left: 0` is added. Making it possible to absolute resize the element after this is left to a follow-up PR. ### Details - Due to a circular dependency, a lot of grid cell related code was factored out into `grid-cell-utils.ts` --- .../canvas-strategy-types.ts | 2 +- .../strategies/grid-cell-bounds.ts | 139 ++++++++++ .../strategies/grid-helpers.ts | 131 +-------- .../grid-rearrange-keyboard-strategy.ts | 3 +- ...-rearrange-move-strategy.spec.browser2.tsx | 2 +- .../strategies/grid-reparent-strategy.tsx | 2 +- ...-resize-element-strategy.spec.browser2.tsx | 3 +- .../grid-resize-element-strategy.ts | 3 +- .../canvas/controls/grid-controls.tsx | 9 +- .../components/editor/global-shortcuts.tsx | 1 + .../editor/shortcuts.spec.browser2.tsx | 252 ++++++++++++++++++ .../components/inspector/inspector-common.ts | 136 +++++++++- 12 files changed, 541 insertions(+), 142 deletions(-) create mode 100644 editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts diff --git a/editor/src/components/canvas/canvas-strategies/canvas-strategy-types.ts b/editor/src/components/canvas/canvas-strategies/canvas-strategy-types.ts index e1809f458ea4..dff0105a300e 100644 --- a/editor/src/components/canvas/canvas-strategies/canvas-strategy-types.ts +++ b/editor/src/components/canvas/canvas-strategies/canvas-strategy-types.ts @@ -10,9 +10,9 @@ import type { InsertionSubject } from '../../editor/editor-modes' import type { AllElementProps } from '../../editor/store/editor-state' import type { CanvasCommand } from '../commands/commands' import type { ActiveFrameAction } from '../commands/set-active-frames-command' -import type { GridCellCoordinates } from '../controls/grid-controls' import type { StrategyApplicationStatus } from './interaction-state' import type { TargetGridCellData } from './strategies/grid-helpers' +import type { GridCellCoordinates } from './strategies/grid-cell-bounds' // TODO: fill this in, maybe make it an ADT for different strategies export interface CustomStrategyState { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts new file mode 100644 index 000000000000..122fd4657bb6 --- /dev/null +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts @@ -0,0 +1,139 @@ +import type { ElementPath } from 'utopia-shared/src/types' +import type { ElementInstanceMetadata } from '../../../../core/shared/element-template' +import type { CanvasVector, WindowPoint, WindowRectangle } from '../../../../core/shared/math-utils' +import { + isInfinityRectangle, + offsetPoint, + rectContainsPoint, + windowPoint, + windowRectangle, +} from '../../../../core/shared/math-utils' +import { canvasPointToWindowPoint } from '../../dom-lookup' +import * as EP from '../../../../core/shared/element-path' + +export type GridCellCoordinates = { row: number; column: number } + +export function gridCellCoordinates(row: number, column: number): GridCellCoordinates { + return { row: row, column: column } +} + +const gridCellTargetIdPrefix = 'grid-cell-target-' + +export function gridCellTargetId( + gridElementPath: ElementPath, + row: number, + column: number, +): string { + return gridCellTargetIdPrefix + `${EP.toString(gridElementPath)}-${row}-${column}` +} + +export function getGridCellUnderMouse(mousePoint: WindowPoint) { + return getGridCellAtPoint(mousePoint, false) +} + +export function getGridCellUnderMouseRecursive(mousePoint: WindowPoint) { + return getGridCellAtPoint(mousePoint, true) +} + +function isGridCellTargetId(id: string): boolean { + return id.startsWith(gridCellTargetIdPrefix) +} + +export function getGridCellAtPoint( + point: WindowPoint, + duplicating: boolean, +): { id: string; coordinates: GridCellCoordinates; cellWindowRectangle: WindowRectangle } | null { + function maybeRecursivelyFindCellAtPoint( + elements: Element[], + ): { element: Element; cellWindowRectangle: WindowRectangle } | null { + // If this used during duplication, the canvas controls will be in the way and we need to traverse the children too. + for (const element of elements) { + if (isGridCellTargetId(element.id)) { + const domRect = element.getBoundingClientRect() + const windowRect = windowRectangle(domRect) + if (rectContainsPoint(windowRect, point)) { + return { element: element, cellWindowRectangle: windowRect } + } + } + + if (duplicating) { + const child = maybeRecursivelyFindCellAtPoint(Array.from(element.children)) + if (child != null) { + return child + } + } + } + + return null + } + + const cellUnderMouse = maybeRecursivelyFindCellAtPoint( + document.elementsFromPoint(point.x, point.y), + ) + if (cellUnderMouse == null) { + return null + } + + const { element, cellWindowRectangle } = cellUnderMouse + const row = element.getAttribute('data-grid-row') + const column = element.getAttribute('data-grid-column') + + return { + id: element.id, + cellWindowRectangle: cellWindowRectangle, + coordinates: gridCellCoordinates( + row == null ? 0 : parseInt(row), + column == null ? 0 : parseInt(column), + ), + } +} + +const GRID_BOUNDS_TOLERANCE = 5 // px + +export function getGridCellBoundsFromCanvas( + cell: ElementInstanceMetadata, + canvasScale: number, + canvasOffset: CanvasVector, +) { + const cellFrame = cell.globalFrame + if (cellFrame == null || isInfinityRectangle(cellFrame)) { + return null + } + + const canvasFrameWidth = cellFrame.width * canvasScale + const canvasFrameHeight = cellFrame.height * canvasScale + + const cellOriginPoint = offsetPoint( + canvasPointToWindowPoint(cellFrame, canvasScale, canvasOffset), + windowPoint({ x: GRID_BOUNDS_TOLERANCE, y: GRID_BOUNDS_TOLERANCE }), + ) + const cellOrigin = getGridCellAtPoint(cellOriginPoint, true) + if (cellOrigin == null) { + return null + } + + const cellEndPoint = offsetPoint( + cellOriginPoint, + windowPoint({ + x: canvasFrameWidth - GRID_BOUNDS_TOLERANCE, + y: canvasFrameHeight - GRID_BOUNDS_TOLERANCE, + }), + ) + const cellEnd = getGridCellAtPoint(cellEndPoint, true) + if (cellEnd == null) { + return null + } + + const cellOriginCoords = cellOrigin.coordinates + const cellEndCoords = cellEnd.coordinates + + const cellWidth = cellEndCoords.column - cellOriginCoords.column + 1 + const cellHeight = cellEndCoords.row - cellOriginCoords.row + 1 + + return { + column: cellOriginCoords.column, + row: cellOriginCoords.row, + width: cellWidth, + height: cellHeight, + } +} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index f1d8f4a573e5..b8c0839bd4c9 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -13,10 +13,8 @@ import { canvasPoint, isInfinityRectangle, offsetPoint, - rectContainsPoint, scaleVector, windowPoint, - windowRectangle, windowVector, type WindowPoint, } from '../../../../core/shared/math-utils' @@ -26,83 +24,16 @@ import { setProperty } from '../../commands/set-property-command' import { canvasPointToWindowPoint } from '../../dom-lookup' import type { DragInteractionData } from '../interaction-state' import type { GridCustomStrategyState, InteractionCanvasState } from '../canvas-strategy-types' -import type { GridCellCoordinates } from '../../controls/grid-controls' -import { gridCellCoordinates } from '../../controls/grid-controls' import * as EP from '../../../../core/shared/element-path' import { deleteProperties } from '../../commands/delete-properties-command' import { cssNumber, isCSSKeyword } from '../../../inspector/common/css-utils' import { setCssLengthProperty } from '../../commands/set-css-length-command' - -export function getGridCellUnderMouse(mousePoint: WindowPoint) { - return getGridCellAtPoint(mousePoint, false) -} - -function getGridCellUnderMouseRecursive(mousePoint: WindowPoint) { - return getGridCellAtPoint(mousePoint, true) -} - -const gridCellTargetIdPrefix = 'grid-cell-target-' - -export function gridCellTargetId( - gridElementPath: ElementPath, - row: number, - column: number, -): string { - return gridCellTargetIdPrefix + `${EP.toString(gridElementPath)}-${row}-${column}` -} - -function isGridCellTargetId(id: string): boolean { - return id.startsWith(gridCellTargetIdPrefix) -} - -export function getGridCellAtPoint( - point: WindowPoint, - duplicating: boolean, -): { id: string; coordinates: GridCellCoordinates; cellWindowRectangle: WindowRectangle } | null { - function maybeRecursivelyFindCellAtPoint( - elements: Element[], - ): { element: Element; cellWindowRectangle: WindowRectangle } | null { - // If this used during duplication, the canvas controls will be in the way and we need to traverse the children too. - for (const element of elements) { - if (isGridCellTargetId(element.id)) { - const domRect = element.getBoundingClientRect() - const windowRect = windowRectangle(domRect) - if (rectContainsPoint(windowRect, point)) { - return { element: element, cellWindowRectangle: windowRect } - } - } - - if (duplicating) { - const child = maybeRecursivelyFindCellAtPoint(Array.from(element.children)) - if (child != null) { - return child - } - } - } - - return null - } - - const cellUnderMouse = maybeRecursivelyFindCellAtPoint( - document.elementsFromPoint(point.x, point.y), - ) - if (cellUnderMouse == null) { - return null - } - - const { element, cellWindowRectangle } = cellUnderMouse - const row = element.getAttribute('data-grid-row') - const column = element.getAttribute('data-grid-column') - - return { - id: element.id, - cellWindowRectangle: cellWindowRectangle, - coordinates: gridCellCoordinates( - row == null ? 0 : parseInt(row), - column == null ? 0 : parseInt(column), - ), - } -} +import type { GridCellCoordinates } from './grid-cell-bounds' +import { + getGridCellUnderMouse, + getGridCellUnderMouseRecursive, + gridCellCoordinates, +} from './grid-cell-bounds' export function runGridRearrangeMove( targetElement: ElementPath, @@ -501,53 +432,3 @@ function gridChildAbsoluteMoveCommands( ), ] } - -const GRID_BOUNDS_TOLERANCE = 5 // px - -export function getGridCellBoundsFromCanvas( - cell: ElementInstanceMetadata, - canvasScale: number, - canvasOffset: CanvasVector, -) { - const cellFrame = cell.globalFrame - if (cellFrame == null || isInfinityRectangle(cellFrame)) { - return null - } - - const canvasFrameWidth = cellFrame.width * canvasScale - const canvasFrameHeight = cellFrame.height * canvasScale - - const cellOriginPoint = offsetPoint( - canvasPointToWindowPoint(cellFrame, canvasScale, canvasOffset), - windowPoint({ x: GRID_BOUNDS_TOLERANCE, y: GRID_BOUNDS_TOLERANCE }), - ) - const cellOrigin = getGridCellAtPoint(cellOriginPoint, true) - if (cellOrigin == null) { - return null - } - - const cellEndPoint = offsetPoint( - cellOriginPoint, - windowPoint({ - x: canvasFrameWidth - GRID_BOUNDS_TOLERANCE, - y: canvasFrameHeight - GRID_BOUNDS_TOLERANCE, - }), - ) - const cellEnd = getGridCellAtPoint(cellEndPoint, true) - if (cellEnd == null) { - return null - } - - const cellOriginCoords = cellOrigin.coordinates - const cellEndCoords = cellEnd.coordinates - - const cellWidth = cellEndCoords.column - cellOriginCoords.column + 1 - const cellHeight = cellEndCoords.row - cellOriginCoords.row + 1 - - return { - column: cellOriginCoords.column, - row: cellOriginCoords.row, - width: cellWidth, - height: cellHeight, - } -} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts index a8254b819c27..b378a9702ad6 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts @@ -14,7 +14,8 @@ import { strategyApplicationResult, } from '../canvas-strategy-types' import type { InteractionSession } from '../interaction-state' -import { getGridCellBoundsFromCanvas, setGridPropsCommands } from './grid-helpers' +import { setGridPropsCommands } from './grid-helpers' +import { getGridCellBoundsFromCanvas } from './grid-cell-bounds' import { accumulatePresses } from './shared-keyboard-strategy-helpers' export function gridRearrangeResizeKeyboardStrategy( diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx index 6326d5d74cb2..212b6c8cb2df 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx @@ -11,7 +11,7 @@ import { GridCellTestId } from '../../controls/grid-controls' import { mouseDragFromPointToPoint } from '../../event-helpers.test-utils' import type { EditorRenderResult } from '../../ui-jsx.test-utils' import { renderTestEditorWithCode } from '../../ui-jsx.test-utils' -import { gridCellTargetId } from './grid-helpers' +import { gridCellTargetId } from './grid-cell-bounds' describe('grid rearrange move strategy', () => { it('can rearrange elements on a grid', async () => { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx index 4c9a08b22bf3..079640425291 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx @@ -34,7 +34,6 @@ import { flattenSelection } from './shared-move-strategies-helpers' import type { CanvasRectangle, CanvasVector } from '../../../../core/shared/math-utils' import { canvasVector, isInfinityRectangle, offsetPoint } from '../../../../core/shared/math-utils' import { showGridControls } from '../../commands/show-grid-controls-command' -import type { GridCellCoordinates } from '../../controls/grid-controls' import { GridControls } from '../../controls/grid-controls' import { gridPositionValue, @@ -49,6 +48,7 @@ import { removeAbsolutePositioningProps } from './reparent-helpers/reparent-prop import { canvasPointToWindowPoint } from '../../dom-lookup' import type { TargetGridCellData } from './grid-helpers' import { getTargetCell, setGridPropsCommands } from './grid-helpers' +import type { GridCellCoordinates } from './grid-cell-bounds' export function gridReparentStrategy( reparentTarget: ReparentTarget, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx index 269d2c956972..85928426360a 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx @@ -14,8 +14,7 @@ import { mouseDragFromPointToPoint } from '../../event-helpers.test-utils' import type { EditorRenderResult } from '../../ui-jsx.test-utils' import { renderTestEditorWithCode } from '../../ui-jsx.test-utils' import type { GridResizeEdge } from '../interaction-state' -import { gridCellTargetId } from './grid-helpers' -import { wait } from '../../../../core/model/performance-scripts' +import { gridCellTargetId } from './grid-cell-bounds' async function runCellResizeTest( editor: EditorRenderResult, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts index a855235f8f39..0c1e4127742c 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts @@ -15,8 +15,9 @@ import { strategyApplicationResult, } from '../canvas-strategy-types' import type { InteractionSession } from '../interaction-state' +import { getGridCellUnderMouse } from './grid-cell-bounds' import type { TargetGridCellData } from './grid-helpers' -import { getGridCellUnderMouse, setGridPropsCommands } from './grid-helpers' +import { setGridPropsCommands } from './grid-helpers' export const gridResizeElementStrategy: CanvasStrategyFactory = ( canvasState: InteractionCanvasState, diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 9ac6790706d7..077b729a6d45 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -64,7 +64,6 @@ import { GridResizeEdges, gridResizeHandle, } from '../canvas-strategies/interaction-state' -import { gridCellTargetId } from '../canvas-strategies/strategies/grid-helpers' import { resizeBoundingBoxFromSide } from '../canvas-strategies/strategies/resize-helpers' import type { EdgePosition } from '../canvas-types' import { @@ -80,17 +79,13 @@ import { useCanvasAnimation } from '../ui-jsx-canvas-renderer/animation-context' import { CanvasOffsetWrapper } from './canvas-offset-wrapper' import { CanvasLabel } from './select-mode/controls-common' import { useMaybeHighlightElement } from './select-mode/select-mode-hooks' +import type { GridCellCoordinates } from '../canvas-strategies/strategies/grid-cell-bounds' +import { gridCellTargetId } from '../canvas-strategies/strategies/grid-cell-bounds' const CELL_ANIMATION_DURATION = 0.15 // seconds export const GridCellTestId = (elementPath: ElementPath) => `grid-cell-${EP.toString(elementPath)}` -export type GridCellCoordinates = { row: number; column: number } - -export function gridCellCoordinates(row: number, column: number): GridCellCoordinates { - return { row: row, column: column } -} - function getCellsCount(template: GridAutoOrTemplateBase | null): number { if (template == null) { return 0 diff --git a/editor/src/components/editor/global-shortcuts.tsx b/editor/src/components/editor/global-shortcuts.tsx index 2c6c4e21bbe1..ef19ed9c7287 100644 --- a/editor/src/components/editor/global-shortcuts.tsx +++ b/editor/src/components/editor/global-shortcuts.tsx @@ -963,6 +963,7 @@ export function handleKeyDown( editor.allElementProps, editor.elementPathTree, editor.selectedViews, + { scale: editor.canvas.scale, offset: editor.canvas.realCanvasOffset }, ) if (commands.length === 0) { diff --git a/editor/src/components/editor/shortcuts.spec.browser2.tsx b/editor/src/components/editor/shortcuts.spec.browser2.tsx index f52647bf152a..0e1342631ae7 100644 --- a/editor/src/components/editor/shortcuts.spec.browser2.tsx +++ b/editor/src/components/editor/shortcuts.spec.browser2.tsx @@ -259,6 +259,258 @@ describe('shortcuts', () => { canvasRectangle({ x: 186, y: 34, width: 94, height: 55 }), ) }) + + describe('inside grid', () => { + it('can place element spanning a single cell into the grid and take it out', async () => { + const editor = await renderTestEditorWithCode( + `import { Scene, Storyboard } from 'utopia-api' + +export var storyboard = ( + + +
+
+
+ + +) +`, + 'await-first-dom-report', + ) + + await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/child')]) + await pressKey('x') + + { + const { position, gridRow, gridColumn, width, height } = + editor.renderedDOM.getByTestId('child').style + expect({ position, gridRow, gridColumn, width, height }).toEqual({ + gridColumn: '3', + gridRow: '3', + height: '', + position: '', + width: '', + }) + } + + await pressKey('x') // convert it back to absolute + + { + const { position, gridRow, gridColumn, width, height, top, left } = + editor.renderedDOM.getByTestId('child').style + expect({ position, gridRow, gridColumn, width, height, top, left }).toEqual({ + gridColumn: '3', + gridRow: '3', + height: '90.5px', + left: '0px', + position: 'absolute', + top: '0px', + width: '104px', + }) + } + }) + + it('can place element spanning multiple grid cells into the grid and take it out', async () => { + const editor = await renderTestEditorWithCode( + `import { Scene, Storyboard } from 'utopia-api' + +export var storyboard = ( + + +
+
+
+ + +) +`, + 'await-first-dom-report', + ) + + await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/child')]) + await pressKey('x') + + { + const { position, gridRow, gridColumn, width, height } = + editor.renderedDOM.getByTestId('child').style + expect({ position, gridRow, gridColumn, width, height }).toEqual({ + gridColumn: '2 / 5', + gridRow: '2 / 4', + height: '', + position: '', + width: '', + }) + } + + await pressKey('x') // convert it back to absolute + + { + const { position, gridRow, gridColumn, width, height, top, left } = + editor.renderedDOM.getByTestId('child').style + expect({ position, gridRow, gridColumn, width, height, top, left }).toEqual({ + gridColumn: '2', + gridRow: '2', + height: '183px', + left: '0px', + position: 'absolute', + top: '0px', + width: '315.5px', + }) + } + }) + + it('can place element with no grid positioning props set', async () => { + const editor = await renderTestEditorWithCode( + `import { Scene, Storyboard } from 'utopia-api' + +export var storyboard = ( + + +
+
+
+ + +) +`, + 'await-first-dom-report', + ) + + await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/child')]) + await pressKey('x') + + { + const { position, gridRow, gridColumn, width, height } = + editor.renderedDOM.getByTestId('child').style + expect({ position, gridRow, gridColumn, width, height }).toEqual({ + gridColumn: '2 / 4', + gridRow: '2 / 4', + height: '', + position: '', + width: '', + }) + } + }) + }) }) describe('jump to parent', () => { diff --git a/editor/src/components/inspector/inspector-common.ts b/editor/src/components/inspector/inspector-common.ts index 0f48cbb3ff53..69c4c92638b6 100644 --- a/editor/src/components/inspector/inspector-common.ts +++ b/editor/src/components/inspector/inspector-common.ts @@ -13,7 +13,6 @@ import type { ElementInstanceMetadata, ElementInstanceMetadataMap, JSXAttributes, - JSXElement, } from '../../core/shared/element-template' import { isJSXElement, @@ -35,7 +34,12 @@ import { optionalMap } from '../../core/shared/optional-utils' import type { CSSProperties } from 'react' import type { CanvasCommand } from '../canvas/commands/commands' import { deleteProperties } from '../canvas/commands/delete-properties-command' -import { setProperty } from '../canvas/commands/set-property-command' +import { + propertyToDelete, + propertyToSet, + setProperty, + updateBulkProperties, +} from '../canvas/commands/set-property-command' import { addContainLayoutIfNeeded } from '../canvas/commands/add-contain-layout-if-needed-command' import { setCssLengthProperty, @@ -47,7 +51,7 @@ import { setPropHugAbsoluteStrategies, } from './inspector-strategies/inspector-strategies' import { commandsForFirstApplicableStrategy } from './inspector-strategies/inspector-strategy' -import type { Size } from '../../core/shared/math-utils' +import type { CanvasVector, Size } from '../../core/shared/math-utils' import { isFiniteRectangle, isInfinityRectangle, @@ -76,6 +80,7 @@ import { fixedSizeDimensionHandlingText } from '../text-editor/text-handling' import { convertToAbsolute } from '../canvas/commands/convert-to-absolute-command' import { hugPropertiesFromStyleMap } from '../../core/shared/dom-utils' import { setHugContentForAxis } from './inspector-strategies/hug-contents-strategy' +import { getGridCellBoundsFromCanvas } from '../canvas/canvas-strategies/strategies/grid-cell-bounds' export type StartCenterEnd = 'flex-start' | 'center' | 'flex-end' @@ -1216,6 +1221,7 @@ export function toggleAbsolutePositioningCommands( allElementProps: AllElementProps, elementPathTree: ElementPathTrees, selectedViews: Array, + canvasContext: { scale: number; offset: CanvasVector }, ): Array { const commands = selectedViews.flatMap((elementPath) => { const maybeGroupConversionCommands = groupConversionCommands( @@ -1229,6 +1235,16 @@ export function toggleAbsolutePositioningCommands( return maybeGroupConversionCommands } + const maybeGridElementConversionCommands = gridChildAbsolutePositionConversionCommands( + jsxMetadata, + elementPathTree, + elementPath, + canvasContext, + ) + if (maybeGridElementConversionCommands != null) { + return maybeGridElementConversionCommands + } + const element = MetadataUtils.findElementByElementPath(jsxMetadata, elementPath) if (element == null) { return [] @@ -1401,3 +1417,117 @@ export function getConstraintsIncludingImplicitForElement( export function isHuggingParent(element: ElementInstanceMetadata, property: 'width' | 'height') { return element.specialSizeMeasurements.computedHugProperty[property] != null } + +interface ContainedGridPositioning { + type: 'contained' + gridRow: number + gridColumn: number +} + +interface SpanningGridPositioning { + type: 'span' + gridRowStart: number + gridRowEnd: number + gridColumnStart: number + gridColumnEnd: number +} + +type DetectedGridPositioning = ContainedGridPositioning | SpanningGridPositioning + +function getGridElementBounds( + cell: ElementInstanceMetadata, + canvasContext: { scale: number; offset: CanvasVector }, +): DetectedGridPositioning | null { + const initialCellBounds = getGridCellBoundsFromCanvas( + cell, + canvasContext.scale, + canvasContext.offset, + ) + + if (initialCellBounds == null) { + return null + } + + if (initialCellBounds.height > 1 || initialCellBounds.width > 1) { + return { + type: 'span', + gridRowStart: initialCellBounds.row, + gridRowEnd: initialCellBounds.row + initialCellBounds.height, + gridColumnStart: initialCellBounds.column, + gridColumnEnd: initialCellBounds.column + initialCellBounds.width, + } + } + + return { + type: 'contained', + gridRow: initialCellBounds.row, + gridColumn: initialCellBounds.column, + } +} + +function gridChildAbsolutePositionConversionCommands( + jsxMetadata: ElementInstanceMetadataMap, + elementPathTree: ElementPathTrees, + elementPath: ElementPath, + canvasContext: { scale: number; offset: CanvasVector }, +): CanvasCommand[] | null { + if (!MetadataUtils.isGridCell(jsxMetadata, elementPath)) { + return null + } + + const instance = MetadataUtils.findElementByElementPath(jsxMetadata, elementPath) + if (instance == null) { + return null + } + + const cellBounds = getGridElementBounds(instance, canvasContext) + if (cellBounds == null) { + return null + } + + if (MetadataUtils.isPositionAbsolute(instance)) { + const gridPositioningProps = + cellBounds.type === 'contained' + ? [ + { prop: PP.create('style', 'gridRow'), value: cellBounds.gridRow }, + { prop: PP.create('style', 'gridColumn'), value: cellBounds.gridColumn }, + ] + : cellBounds.type === 'span' + ? [ + { prop: PP.create('style', 'gridRowStart'), value: cellBounds.gridRowStart }, + { prop: PP.create('style', 'gridRowEnd'), value: cellBounds.gridRowEnd }, + { prop: PP.create('style', 'gridColumnStart'), value: cellBounds.gridColumnStart }, + { prop: PP.create('style', 'gridColumnEnd'), value: cellBounds.gridColumnEnd }, + ] + : assertNever(cellBounds) + + return [ + ...nukeAllAbsolutePositioningPropsCommands(elementPath), + updateBulkProperties('always', elementPath, [ + propertyToDelete(PP.create('style', 'width')), + propertyToDelete(PP.create('style', 'height')), + ...gridElementProps.map(propertyToDelete), + ...gridPositioningProps.map(({ prop, value }) => propertyToSet(prop, value)), + ]), + ] + } + + const { row, column } = + cellBounds.type === 'contained' + ? { row: cellBounds.gridRow, column: cellBounds.gridColumn } + : cellBounds.type === 'span' + ? { row: cellBounds.gridRowStart, column: cellBounds.gridColumnStart } + : assertNever(cellBounds) + + return [ + ...sizeToVisualDimensions(jsxMetadata, elementPathTree, elementPath), + updateBulkProperties('always', elementPath, [ + ...gridElementProps.map(propertyToDelete), + propertyToSet(PP.create('style', 'gridRow'), row), + propertyToSet(PP.create('style', 'gridColumn'), column), + propertyToSet(PP.create('style', 'position'), 'absolute'), + propertyToSet(PP.create('style', 'top'), 0), + propertyToSet(PP.create('style', 'left'), 0), + ]), + ] +} From 1293ce4be9ddf2e4c176112ad73283699bb5306f Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Tue, 10 Sep 2024 15:40:11 +0200 Subject: [PATCH 009/272] Resize grid cell if the element is set to fill, resize the element otherwise (#6347) **Problem:** Currently when a grid element is selected, it's only possible to resize it's _cell_. **Fix:** This PR expands the functionality in two ways: 1. if the selected element is set to fill on both width and height, show the _cell_ resize controls 2. otherwise, show the regular _element_ resize controls https://github.com/user-attachments/assets/9e1ad8ac-0dae-43c2-b0f0-c282152e884b Fixes #6348 --- .../strategies/basic-resize-strategy.tsx | 20 ++++++--- .../grid-draw-to-insert-strategy.tsx | 12 +---- .../grid-rearrange-keyboard-strategy.ts | 12 +---- .../grid-rearrange-move-duplicate-strategy.ts | 12 +---- ...-rearrange-move-strategy.spec.browser2.tsx | 4 +- .../grid-rearrange-move-strategy.ts | 12 +---- .../strategies/grid-reparent-strategy.tsx | 44 ++++++++----------- ...-resize-element-strategy.spec.browser2.tsx | 22 +++++++++- .../grid-resize-element-strategy.ts | 20 +++++---- .../rearrange-grid-swap-strategy.ts | 12 +---- .../strategies/resize-grid-strategy.ts | 11 +---- .../strategies/set-grid-gap-strategy.tsx | 12 +---- .../canvas/controls/grid-controls.tsx | 11 +++++ 13 files changed, 94 insertions(+), 110 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx index 6a0246a9980f..ba16fa986e4d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx @@ -1,8 +1,8 @@ -import { styleStringInArray } from '../../../../utils/common-constants' import { getLayoutProperty } from '../../../../core/layout/getLayoutProperty' import type { PropsOrJSXAttributes } from '../../../../core/model/element-metadata-utils' import { MetadataUtils } from '../../../../core/model/element-metadata-utils' import { foldEither, isLeft, right } from '../../../../core/shared/either' +import * as EP from '../../../../core/shared/element-path' import type { ElementInstanceMetadata } from '../../../../core/shared/element-template' import { isJSXElement } from '../../../../core/shared/element-template' import type { CanvasPoint, CanvasRectangle } from '../../../../core/shared/math-utils' @@ -11,7 +11,10 @@ import { isInfinityRectangle, offsetPoint, } from '../../../../core/shared/math-utils' +import { styleStringInArray } from '../../../../utils/common-constants' +import { trueUpGroupElementChanged } from '../../../editor/store/editor-state' import { stylePropPathMappingFn } from '../../../inspector/common/property-path-hooks' +import { isFixedHugFillModeApplied } from '../../../inspector/inspector-common' import type { EdgePosition } from '../../canvas-types' import { oppositeEdgePosition } from '../../canvas-types' import { @@ -24,9 +27,12 @@ import { adjustCssLengthProperties, lengthPropertyToAdjust, } from '../../commands/adjust-css-length-command' +import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command' +import { queueTrueUpElement } from '../../commands/queue-true-up-command' import { setCursorCommand } from '../../commands/set-cursor-command' import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' +import { controlsForGridPlaceholders } from '../../controls/grid-controls' import { ImmediateParentBounds } from '../../controls/parent-bounds' import { ImmediateParentOutlines } from '../../controls/parent-outlines' import { AbsoluteResizeControl } from '../../controls/select-mode/absolute-resize-control' @@ -44,16 +50,13 @@ import { } from '../canvas-strategy-types' import type { InteractionSession } from '../interaction-state' import { honoursPropsSize } from './absolute-utils' +import { treatElementAsGroupLike } from './group-helpers' import { getLockedAspectRatio, isAnySelectedElementAspectRatioLocked, pickCursorFromEdgePosition, resizeBoundingBox, } from './resize-helpers' -import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command' -import { queueTrueUpElement } from '../../commands/queue-true-up-command' -import { treatElementAsGroupLike } from './group-helpers' -import { trueUpGroupElementChanged } from '../../../editor/store/editor-state' export const BASIC_RESIZE_STRATEGY_ID = 'BASIC_RESIZE' @@ -76,7 +79,11 @@ export function basicResizeStrategy( const elementDimensionsProps = metadata != null ? getElementDimensions(metadata) : null const elementParentBounds = metadata?.specialSizeMeasurements.immediateParentBounds ?? null - if (MetadataUtils.isGridCell(canvasState.startingMetadata, selectedElement)) { + const isGridCell = MetadataUtils.isGridCell(canvasState.startingMetadata, selectedElement) + if ( + isGridCell && + isFixedHugFillModeApplied(canvasState.startingMetadata, selectedElement, 'fill') + ) { return null } @@ -113,6 +120,7 @@ export function basicResizeStrategy( key: 'parent-bounds-control', show: 'visible-only-while-active', }), + ...(isGridCell ? [controlsForGridPlaceholders(EP.parentPath(selectedElement))] : []), ], fitness: interactionSession != null && diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx index c485498776aa..a1a518dbef2c 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx @@ -24,7 +24,7 @@ import type { InsertElementInsertionSubject } from '../../commands/insert-elemen import { insertElementInsertionSubject } from '../../commands/insert-element-insertion-subject' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { wildcardPatch } from '../../commands/wildcard-patch-command' -import { GridControls } from '../../controls/grid-controls' +import { controlsForGridPlaceholders } from '../../controls/grid-controls' import { canvasPointToWindowPoint } from '../../dom-lookup' import { getWrapperWithGeneratedUid, @@ -153,15 +153,7 @@ const gridDrawToInsertStrategyInner = category: 'tools', type: 'pointer', }, - controlsToRender: [ - { - control: GridControls, - props: { targets: [targetParent] }, - key: `draw-into-grid-strategy-controls`, - show: 'always-visible', - priority: 'bottom', - }, - ], + controlsToRender: [controlsForGridPlaceholders(targetParent)], fitness: 5, apply: (strategyLifecycle) => { const newTargetCell = getGridCellUnderCursor( diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts index b378a9702ad6..3807c3d9b71d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts @@ -2,7 +2,7 @@ import { MetadataUtils } from '../../../../core/model/element-metadata-utils' import * as EP from '../../../../core/shared/element-path' import type { GridPositionValue } from '../../../../core/shared/element-template' import { gridPositionValue } from '../../../../core/shared/element-template' -import { GridControls, GridControlsKey } from '../../controls/grid-controls' +import { controlsForGridPlaceholders } from '../../controls/grid-controls' import type { CanvasStrategy, CustomStrategyState, @@ -78,15 +78,7 @@ export function gridRearrangeResizeKeyboardStrategy( category: 'modalities', type: 'reorder-large', }, - controlsToRender: [ - { - control: GridControls, - props: { targets: [parentGridPath] }, - key: GridControlsKey(parentGridPath), - show: 'always-visible', - priority: 'bottom', - }, - ], + controlsToRender: [controlsForGridPlaceholders(parentGridPath)], fitness: fitness(interactionSession), apply: () => { if (interactionSession == null || interactionSession.interactionData.type !== 'KEYBOARD') { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts index bdc88e3624cf..ec44a5d3d40d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts @@ -7,7 +7,7 @@ import { setCursorCommand } from '../../commands/set-cursor-command' import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { updateSelectedViews } from '../../commands/update-selected-views-command' -import { GridControls, GridControlsKey } from '../../controls/grid-controls' +import { controlsForGridPlaceholders } from '../../controls/grid-controls' import type { CanvasStrategyFactory } from '../canvas-strategies' import { onlyFitWhenDraggingThisControl } from '../canvas-strategies' import type { CustomStrategyState, InteractionCanvasState } from '../canvas-strategy-types' @@ -49,15 +49,7 @@ export const gridRearrangeMoveDuplicateStrategy: CanvasStrategyFactory = ( category: 'tools', type: 'pointer', }, - controlsToRender: [ - { - control: GridControls, - props: { targets: [EP.parentPath(selectedElement)] }, - key: GridControlsKey(EP.parentPath(selectedElement)), - show: 'always-visible', - priority: 'bottom', - }, - ], + controlsToRender: [controlsForGridPlaceholders(EP.parentPath(selectedElement))], fitness: onlyFitWhenDraggingThisControl(interactionSession, 'GRID_CELL_HANDLE', 3), apply: () => { if ( diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx index 212b6c8cb2df..43d2142f35e1 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx @@ -5,7 +5,7 @@ import { offsetPoint, windowPoint, } from '../../../../core/shared/math-utils' -import { selectComponentsForTest, wait } from '../../../../utils/utils.test-utils' +import { selectComponentsForTest } from '../../../../utils/utils.test-utils' import CanvasActions from '../../canvas-actions' import { GridCellTestId } from '../../controls/grid-controls' import { mouseDragFromPointToPoint } from '../../event-helpers.test-utils' @@ -117,6 +117,8 @@ export var storyboard = ( gridTemplateRows: '1fr', gridColumn: 1, gridRow: 2, + width: '100%', + height: '100%', }} >
{ + it('cannot resize non-filling cells', async () => { + const editor = await renderTestEditorWithCode(ProjectCode, 'await-first-dom-report') + + await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/grid-child-not-filling')]) + + const resizeControl = editor.renderedDOM.queryByTestId(GridResizeEdgeTestId('column-end')) + expect(resizeControl).toBeNull() + }) + describe('column-end', () => { it('can enlarge element', async () => { const editor = await renderTestEditorWithCode(ProjectCode, 'await-first-dom-report') @@ -230,6 +239,8 @@ describe('grid resize element strategy', () => { expect(styleProp).toEqual([ ['minHeight', 0], ['backgroundColor', '#db48f6'], + ['width', '100%'], + ['height', '100%'], ['gridColumnStart', 7], ['gridColumnEnd', 11], ['gridRow', 2], @@ -271,6 +282,8 @@ export var storyboard = ( gridTemplateRows: '1fr', gridColumn: 1, gridRow: 2, + width: '100%', + height: '100%', }} >
{ diff --git a/editor/src/components/canvas/canvas-strategies/strategies/rearrange-grid-swap-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/rearrange-grid-swap-strategy.ts index 85688d7c2441..54971c1429bf 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/rearrange-grid-swap-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/rearrange-grid-swap-strategy.ts @@ -14,7 +14,7 @@ import { create } from '../../../../core/shared/property-path' import type { CanvasCommand } from '../../commands/commands' import { deleteProperties } from '../../commands/delete-properties-command' import { rearrangeChildren } from '../../commands/rearrange-children-command' -import { GridControls, GridControlsKey } from '../../controls/grid-controls' +import { controlsForGridPlaceholders } from '../../controls/grid-controls' import { recurseIntoChildrenOfMapOrFragment } from '../../gap-utils' import type { CanvasStrategyFactory } from '../canvas-strategies' import { onlyFitWhenDraggingThisControl } from '../canvas-strategies' @@ -67,15 +67,7 @@ export const rearrangeGridSwapStrategy: CanvasStrategyFactory = ( category: 'tools', type: 'pointer', }, - controlsToRender: [ - { - control: GridControls, - props: { targets: [parentGridPath] }, - key: GridControlsKey(parentGridPath), - show: 'always-visible', - priority: 'bottom', - }, - ], + controlsToRender: [controlsForGridPlaceholders(parentGridPath)], fitness: onlyFitWhenDraggingThisControl(interactionSession, 'GRID_CELL_HANDLE', 1), apply: () => { if ( diff --git a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts index 619fe370b4ce..57f261d4e10f 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts @@ -9,8 +9,7 @@ import * as EP from '../../../../core/shared/element-path' import * as PP from '../../../../core/shared/property-path' import { setProperty } from '../../commands/set-property-command' import { - GridControls, - GridControlsKey, + controlsForGridPlaceholders, GridRowColumnResizingControls, } from '../../controls/grid-controls' import type { CanvasStrategyFactory } from '../canvas-strategies' @@ -73,13 +72,7 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( show: 'always-visible', priority: 'top', }, - { - control: GridControls, - props: { targets: [gridPath] }, - key: GridControlsKey(gridPath), - show: 'always-visible', - priority: 'bottom', - }, + controlsForGridPlaceholders(gridPath), ], fitness: onlyFitWhenDraggingThisControl(interactionSession, 'GRID_AXIS_HANDLE', 1), apply: () => { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx index e284b8d75aa0..b99698f01649 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx @@ -43,7 +43,7 @@ import { activeFrameTargetPath, setActiveFrames } from '../../commands/set-activ import type { GridGapControlProps } from '../../controls/select-mode/grid-gap-control' import { GridGapControl } from '../../controls/select-mode/grid-gap-control' import type { GridControlsProps } from '../../controls/grid-controls' -import { GridControls } from '../../controls/grid-controls' +import { controlsForGridPlaceholders } from '../../controls/grid-controls' const SetGridGapStrategyId = 'SET_GRID_GAP_STRATEGY' @@ -142,15 +142,7 @@ export const setGridGapStrategy: CanvasStrategyFactory = ( // when the drag is ongoing, keep showing the grid cells if (isDragOngoing(interactionSession)) { - controlsToRender.push( - controlWithProps({ - control: GridControls, - props: { targets: [selectedElement] }, - key: `set-grid-gap-strategy-controls`, - show: 'always-visible', - priority: 'bottom', - }), - ) + controlsToRender.push(controlsForGridPlaceholders(selectedElement)) } return { diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 077b729a6d45..7a4fcdc11cfd 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -51,6 +51,7 @@ import { useDispatch } from '../../editor/store/dispatch-context' import { Substores, useEditorState, useRefEditorState } from '../../editor/store/store-hook' import { useRollYourOwnFeatures } from '../../navigator/left-pane/roll-your-own-pane' import CanvasActions from '../canvas-actions' +import type { ControlWithProps } from '../canvas-strategies/canvas-strategy-types' import { controlForStrategyMemoized } from '../canvas-strategies/canvas-strategy-types' import type { GridResizeEdge, @@ -1695,3 +1696,13 @@ export function getGridPlaceholderDomElementFromCoordinates(params: { } const gridPlaceholderBorder = (color: string) => `2px solid ${color}` + +export function controlsForGridPlaceholders(gridPath: ElementPath): ControlWithProps { + return { + control: GridControls, + props: { targets: [gridPath] }, + key: GridControlsKey(gridPath), + show: 'always-visible', + priority: 'bottom', + } +} From c929e929f10076a52c1aedf85a7ddf53ba5583e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20K=C3=B6rmendy?= Date: Tue, 10 Sep 2024 17:54:52 +0200 Subject: [PATCH 010/272] Absolute move should use the root cell in calculations (#6342) ## Problem https://github.com/user-attachments/assets/a0e33272-6b37-4d5b-b145-4437b615bc1b ## Fix Use `targetRootCell` in the absolute move offset calculations https://github.com/user-attachments/assets/c8864c75-ed4d-42a3-be6f-72b8da14988e --- .../strategies/grid-cell-bounds.ts | 20 +++++ .../strategies/grid-helpers.ts | 23 ++--- ...-rearrange-move-strategy.spec.browser2.tsx | 83 +++++++++++++++++++ .../canvas/controls/grid-controls.tsx | 14 +--- 4 files changed, 120 insertions(+), 20 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts index 122fd4657bb6..02e7bf3f1d81 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts @@ -137,3 +137,23 @@ export function getGridCellBoundsFromCanvas( height: cellHeight, } } + +export function getGridPlaceholderDomElementFromCoordinates(params: { + row: number + column: number +}): HTMLElement | null { + return document.querySelector( + `[data-grid-row="${params.row}"]` + `[data-grid-column="${params.column}"]`, + ) +} + +export function getCellWindowRect(coords: GridCellCoordinates): WindowRectangle | null { + const element = getGridPlaceholderDomElementFromCoordinates(coords) + if (element == null) { + return null + } + + const domRect = element!.getBoundingClientRect() + const windowRect = windowRectangle(domRect) + return windowRect +} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index b8c0839bd4c9..aa51581ec657 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -30,6 +30,7 @@ import { cssNumber, isCSSKeyword } from '../../../inspector/common/css-utils' import { setCssLengthProperty } from '../../commands/set-css-length-command' import type { GridCellCoordinates } from './grid-cell-bounds' import { + getCellWindowRect, getGridCellUnderMouse, getGridCellUnderMouseRecursive, gridCellCoordinates, @@ -86,16 +87,6 @@ export function runGridRearrangeMove( const targetCellUnderMouse = targetCellData?.gridCellCoordinates ?? null - const absoluteMoveCommands = - targetCellData == null - ? [] - : gridChildAbsoluteMoveCommands( - MetadataUtils.findElementByElementPath(jsxMetadata, targetElement), - targetCellData.cellWindowRectangle, - interactionData, - { scale: canvasScale, canvasOffset: canvasOffset }, - ) - const originalElementMetadata = MetadataUtils.findElementByElementPath( jsxMetadata, selectedElement, @@ -148,6 +139,18 @@ export function runGridRearrangeMove( const targetRootCell = gridCellCoordinates(row.start, column.start) + const windowRect = getCellWindowRect(targetRootCell) + + const absoluteMoveCommands = + windowRect == null + ? [] + : gridChildAbsoluteMoveCommands( + MetadataUtils.findElementByElementPath(jsxMetadata, targetElement), + windowRect, + interactionData, + { scale: canvasScale, canvasOffset: canvasOffset }, + ) + const gridCellMoveCommands = setGridPropsCommands(targetElement, gridTemplate, { gridColumnStart: gridPositionValue(column.start), gridColumnEnd: gridPositionValue(column.end), diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx index 43d2142f35e1..ce0becd9726d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx @@ -370,6 +370,89 @@ export var storyboard = ( }) } }) + + it("can move element spanning multiple cell by a cell that isn't the root cell", async () => { + const editor = await renderTestEditorWithCode( + `import { Scene, Storyboard } from 'utopia-api' +export var storyboard = ( + + +
+
+
+ + +) +`, + 'await-first-dom-report', + ) + + await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/child')]) + + const child = editor.renderedDOM.getByTestId('child') + const childBounds = child.getBoundingClientRect() + const startPoint = windowPoint({ + x: Math.floor(childBounds.left + childBounds.width - 3), + y: Math.floor(childBounds.top + childBounds.height - 3), + }) + + await mouseDragFromPointToPoint( + editor.renderedDOM.getByTestId(GridCellTestId(EP.fromString('sb/scene/grid/child'))), + startPoint, + offsetPoint(startPoint, windowPoint({ x: -100, y: -100 })), + ) + + { + const { top, left, gridColumn, gridRow } = child.style + expect({ top, left, gridColumn, gridRow }).toEqual({ + gridColumn: '1', + gridRow: '1', + left: '60.5px', + top: '61px', + }) + } + }) }) }) diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 7a4fcdc11cfd..f3d47c9991f8 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -81,7 +81,10 @@ import { CanvasOffsetWrapper } from './canvas-offset-wrapper' import { CanvasLabel } from './select-mode/controls-common' import { useMaybeHighlightElement } from './select-mode/select-mode-hooks' import type { GridCellCoordinates } from '../canvas-strategies/strategies/grid-cell-bounds' -import { gridCellTargetId } from '../canvas-strategies/strategies/grid-cell-bounds' +import { + getGridPlaceholderDomElementFromCoordinates, + gridCellTargetId, +} from '../canvas-strategies/strategies/grid-cell-bounds' const CELL_ANIMATION_DURATION = 0.15 // seconds @@ -1686,15 +1689,6 @@ export function getGridPlaceholderDomElement(elementPath: ElementPath): HTMLElem return document.getElementById(gridKeyFromPath(elementPath)) } -export function getGridPlaceholderDomElementFromCoordinates(params: { - row: number - column: number -}): HTMLElement | null { - return document.querySelector( - `[data-grid-row="${params.row}"]` + `[data-grid-column="${params.column}"]`, - ) -} - const gridPlaceholderBorder = (color: string) => `2px solid ${color}` export function controlsForGridPlaceholders(gridPath: ElementPath): ControlWithProps { From 73b4df7b5a904761ab95b8a70ed196d662ab0e21 Mon Sep 17 00:00:00 2001 From: Sean Parsons <217400+seanparsons@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:49:50 +0100 Subject: [PATCH 011/272] performance(editor) Improved `buildTree`. (#6325) - Reworked `buildTree_MUTATE` to build the tree from the root downwards, combining it with some of the logic taken from `getChildrenPaths`. - Further improvement to `isDescendantOf` replacing the previous implementation. - `getReorderedPaths` now avoids a lot of repeated logic for checking the element type. - Broke apart `ElementPathTree.children` into two separate fields to make for easier ordering. - Added `getElementPathTreeChildren` and `forEachElementPathTreeChild` utility functions. - `buildTree_MUTATE` now adds to the two different children fields based on the element path representing inner children over property children. - `getReorderedIndexInPaths` further reworked to handle shifting by the siblings. - Fixed some tests that had expressions incorrectly ordered. --- editor/src/benchmarks.benchmark.ts | 4 +- editor/src/components/canvas/canvas.ts | 4 +- .../controls/select-mode/scene-label.tsx | 4 +- .../canvas/dom-sampler.spec.browser2.tsx | 6 +- editor/src/components/canvas/gap-utils.ts | 8 +- .../store/store-deep-equality-instances.ts | 6 +- .../components/navigator/navigator-utils.ts | 18 +- .../navigator/navigator.spec.browser2.tsx | 6 +- .../model/element-metadata-utils.spec.tsx | 14 + .../src/core/model/element-metadata-utils.ts | 19 +- .../shared/element-path-tree.benchmark.ts | 56 ++++ .../element-path-tree.spec.browser2.tsx | 6 +- editor/src/core/shared/element-path-tree.ts | 283 ++++++++++-------- editor/src/core/shared/element-path.ts | 50 +++- 14 files changed, 324 insertions(+), 160 deletions(-) diff --git a/editor/src/benchmarks.benchmark.ts b/editor/src/benchmarks.benchmark.ts index 4cb01c8292cf..57192a78c629 100644 --- a/editor/src/benchmarks.benchmark.ts +++ b/editor/src/benchmarks.benchmark.ts @@ -5,9 +5,9 @@ import { benchmarkOptics } from './core/shared/optics.benchmark' import { benchmarkPropertyPathFunction } from './core/shared/property-path.benchmark' import { benchmarkGetUniqueUids } from './core/model/get-unique-ids.benchmark' -// await benchmarkBuildTree() +await benchmarkBuildTree() // await benchmarkElementPathFunction() // await benchmarkPropertyPathFunction() // await benchmarkAttributes() // await benchmarkOptics() -await benchmarkGetUniqueUids() +// await benchmarkGetUniqueUids() diff --git a/editor/src/components/canvas/canvas.ts b/editor/src/components/canvas/canvas.ts index ca9b4009d4db..d59c126e1400 100644 --- a/editor/src/components/canvas/canvas.ts +++ b/editor/src/components/canvas/canvas.ts @@ -18,7 +18,7 @@ import type { } from '../editor/store/editor-state' import * as EP from '../../core/shared/element-path' import type { ElementPathTree, ElementPathTrees } from '../../core/shared/element-path-tree' -import { getSubTree } from '../../core/shared/element-path-tree' +import { forEachElementPathTreeChild, getSubTree } from '../../core/shared/element-path-tree' import { assertNever, fastForEach } from '../../core/shared/utils' import { memoize } from '../../core/shared/memoize' import { maybeToArray } from '../../core/shared/optional-utils' @@ -73,7 +73,7 @@ function getFramesInCanvasContextUncached( let children: Array = [] let unfurledComponents: Array = [] - fastForEach(Object.values(componentTree.children), (childTree) => { + forEachElementPathTreeChild(componentTree, (childTree) => { if (EP.isRootElementOfInstance(childTree.path)) { unfurledComponents.push(childTree) } else { diff --git a/editor/src/components/canvas/controls/select-mode/scene-label.tsx b/editor/src/components/canvas/controls/select-mode/scene-label.tsx index fc5db3cd09f0..36e9227f4157 100644 --- a/editor/src/components/canvas/controls/select-mode/scene-label.tsx +++ b/editor/src/components/canvas/controls/select-mode/scene-label.tsx @@ -18,7 +18,7 @@ import { boundingArea, createInteractionViaMouse } from '../../canvas-strategies import { windowToCanvasCoordinates } from '../../dom-lookup' import { CanvasOffsetWrapper } from '../canvas-offset-wrapper' import { isCommentMode, isSelectModeWithArea } from '../../../editor/editor-modes' -import { getSubTree } from '../../../../core/shared/element-path-tree' +import { getElementPathTreeChildren, getSubTree } from '../../../../core/shared/element-path-tree' interface SceneLabelControlProps { maybeHighlightOnHover: (target: ElementPath) => void @@ -65,7 +65,7 @@ const SceneLabel = React.memo((props) => { if (subTree == null) { return false } else { - return subTree.children.length === 1 + return getElementPathTreeChildren(subTree).length === 1 } }, 'SceneLabel sceneHasSingleChild', diff --git a/editor/src/components/canvas/dom-sampler.spec.browser2.tsx b/editor/src/components/canvas/dom-sampler.spec.browser2.tsx index f1ca07c54a40..3b93654cda41 100644 --- a/editor/src/components/canvas/dom-sampler.spec.browser2.tsx +++ b/editor/src/components/canvas/dom-sampler.spec.browser2.tsx @@ -296,16 +296,14 @@ export var storyboard = ( navigatorEntryToKey, ), ).toEqual([ - 'regular-sb/1e7', 'regular-sb/sc', 'regular-sb/sc/app', 'regular-sb/sc/app:app-root', 'regular-sb/sc/app:app-root/card', 'regular-sb/sc/app:app-root/card:card-root', - 'regular-sb/sc/app:app-root/card:card-root/30d', 'regular-sb/sc/app:app-root/card:card-root/card-span', + 'regular-sb/sc/app:app-root/card:card-root/30d', 'regular-sb/sc/app:app-root/card/card-child', - 'regular-sb/sc/app:app-root/children-code-block', 'regular-sb/sc/app:app-root/frag', 'regular-sb/sc/app:app-root/frag/frag-child', 'regular-sb/sc/app:app-root/frag/cond-1', @@ -319,7 +317,9 @@ export var storyboard = ( 'synthetic-sb/sc/app:app-root/frag/cond-1/cond-1-true/cond-2/d84-attribute', 'conditional-clause-sb/sc/app:app-root/frag/cond-1-false-case', 'synthetic-sb/sc/app:app-root/frag/cond-1/019-attribute', + 'regular-sb/sc/app:app-root/children-code-block', 'regular-sb/sc/app/app-child', + 'regular-sb/1e7', ]) }) diff --git a/editor/src/components/canvas/gap-utils.ts b/editor/src/components/canvas/gap-utils.ts index 99a70eeae5c4..c30454a2afeb 100644 --- a/editor/src/components/canvas/gap-utils.ts +++ b/editor/src/components/canvas/gap-utils.ts @@ -22,7 +22,11 @@ import type { CSSNumber, FlexDirection } from '../inspector/common/css-utils' import type { Sides } from 'utopia-api/core' import { sides } from 'utopia-api/core' import { styleStringInArray } from '../../utils/common-constants' -import { getSubTree, type ElementPathTrees } from '../../core/shared/element-path-tree' +import { + getElementPathTreeChildren, + getSubTree, + type ElementPathTrees, +} from '../../core/shared/element-path-tree' import { isReversedFlexDirection } from '../../core/model/flex-utils' import * as EP from '../../core/shared/element-path' import { treatElementAsFragmentLike } from './canvas-strategies/strategies/fragment-like-helpers' @@ -380,7 +384,7 @@ export function recurseIntoChildrenOfMapOrFragment( return [] } - return subTree.children.flatMap((element) => { + return getElementPathTreeChildren(subTree).flatMap((element) => { const elementPath = element.path if (EP.isRootElementOfInstance(elementPath)) { return [] diff --git a/editor/src/components/editor/store/store-deep-equality-instances.ts b/editor/src/components/editor/store/store-deep-equality-instances.ts index 6f3b13d23626..e19d4f36fab4 100644 --- a/editor/src/components/editor/store/store-deep-equality-instances.ts +++ b/editor/src/components/editor/store/store-deep-equality-instances.ts @@ -2996,12 +2996,14 @@ export function ElementPathTreeKeepDeepEquality( oldValue: ElementPathTree, newValue: ElementPathTree, ): KeepDeepEqualityResult { - return combine3EqualityCalls( + return combine4EqualityCalls( (pathTree) => pathTree.path, ElementPathKeepDeepEquality, (pathTree) => pathTree.pathString, createCallWithTripleEquals(), - (pathTree) => pathTree.children, + (pathTree) => pathTree.innerChildren, + arrayDeepEquality(ElementPathTreeKeepDeepEquality), + (pathTree) => pathTree.propsChildren, arrayDeepEquality(ElementPathTreeKeepDeepEquality), elementPathTree, )(oldValue, newValue) diff --git a/editor/src/components/navigator/navigator-utils.ts b/editor/src/components/navigator/navigator-utils.ts index c3a8c358566e..d84324561244 100644 --- a/editor/src/components/navigator/navigator-utils.ts +++ b/editor/src/components/navigator/navigator-utils.ts @@ -37,7 +37,11 @@ import { syntheticNavigatorEntry, } from '../editor/store/editor-state' import type { ElementPathTree, ElementPathTrees } from '../../core/shared/element-path-tree' -import { getCanvasRoots, getSubTree } from '../../core/shared/element-path-tree' +import { + getCanvasRoots, + getElementPathTreeChildren, + getSubTree, +} from '../../core/shared/element-path-tree' import { assertNever } from '../../core/shared/utils' import type { ConditionalCase } from '../../core/model/conditionals' import { getConditionalClausePath } from '../../core/model/conditionals' @@ -320,7 +324,9 @@ function walkRegularNavigatorEntry( const childPath = EP.appendToPath(elementPath, getUtopiaID(propValue)) - const subTreeChild = subTree?.children.find((child) => EP.pathsEqual(child.path, childPath)) + const subTreeChild = getElementPathTreeChildren(subTree).find((child) => + EP.pathsEqual(child.path, childPath), + ) if (subTreeChild != null) { const childTreeEntry = createNavigatorSubtree( metadata, @@ -359,7 +365,7 @@ function walkRegularNavigatorEntry( }) } - const childrenPaths = subTree.children.filter( + const childrenPaths = getElementPathTreeChildren(subTree).filter( (child) => !processedAccumulator.has(EP.toString(child.path)), ) const children: Array = mapDropNulls((child) => { @@ -457,7 +463,7 @@ function walkConditionalClause( const branch = conditionalCase === 'true-case' ? conditional.whenTrue : conditional.whenFalse // Walk the clause of the conditional. - const clausePathTrees = Object.values(conditionalSubTree.children).filter((childPath) => { + const clausePathTrees = getElementPathTreeChildren(conditionalSubTree).filter((childPath) => { if (isDynamic(childPath.path) && hasElementsWithin(branch)) { for (const element of Object.values(branch.elementsWithin)) { const firstChildPath = EP.appendToPath(EP.parentPath(clausePath), element.uid) @@ -513,7 +519,7 @@ function walkMapExpression( const commentFlag = findUtopiaCommentFlag(element.comments, 'map-count') const mapCountOverride = isUtopiaPropOrCommentFlagMapCount(commentFlag) ? commentFlag.value : null - const mappedChildren = Object.values(subTree.children).map((child) => + const mappedChildren = getElementPathTreeChildren(subTree).map((child) => createNavigatorSubtree( metadata, elementPathTrees, @@ -531,7 +537,7 @@ function walkMapExpression( } let invalidEntries: Array = [] - for (let i = Object.values(subTree.children).length; i < mapCountOverride; i++) { + for (let i = getElementPathTreeChildren(subTree).length; i < mapCountOverride; i++) { const entry = invalidOverrideNavigatorEntry( EP.appendToPath(subTree.path, `invalid-override-${i + 1}`), 'data source not found', diff --git a/editor/src/components/navigator/navigator.spec.browser2.tsx b/editor/src/components/navigator/navigator.spec.browser2.tsx index 2da3ac334c1d..e8911f87814c 100644 --- a/editor/src/components/navigator/navigator.spec.browser2.tsx +++ b/editor/src/components/navigator/navigator.spec.browser2.tsx @@ -5495,16 +5495,14 @@ describe('Navigator row order', () => { navigatorEntryToKey, ), ).toEqual([ - 'regular-sb/1e7', 'regular-sb/sc', 'regular-sb/sc/app', 'regular-sb/sc/app:app-root', 'regular-sb/sc/app:app-root/card', 'regular-sb/sc/app:app-root/card:card-root', - 'regular-sb/sc/app:app-root/card:card-root/30d', 'regular-sb/sc/app:app-root/card:card-root/card-span', + 'regular-sb/sc/app:app-root/card:card-root/30d', 'regular-sb/sc/app:app-root/card/card-child', - 'regular-sb/sc/app:app-root/children-code-block', 'regular-sb/sc/app:app-root/frag', 'regular-sb/sc/app:app-root/frag/frag-child', 'regular-sb/sc/app:app-root/frag/cond-1', @@ -5518,7 +5516,9 @@ describe('Navigator row order', () => { 'synthetic-sb/sc/app:app-root/frag/cond-1/cond-1-true/cond-2/d84-attribute', 'conditional-clause-sb/sc/app:app-root/frag/cond-1-false-case', 'synthetic-sb/sc/app:app-root/frag/cond-1/019-attribute', + 'regular-sb/sc/app:app-root/children-code-block', 'regular-sb/sc/app/app-child', + 'regular-sb/1e7', ]) }) diff --git a/editor/src/core/model/element-metadata-utils.spec.tsx b/editor/src/core/model/element-metadata-utils.spec.tsx index 49ab92bb84da..695b9a2de175 100644 --- a/editor/src/core/model/element-metadata-utils.spec.tsx +++ b/editor/src/core/model/element-metadata-utils.spec.tsx @@ -1101,6 +1101,7 @@ describe('getElementLabel', () => { spanElementMetadata.elementPath, EP.toString(spanElementMetadata.elementPath), [], + [], ), [EP.toString(divElementMetadata.elementPath)]: elementPathTree( divElementMetadata.elementPath, @@ -1110,8 +1111,10 @@ describe('getElementLabel', () => { spanElementMetadata.elementPath, EP.toString(spanElementMetadata.elementPath), [], + [], ), ], + [], ), } it('the label of a spin containing text is that text', () => { @@ -1138,16 +1141,19 @@ describe('getting the root paths', () => { testComponentSceneElement.elementPath, EP.toString(testComponentSceneElement.elementPath), [], + [], ) const testStoryboardChildTree = elementPathTree( testStoryboardChildElement.elementPath, EP.toString(testStoryboardChildElement.elementPath), [], + [], ) const storyboardTree = elementPathTree( EP.elementPath([[BakedInStoryboardUID]]), EP.toString(EP.elementPath([[BakedInStoryboardUID]])), [testComponentSceneTree, testStoryboardChildTree], + [], ) const pathTrees: ElementPathTrees = { [EP.toString(EP.elementPath([[BakedInStoryboardUID]]))]: storyboardTree, @@ -1170,41 +1176,49 @@ describe('getting the root paths', () => { testComponentSceneChildElement.elementPath, EP.toString(testComponentSceneChildElement.elementPath), [], + [], ) const testComponentChild1Tree = elementPathTree( testComponentMetadataChild1.elementPath, EP.toString(testComponentMetadataChild1.elementPath), [], + [], ) const testComponentChild2Tree = elementPathTree( testComponentMetadataChild2.elementPath, EP.toString(testComponentMetadataChild2.elementPath), [], + [], ) const testComponentChild3Tree = elementPathTree( testComponentMetadataChild3.elementPath, EP.toString(testComponentMetadataChild3.elementPath), [], + [], ) const testComponentRoot1Tree = elementPathTree( testComponentRoot1.elementPath, EP.toString(testComponentRoot1.elementPath), [testComponentChild1Tree, testComponentChild2Tree, testComponentChild3Tree], + [], ) const testComponentSceneTree = elementPathTree( testComponentSceneElement.elementPath, EP.toString(testComponentSceneElement.elementPath), [testComponentSceneChildTree, testComponentRoot1Tree], + [], ) const testStoryboardChildTree = elementPathTree( testStoryboardChildElement.elementPath, EP.toString(testStoryboardChildElement.elementPath), [], + [], ) const storyboardTree = elementPathTree( EP.elementPath([[BakedInStoryboardUID]]), EP.toString(EP.elementPath([[BakedInStoryboardUID]])), [testComponentSceneChildTree, testStoryboardChildTree], + [], ) const pathTrees: ElementPathTrees = { [EP.toString(EP.elementPath([[BakedInStoryboardUID]]))]: storyboardTree, diff --git a/editor/src/core/model/element-metadata-utils.ts b/editor/src/core/model/element-metadata-utils.ts index de4faaa17ad5..6c089afe8b5f 100644 --- a/editor/src/core/model/element-metadata-utils.ts +++ b/editor/src/core/model/element-metadata-utils.ts @@ -138,7 +138,15 @@ import { import type { ProjectContentTreeRoot } from '../../components/assets' import { memoize } from '../shared/memoize' import type { ElementPathTree, ElementPathTrees } from '../shared/element-path-tree' -import { buildTree, getSubTree, getCanvasRoots, elementPathTree } from '../shared/element-path-tree' +import { + buildTree, + getSubTree, + getCanvasRoots, + elementPathTree, + getElementPathTreeChildren, + forEachElementPathTreeChild, + printTree, +} from '../shared/element-path-tree' import type { PropertyControlsInfo } from '../../components/custom-code/code-file' import { findUnderlyingTargetComponentImplementationFromImportInfo } from '../../components/custom-code/code-file' import type { @@ -323,7 +331,6 @@ export const MetadataUtils = { if (target == null) { return [] } - const parentPath = EP.parentPath(target) const siblingPathsOrNull = EP.isRootElementOfInstance(target) ? MetadataUtils.getRootViewPathsOrdered(metadata, pathTree, parentPath) @@ -724,7 +731,7 @@ export const MetadataUtils = { if (subTree == null) { return [] } else { - return subTree.children + return getElementPathTreeChildren(subTree) .map((child) => child.path) .filter((path) => !EP.isRootElementOfInstance(path)) } @@ -845,7 +852,7 @@ export const MetadataUtils = { let result: Array = [] function recurseElement(tree: ElementPathTree): void { result.push(tree.path) - fastForEach(Object.values(tree.children), (childTree) => { + forEachElementPathTreeChild(tree, (childTree) => { recurseElement(childTree) }) } @@ -878,7 +885,7 @@ export const MetadataUtils = { if (tree != null) { result.push(tree.path) - fastForEach(Object.values(tree.children), (childTree) => { + forEachElementPathTreeChild(tree, (childTree) => { recurseElement(childTree) }) } @@ -1375,7 +1382,7 @@ export const MetadataUtils = { let unfurledComponents: Array = [] - fastForEach(Object.values(subTree.children), (child) => { + forEachElementPathTreeChild(subTree, (child) => { if (EP.isRootElementOfInstance(child.path)) { unfurledComponents.push(child) } else { diff --git a/editor/src/core/shared/element-path-tree.benchmark.ts b/editor/src/core/shared/element-path-tree.benchmark.ts index cc55e77ac41e..ffd7351e1ff3 100644 --- a/editor/src/core/shared/element-path-tree.benchmark.ts +++ b/editor/src/core/shared/element-path-tree.benchmark.ts @@ -17,6 +17,62 @@ function dummyMetadataFromPaths(elementPaths: ElementPath[]): ElementInstanceMet } export async function benchmarkBuildTree(): Promise { + await Benny.suite( + 'isDescendantOf - for immediate descendant', + Benny.add('for immediate descendant', () => { + const path1 = EP.fromString(`aaa/bbb/ccc`) + const path2 = EP.fromString(`aaa/bbb/ccc:ddd`) + + return () => { + EP.isDescendantOf(path2, path1) + } + }), + Benny.cycle(), + Benny.complete(), + Benny.save({ file: 'buildTree immediate descendant', details: true }), + ) + await Benny.suite( + 'isDescendantOf - non-descendant', + Benny.add('non-descendant', () => { + const path1 = EP.fromString(`aaa/bbb/ccc`) + const path2 = EP.fromString(`aaa/bbb/ddd`) + + return () => { + EP.isDescendantOf(path2, path1) + } + }), + Benny.cycle(), + Benny.complete(), + Benny.save({ file: 'buildTree non-descendant', details: true }), + ) + await Benny.suite( + 'isChildOf - child', + Benny.add('child', () => { + const path1 = EP.fromString(`aaa/bbb/ccc`) + const path2 = EP.fromString(`aaa/bbb/ccc:ddd`) + + return () => { + EP.isChildOf(path2, path1) + } + }), + Benny.cycle(), + Benny.complete(), + Benny.save({ file: 'isChildOf child', details: true }), + ) + await Benny.suite( + 'isChildOf - not child', + Benny.add('not child', () => { + const path1 = EP.fromString(`aaa/bbb/ccc`) + const path2 = EP.fromString(`aaa/bbb/ddd`) + + return () => { + EP.isChildOf(path2, path1) + } + }), + Benny.cycle(), + Benny.complete(), + Benny.save({ file: 'isChildOf not child', details: true }), + ) await Benny.suite( 'buildTree - deeply nested elements', Benny.add('deeply nested elements', () => { diff --git a/editor/src/core/shared/element-path-tree.spec.browser2.tsx b/editor/src/core/shared/element-path-tree.spec.browser2.tsx index 16348c6b1b1d..321414400399 100644 --- a/editor/src/core/shared/element-path-tree.spec.browser2.tsx +++ b/editor/src/core/shared/element-path-tree.spec.browser2.tsx @@ -126,16 +126,14 @@ describe('Building and ordering the element path tree for a real project', () => expect(printTree(renderResult.getEditorState().editor.elementPathTree)).toEqual( `sb - sb/1e7 sb/sc sb/sc/app sb/sc/app:app-root sb/sc/app:app-root/card sb/sc/app:app-root/card:card-root - sb/sc/app:app-root/card:card-root/30d sb/sc/app:app-root/card:card-root/card-span + sb/sc/app:app-root/card:card-root/30d sb/sc/app:app-root/card/card-child - sb/sc/app:app-root/52e sb/sc/app:app-root/frag sb/sc/app:app-root/frag/frag-child sb/sc/app:app-root/frag/cond-1 @@ -144,7 +142,9 @@ describe('Building and ordering the element path tree for a real project', () => sb/sc/app:app-root/frag/cond-1/cond-1-true/cond-2 sb/sc/app:app-root/frag/cond-1/cond-1-true/cond-2/e26 sb/sc/app:app-root/frag/cond-1/cond-1-true/cond-2/e26/cond-2-child~~~1 + sb/sc/app:app-root/52e sb/sc/app/app-child + sb/1e7 `, ) }) diff --git a/editor/src/core/shared/element-path-tree.ts b/editor/src/core/shared/element-path-tree.ts index 1c223657b4f9..55d36be8332f 100644 --- a/editor/src/core/shared/element-path-tree.ts +++ b/editor/src/core/shared/element-path-tree.ts @@ -1,140 +1,155 @@ import { isFeatureEnabled } from '../../utils/feature-switches' import { MetadataUtils } from '../model/element-metadata-utils' -import { isLeft, isRight } from './either' +import { forEachRight, isLeft } from './either' import * as EP from './element-path' -import type { ElementInstanceMetadataMap } from './element-template' +import type { ElementInstanceMetadataMap, JSXElementChild } from './element-template' import { - isJSElementAccess, - isJSExpressionMapOrOtherJavaScript, - isJSIdentifier, - isJSPropertyAccess, isJSXConditionalExpression, isJSXElement, + isJSXElementLike, isJSXFragment, - isJSXTextBlock, } from './element-template' import type { ElementPath } from './project-file-types' -import { fastForEach } from './utils' +import { assertNever } from './utils' export interface ElementPathTree { path: ElementPath pathString: string - children: Array + innerChildren: Array + propsChildren: Array } export function elementPathTree( path: ElementPath, pathString: string, - children: Array, + innerChildren: Array, + propsChildren: Array, ): ElementPathTree { return { path: path, pathString: pathString, - children: children, + innerChildren: innerChildren, + propsChildren: propsChildren, } } +export function getElementPathTreeChildren(tree: ElementPathTree): Array { + return [...tree.innerChildren, ...tree.propsChildren] +} + +export function forEachElementPathTreeChild( + tree: ElementPathTree, + handler: (elementPathTree: ElementPathTree) => void, +): void { + tree.innerChildren.forEach(handler) + tree.propsChildren.forEach(handler) +} + export type ElementPathTrees = { [key: string]: ElementPathTree } export function buildTree(...metadatas: Array): ElementPathTrees { let tree: ElementPathTrees = {} for (const metadata of metadatas) { + // The tree should maintain the ordering of the statically defined elements, + // But the metadata itself may not match that ordering. const elementPaths = Object.values(metadata).map((m) => m.elementPath) - if (elementPaths.length === 0) { - return {} + const firstElementPath = elementPaths.at(0) + if (firstElementPath == null) { + continue } - const root = EP.getStoryboardPathFromPath(elementPaths[0]) + const root = EP.getStoryboardPathFromPath(firstElementPath) if (root == null) { - return {} + continue } const missingParents = getMissingParentPaths(elementPaths, metadata) const paths = getReorderedPaths(elementPaths, metadata, missingParents) - buildTreeRecursive_MUTATE(root, tree, paths, metadata) + buildTree_MUTATE(root, tree, paths, metadata) } return tree } -function buildTreeRecursive_MUTATE( +function addRootToTree(rootPath: ElementPath, trees: ElementPathTrees): void { + const rootPathString = EP.toString(rootPath) + if (!(rootPathString in trees)) { + trees[rootPathString] = elementPathTree(rootPath, rootPathString, [], []) + } +} + +function buildTree_MUTATE( rootPath: ElementPath, trees: ElementPathTrees, originalPaths: ElementPath[], metadata: ElementInstanceMetadataMap, -): ElementPathTree[] { - const rootPathString = EP.toString(rootPath) - trees[rootPathString] = elementPathTree(rootPath, rootPathString, []) - - const childrenPaths = getChildrenPaths(metadata, rootPath, originalPaths) +): void { + addRootToTree(rootPath, trees) - let children: ElementPathTree[] = [] - for (const path of childrenPaths) { + function addPathToTree(path: ElementPath): void { const pathString = EP.toString(path) - const subTree = elementPathTree( - path, - pathString, - buildTreeRecursive_MUTATE(path, trees, originalPaths, metadata), - ) - trees[rootPathString].children.push(subTree) - children.push(subTree) - } + const alreadyAdded = pathString in trees + if (!alreadyAdded) { + const parentPath = EP.parentPath(path) + const subTree = elementPathTree(path, pathString, [], []) + trees[pathString] = subTree + const pathLastPart = EP.lastElementPathForPath(path) - return children -} + if (pathLastPart?.length === 1) { + // If the last part of the path is a single element, it should be added to the inner children. + // This would be a path like `a/b/c:d`. + trees[EP.toString(parentPath)].innerChildren.push(subTree) + } else { + // Otherwise this should be added to the props children. + trees[EP.toString(parentPath)].propsChildren.push(subTree) + } + } + } -function getChildrenPaths( - metadata: ElementInstanceMetadataMap, - rootPath: ElementPath, - paths: ElementPath[], -): ElementPath[] { - const element = metadata[EP.toString(rootPath)] + let workingPaths = [...originalPaths] + workingPaths.sort((a, b) => { + return EP.fullDepth(a) - EP.fullDepth(b) + }) + for (const workingPath of workingPaths) { + addPathToTree(workingPath) + } - // Grab the child elements from the element metadata, if available. - let childrenFromElement: ElementPath[] = [] - if ( - element != null && - isRight(element.element) && - (isJSXElement(element.element.value) || isJSXFragment(element.element.value)) && - element.element.value.children.length > 0 - ) { - childrenFromElement = element.element.value.children - .filter((child) => { + for (const elementMetadata of Object.values(metadata)) { + forEachRight(elementMetadata.element, (element) => { + if (isJSXElementLike(element)) { + let elementChildren: Array if (isFeatureEnabled('Condensed Navigator Entries')) { - // if Data Entries are enabled, we should always show them in the Navigator - return true + elementChildren = element.children } else { - return ( - !isJSXTextBlock(child) && - !isJSExpressionMapOrOtherJavaScript(child) && - !isJSIdentifier(child) && - !isJSPropertyAccess(child) && - !isJSElementAccess(child) - ) + elementChildren = element.children.filter((child) => { + switch (child.type) { + case 'JSX_TEXT_BLOCK': + case 'ATTRIBUTE_OTHER_JAVASCRIPT': + case 'JSX_MAP_EXPRESSION': + case 'JS_IDENTIFIER': + case 'JS_PROPERTY_ACCESS': + case 'JS_ELEMENT_ACCESS': + return false + case 'JSX_ELEMENT': + case 'JSX_CONDITIONAL_EXPRESSION': + case 'JSX_FRAGMENT': + case 'ATTRIBUTE_FUNCTION_CALL': + case 'ATTRIBUTE_NESTED_ARRAY': + case 'ATTRIBUTE_NESTED_OBJECT': + case 'ATTRIBUTE_VALUE': + return true + default: + assertNever(child) + } + }) } - }) - .map((child) => EP.appendToPath(rootPath, child.uid)) + for (const child of elementChildren) { + const childPath = EP.appendToPath(elementMetadata.elementPath, child.uid) + addPathToTree(childPath) + } + } + }) } - - // Then, grab any other child from the paths array, which is not included in the - // elements from the metadata. - const otherChildrenFromPaths = paths.filter( - (path) => - EP.isChildOf(path, rootPath) && - !childrenFromElement.some((other) => EP.pathsEqual(other, path)), - ) - - // If there are children outside the element metadata, need to merge the two and sort them. - // Otherwise, return the children from the meta. - return otherChildrenFromPaths.length > 0 - ? childrenFromElement - .concat(otherChildrenFromPaths) - .sort( - (a, b) => - paths.findIndex((p) => EP.pathsEqual(p, a)) - - paths.findIndex((p) => EP.pathsEqual(p, b)), - ) - : childrenFromElement } function getMissingParentPaths( @@ -159,32 +174,19 @@ function getReorderedPaths( metadata: ElementInstanceMetadataMap, missingParents: ElementPath[], ): ElementPath[] { - const elementsToReorder = original.filter((path) => { - const element = MetadataUtils.findElementByElementPath(metadata, path) - if (element == null) { - return false - } - return ( - MetadataUtils.isConditionalFromMetadata(element) || - MetadataUtils.isExpressionOtherJavascriptFromMetadata(element) || - MetadataUtils.isJSXMapExpressionFromMetadata(element) || - MetadataUtils.isIdentifierFromMetadata(element) || - MetadataUtils.isPropertyAccessFromMetadata(element) || - MetadataUtils.isElementAccessFromMetadata(element) - ) + const pathsToBeReordered = original.filter((path) => { + // Omit elements that have a missing ancestor. + return !missingParents.some((parentPath) => EP.isDescendantOf(path, parentPath)) }) - const pathsToBeReordered = original.filter( - (path) => - !elementsToReorder.some((other) => EP.pathsEqual(other, path)) && // omit conditionals, that will be reordered - !missingParents.some((parentPath) => EP.isDescendantOf(path, parentPath)), // omit elements that have a missing parent - ) - return elementsToReorder.reduce((paths, path) => { + + return original.reduce((paths, path) => { const index = getReorderedIndexInPaths(paths, metadata, path) if (index === 'do-not-reorder') { return paths } - const before = paths.slice(0, index) - const after = paths.slice(index) + const pathsWithout = paths.filter((pathEntry) => !EP.pathsEqual(pathEntry, path)) + const before = pathsWithout.slice(0, index) + const after = pathsWithout.slice(index) return [...before, path, ...after] }, pathsToBeReordered) } @@ -192,34 +194,73 @@ function getReorderedPaths( function getReorderedIndexInPaths( paths: ElementPath[], metadata: ElementInstanceMetadataMap, - conditionalPath: ElementPath, + pathToReorder: ElementPath, ): number | 'do-not-reorder' { - const index = paths.findIndex((path) => EP.isDescendantOf(path, conditionalPath)) - if (index >= 0) { - return index - } - - const parent = MetadataUtils.getParent(metadata, conditionalPath) + const parent = MetadataUtils.getParent(metadata, pathToReorder) if (parent == null || isLeft(parent.element)) { return 'do-not-reorder' } + const parentElement = parent.element.value - if (isJSXElement(parent.element.value) || isJSXFragment(parent.element.value)) { - const innerIndex = parent.element.value.children.findIndex((child) => { + if (isJSXElement(parentElement) || isJSXFragment(parentElement)) { + let innerIndex: number | null = null + let priorSiblings: Array = [] + for (let childIndex = 0; childIndex < parentElement.children.length; childIndex++) { + const child = parentElement.children[childIndex] const childPath = EP.appendToPath(parent.elementPath, child.uid) - return EP.pathsEqual(childPath, conditionalPath) - }) - const parentIndex = paths.findIndex((path) => EP.pathsEqual(parent.elementPath, path)) - if (parentIndex < 0) { + if (EP.pathsEqual(childPath, pathToReorder)) { + // We've found the item that we're trying to reorder, so record the index + // and stop searching. + innerIndex = childIndex + break + } else { + // As we haven't reached the element of interest, record + // this prior sibling for later use. + priorSiblings.push(child) + } + } + if (innerIndex == null) { return 'do-not-reorder' } - return parentIndex + innerIndex - } else if (isJSXConditionalExpression(parent.element.value)) { + + const parentIndex = paths.findIndex((path) => EP.pathsEqual(parent.elementPath, path)) + + if (innerIndex === 0) { + if (parentIndex < 0) { + return 'do-not-reorder' + } else { + // As this is the first item, shift the index past the parent. + return parentIndex + 1 + } + } else { + const priorSiblingPaths = priorSiblings.map((sibling) => { + return EP.appendToPath(parent.elementPath, sibling.uid) + }) + // As there are prior siblings, we need to count those and their descendants, + // so as to shift this element past them. + const priorSiblingDescendants = paths.reduce((workingCount, path) => { + if ( + priorSiblingPaths.some((priorSiblingPath) => { + return EP.isDescendantOfOrEqualTo(path, priorSiblingPath) + }) + ) { + return workingCount + 1 + } else { + return workingCount + } + }, 0) + + // Shift by the parent position, add 1 to put it past the parent and then shift it by the + // count of the prior siblings and their descendants. + return parentIndex + 1 + priorSiblingDescendants + } + } else if (isJSXConditionalExpression(parentElement)) { const parentIndex = paths.findIndex((path) => EP.pathsEqual(parent.elementPath, path)) if (parentIndex < 0) { return 'do-not-reorder' + } else { + return parentIndex } - return parentIndex } else { return 'do-not-reorder' } @@ -236,7 +277,7 @@ export function getCanvasRoots(trees: ElementPathTrees): Array return [] } - return storyboardTree.children + return getElementPathTreeChildren(storyboardTree) } export function printTree(treeRoot: ElementPathTrees): string { @@ -247,7 +288,7 @@ export function printTree(treeRoot: ElementPathTrees): string { } outputText += EP.toString(element.path) outputText += '\n' - for (const child of element.children) { + for (const child of getElementPathTreeChildren(element)) { printElement(child, depth + 1) } } @@ -265,7 +306,7 @@ export function forEachChildOfTarget( ): void { const foundTree = getSubTree(treeRoot, target) if (foundTree != null) { - fastForEach(Object.values(foundTree.children), (subTree) => { + forEachElementPathTreeChild(foundTree, (subTree) => { handler(subTree.path) }) } diff --git a/editor/src/core/shared/element-path.ts b/editor/src/core/shared/element-path.ts index 8bfb72740ed1..a63ee8c85a88 100644 --- a/editor/src/core/shared/element-path.ts +++ b/editor/src/core/shared/element-path.ts @@ -642,14 +642,48 @@ export function findAmongAncestorsOfPath( } export function isDescendantOf(target: ElementPath, maybeAncestor: ElementPath): boolean { - const targetString = toString(target) - const maybeAncestorString = toString(maybeAncestor) - return ( - targetString !== maybeAncestorString && - targetString.startsWith(maybeAncestorString) && - (targetString[maybeAncestorString.length] === SceneSeparator || - targetString[maybeAncestorString.length] === ElementSeparator) - ) + // If the target has less parts than the potential ancestor, it's by default + // higher up the hierarchy. + if (target.parts.length < maybeAncestor.parts.length) { + return false + } + // Check if any of the shared (by index) parts are different, if any are that + // means these two are on different branches of the hierarchy. + for (let index = 0; index < maybeAncestor.parts.length - 1; index++) { + const maybeAncestorPart = maybeAncestor.parts[index] + const targetPart = target.parts[index] + if (!elementPathPartsEqual(maybeAncestorPart, targetPart)) { + return false + } + } + // As the rest of the parts are the same, we can check the last part to see + // if the target has less parts as that puts it higher up the hierarchy than the + // potential ancestor. + const lastTargetPart = target.parts[maybeAncestor.parts.length - 1] + const lastAncestorPart = maybeAncestor.parts[maybeAncestor.parts.length - 1] + if (lastTargetPart.length < lastAncestorPart.length) { + return false + } + // Check the elements of the last part to see if there are any differences + // as that means they're on a different branch. Limiting it to the length of + // the potential ancestor. + for (let partIndex = 0; partIndex < lastAncestorPart.length; partIndex++) { + const part = lastAncestorPart[partIndex] + if (lastTargetPart[partIndex] !== part) { + return false + } + } + // If the lengths of the parts and the lengths of the last parts are the same, + // since so far we've determined those to all match, then these are identical paths. + if ( + target.parts.length === maybeAncestor.parts.length && + lastTargetPart.length === lastAncestorPart.length + ) { + return false + } + + // Fallback meaning this is a descendant. + return true } export function getAncestorsForLastPart(path: ElementPath): ElementPath[] { From a2d6ac7ae1fd72a0edf02f84e8c0eb0377a0cb53 Mon Sep 17 00:00:00 2001 From: Balint Gabor <127662+gbalint@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:09:31 +0200 Subject: [PATCH 012/272] Fix subscribing mutation/resize observers during a build error (#6344) **Problem:** Followup to https://github.com/concrete-utopia/utopia/pull/6326 In a Remix project it can happen that in the dispatch flow we don't have the results of the rendering in the dom yet. It can even happen, that after a build error is fixed, we still don't have the canvas root container in the dom. That is a critical issue, because we attach the mutation/resize observers to the canvas root container element, so when we don't have that we can subscribe them, so the dom sample is not going to run when the rendering is finished. **Fix:** I needed an element, which is an ancestor of the canvas root container and 1 is always rendered 2 does not contain canvas controls or other content I choose canvas-container-outer, but I needed to modify its ancestors so it is always rendered, even when there is a build error. To make sure we don't observe unnecessary elements, I filtered the query for the resize observer to only include elements with the `data-uid` attribute. I needed to update the tests to make sure the observers from the previous domwalkermutablestate don't continue to fire when there is a change, because the outer canvas container can stay persistent between test runs. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode Fixes https://github.com/concrete-utopia/utopia/issues/6345 --- .../canvas/canvas-component-entry.tsx | 13 ++++++++---- .../canvas/canvas-wrapper-component.tsx | 21 +++++++++---------- editor/src/components/canvas/dom-walker.ts | 9 ++++---- .../components/canvas/ui-jsx.test-utils.tsx | 5 +++++ editor/src/templates/editor-canvas.tsx | 16 ++++++++------ 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/editor/src/components/canvas/canvas-component-entry.tsx b/editor/src/components/canvas/canvas-component-entry.tsx index ba919a3f5bbb..e9a4faaf3343 100644 --- a/editor/src/components/canvas/canvas-component-entry.tsx +++ b/editor/src/components/canvas/canvas-component-entry.tsx @@ -25,7 +25,11 @@ import type { } from './ui-jsx-canvas' import { DomWalkerInvalidatePathsCtxAtom, UiJsxCanvas, pickUiJsxCanvasProps } from './ui-jsx-canvas' -interface CanvasComponentEntryProps {} +export const CanvasContainerOuterId = 'canvas-container-outer' + +interface CanvasComponentEntryProps { + shouldRenderCanvas: boolean +} export const CanvasComponentEntry = React.memo((props: CanvasComponentEntryProps) => { const canvasStore = React.useContext(CanvasStateContext) @@ -85,7 +89,7 @@ const CanvasComponentEntryInner = React.memo((props: CanvasComponentEntryProps) <> {when(canvasProps == null, )}
- {canvasProps == null ? null : ( + {props.shouldRenderCanvas && canvasProps != null ? ( - )} + ) : null}
+ , ) }) diff --git a/editor/src/components/canvas/canvas-wrapper-component.tsx b/editor/src/components/canvas/canvas-wrapper-component.tsx index 099a094a4747..d3782584d585 100644 --- a/editor/src/components/canvas/canvas-wrapper-component.tsx +++ b/editor/src/components/canvas/canvas-wrapper-component.tsx @@ -85,17 +85,16 @@ export const CanvasWrapperComponent = React.memo(() => { // ^ prevents Monaco from pushing the inspector out }} > - {fatalErrors.length === 0 && !safeMode ? ( - - ) : null} + { + document.querySelectorAll(`#${CanvasContainerOuterId} [${UTOPIA_UID_KEY}]`).forEach((elem) => { domWalkerMutableState.resizeObserver.observe(elem) }) domWalkerMutableState.mutationObserver.observe(canvasRootContainer, MutationObserverConfig) diff --git a/editor/src/components/canvas/ui-jsx.test-utils.tsx b/editor/src/components/canvas/ui-jsx.test-utils.tsx index a95396aafcc8..f1866c8ece55 100644 --- a/editor/src/components/canvas/ui-jsx.test-utils.tsx +++ b/editor/src/components/canvas/ui-jsx.test-utils.tsx @@ -306,6 +306,8 @@ export function optOutFromCheckFileTimestamps() { }) } +let prevDomWalkerMutableState: DomWalkerMutableStateData | null = null + export async function renderTestEditorWithModel( rawModel: PersistentModel, awaitFirstDomReport: 'await-first-dom-report' | 'dont-await-first-dom-report', @@ -600,7 +602,10 @@ export async function renderTestEditorWithModel( patchedStoreFromFullStore(initialEditorStore, 'canvas-store'), ) + prevDomWalkerMutableState?.resizeObserver.disconnect() + prevDomWalkerMutableState?.mutationObserver.disconnect() const domWalkerMutableState = createDomWalkerMutableState(canvasStoreHook, asyncTestDispatch) + prevDomWalkerMutableState = domWalkerMutableState const lowPriorityStoreHook: UtopiaStoreAPI = createStoresAndState( patchedStoreFromFullStore(initialEditorStore, 'low-priority-store'), diff --git a/editor/src/templates/editor-canvas.tsx b/editor/src/templates/editor-canvas.tsx index cbccfb2c07c4..888acce8bc6f 100644 --- a/editor/src/templates/editor-canvas.tsx +++ b/editor/src/templates/editor-canvas.tsx @@ -695,6 +695,7 @@ interface EditorCanvasProps { builtinDependencies: BuiltInDependencies dispatch: EditorDispatch updateCanvasSize: (newValueOrUpdater: Size | ((oldValue: Size) => Size)) => void + shouldRenderCanvas: boolean } export class EditorCanvas extends React.Component { @@ -855,6 +856,10 @@ export class EditorCanvas extends React.Component { // we round the offset here, so all layers, the canvas, and controls use the same rounded value for positioning // instead of letting Chrome do it, because that results in funky artifacts (e.g. while scrolling, the layers don't "jump" pixels at the same time) + if (!this.props.shouldRenderCanvas) { + return + } + const nodeConnectorsDiv = createNodeConnectorsDiv( this.props.model.canvasOffset, this.props.model.scale, @@ -871,10 +876,9 @@ export class EditorCanvas extends React.Component { const canvasIsLive = isLiveMode(this.props.editor.mode) - const canvasControls = React.createElement(NewCanvasControls, { - windowToCanvasPosition: this.getPosition, - cursor, - }) + const canvasControls = ( + + ) const canvasLiveEditingStyle = canvasIsLive ? UtopiaStyles.canvas.live @@ -1070,9 +1074,9 @@ export class EditorCanvas extends React.Component { }, }, nodeConnectorsDiv, - React.createElement(CanvasComponentEntry, {}), + , canvasControls, - React.createElement(CursorComponent, {}), + , , ) } From d3a7bb85f57515ad9f55119e3f90b9c1a6441e6b Mon Sep 17 00:00:00 2001 From: Balint Gabor <127662+gbalint@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:31:54 +0200 Subject: [PATCH 013/272] Fix caching of null result of buildComponentRenderResult (#6352) **Problem:** When a component returns null, it is rerendered all the time. **Root cause:** The problem is in the caching of the result of `buildComponentRenderResult`. The cache is initialized with a `null` value, so when the value is `null` we rerun `buildComponentRenderResult` However, the value can be null just because the component renders nothing. **Commit Details:** - Created a new type for the `buildResult` type which includes an external value for the non-initialized state. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- .../ui-jsx-canvas-component-renderer.tsx | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/editor/src/components/canvas/ui-jsx-canvas-renderer/ui-jsx-canvas-component-renderer.tsx b/editor/src/components/canvas/ui-jsx-canvas-renderer/ui-jsx-canvas-component-renderer.tsx index 55954b926d6a..ce6cefe6446a 100644 --- a/editor/src/components/canvas/ui-jsx-canvas-renderer/ui-jsx-canvas-component-renderer.tsx +++ b/editor/src/components/canvas/ui-jsx-canvas-renderer/ui-jsx-canvas-component-renderer.tsx @@ -66,6 +66,25 @@ function tryToGetInstancePath( } } +type EmptyBuildResult = { + type: 'EMPTY_BUILD_RESULT' +} + +type RenderedBuildResult = { + type: 'RENDERED_BUILD_RESULT' + result: React.ReactElement | null +} + +type BuildResult = EmptyBuildResult | RenderedBuildResult + +function emptyBuildResult(): EmptyBuildResult { + return { type: 'EMPTY_BUILD_RESULT' } +} + +function renderedBuildResult(result: React.ReactElement | null): RenderedBuildResult { + return { type: 'RENDERED_BUILD_RESULT', result: result } +} + export function createComponentRendererComponent(params: { topLevelElementName: string | null filePath: string @@ -247,7 +266,7 @@ export function createComponentRendererComponent(params: { filePathMappings: rerenderUtopiaContext.filePathMappings, } - const buildResult = React.useRef(null) + const buildResult = React.useRef(emptyBuildResult()) let earlyReturn: EarlyReturn | null = null if (utopiaJsxComponent.arbitraryJSBlock != null) { @@ -299,11 +318,11 @@ export function createComponentRendererComponent(params: { break case 'EARLY_RETURN_VOID': earlyReturn = arbitraryBlockResult - buildResult.current = undefined as any + buildResult.current = renderedBuildResult(undefined as any) break case 'EARLY_RETURN_RESULT': earlyReturn = arbitraryBlockResult - buildResult.current = arbitraryBlockResult.result as any + buildResult.current = renderedBuildResult(arbitraryBlockResult.result as any) break default: assertNever(arbitraryBlockResult) @@ -350,10 +369,19 @@ export function createComponentRendererComponent(params: { null, ) } - } else if (shouldUpdate() || buildResult.current === null) { - buildResult.current = buildComponentRenderResult(utopiaJsxComponent.rootElement) + } else if (shouldUpdate() || buildResult.current.type === 'EMPTY_BUILD_RESULT') { + buildResult.current = renderedBuildResult( + buildComponentRenderResult(utopiaJsxComponent.rootElement), + ) + } + switch (buildResult.current.type) { + case 'EMPTY_BUILD_RESULT': + return null + case 'RENDERED_BUILD_RESULT': + return buildResult.current.result + default: + assertNever(buildResult.current) } - return buildResult.current } Component.displayName = `ComponentRenderer(${params.topLevelElementName})` Component.topLevelElementName = params.topLevelElementName From b142af62f0db122b14b4ce34a2be775fa256de47 Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Wed, 11 Sep 2024 17:55:05 +0300 Subject: [PATCH 014/272] fix(grid): move controls when changing content placement (#6350) **Problem:** Today the grid controls placeholder don't move when changing `content` placement ![10-45-psczv-wnkpg](https://github.com/user-attachments/assets/ea5d2623-0705-4337-8aa2-6d0139addec8) **Fix:** Copy `justifyContent` and `alignContent` props to the grid placeholder as well. **Note:** We should discuss how we can avoid these kinds of issues in the future - where there might be a future grid style prop that will not be copied to the grid control **Manual Tests:** I hereby swear that: - [X] I opened a hydrogen project and it loaded - [X] I could navigate to various routes in Preview mode --- .../ui-jsx-canvas-bugs.spec.tsx.snap | 2 + .../__snapshots__/ui-jsx-canvas.spec.tsx.snap | 257 ++++++++++++++++++ .../canvas/controls/grid-controls.tsx | 6 + editor/src/components/canvas/dom-walker.ts | 2 + .../store-deep-equality-instances-3.spec.ts | 7 + .../store/store-deep-equality-instances.ts | 1 + editor/src/core/shared/element-template.ts | 4 + 7 files changed, 279 insertions(+) diff --git a/editor/src/components/canvas/__snapshots__/ui-jsx-canvas-bugs.spec.tsx.snap b/editor/src/components/canvas/__snapshots__/ui-jsx-canvas-bugs.spec.tsx.snap index ea9b9c982796..8e7cd5aa4f45 100644 --- a/editor/src/components/canvas/__snapshots__/ui-jsx-canvas-bugs.spec.tsx.snap +++ b/editor/src/components/canvas/__snapshots__/ui-jsx-canvas-bugs.spec.tsx.snap @@ -158,6 +158,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -304,6 +305,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, diff --git a/editor/src/components/canvas/__snapshots__/ui-jsx-canvas.spec.tsx.snap b/editor/src/components/canvas/__snapshots__/ui-jsx-canvas.spec.tsx.snap index 301e9913f6e9..e57bf2a7375e 100644 --- a/editor/src/components/canvas/__snapshots__/ui-jsx-canvas.spec.tsx.snap +++ b/editor/src/components/canvas/__snapshots__/ui-jsx-canvas.spec.tsx.snap @@ -199,6 +199,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -368,6 +369,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -832,6 +834,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -1145,6 +1148,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -1313,6 +1317,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -1481,6 +1486,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -1649,6 +1655,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -1922,6 +1929,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -2091,6 +2099,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -2366,6 +2375,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -2638,6 +2648,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -2807,6 +2818,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -2956,6 +2968,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -3246,6 +3259,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -3415,6 +3429,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -3791,6 +3806,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -4133,6 +4149,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -4330,6 +4347,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -4493,6 +4511,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -4690,6 +4709,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -4853,6 +4873,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -5050,6 +5071,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -5213,6 +5235,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -5554,6 +5577,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -5723,6 +5747,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -6320,6 +6345,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -6883,6 +6909,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -7286,6 +7313,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -7655,6 +7683,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -7872,6 +7901,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -8055,6 +8085,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -8272,6 +8303,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -8455,6 +8487,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -8672,6 +8705,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -8855,6 +8889,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -9258,6 +9293,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -9627,6 +9663,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -9844,6 +9881,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -10027,6 +10065,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -10244,6 +10283,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -10427,6 +10467,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -10644,6 +10685,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -10827,6 +10869,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -11230,6 +11273,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -11599,6 +11643,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -11816,6 +11861,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -11999,6 +12045,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -12216,6 +12263,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -12399,6 +12447,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -12616,6 +12665,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -12799,6 +12849,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -13083,6 +13134,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -13252,6 +13304,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -13462,6 +13515,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -13612,6 +13666,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -13762,6 +13817,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -14034,6 +14090,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -14203,6 +14260,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -14465,6 +14523,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -14755,6 +14814,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -14924,6 +14984,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -15317,6 +15378,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -15675,6 +15737,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -15892,6 +15955,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -16109,6 +16173,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -16326,6 +16391,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -16616,6 +16682,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -16785,6 +16852,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -17178,6 +17246,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -17536,6 +17605,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -17753,6 +17823,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -17970,6 +18041,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -18187,6 +18259,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -18471,6 +18544,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -18640,6 +18714,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -18850,6 +18925,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -19000,6 +19076,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -19150,6 +19227,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -19434,6 +19512,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -19603,6 +19682,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -19918,6 +19998,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -20199,6 +20280,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -20350,6 +20432,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -20501,6 +20584,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -20801,6 +20885,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -20985,6 +21070,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -21448,6 +21534,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -21730,6 +21817,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -22029,6 +22117,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -22213,6 +22302,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -22676,6 +22766,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -22958,6 +23049,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -23258,6 +23350,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -23442,6 +23535,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -23956,6 +24050,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -24289,6 +24384,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -24589,6 +24685,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -24773,6 +24870,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -25287,6 +25385,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -25620,6 +25719,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -25891,6 +25991,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -26060,6 +26161,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -26209,6 +26311,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -26603,6 +26706,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -26772,6 +26876,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -28699,6 +28804,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -30172,6 +30278,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -31611,6 +31718,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -32232,6 +32340,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -32581,6 +32690,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -33202,6 +33312,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -33551,6 +33662,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -34172,6 +34284,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -34521,6 +34634,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -35180,6 +35294,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -35571,6 +35686,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -36230,6 +36346,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -36621,6 +36738,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -37280,6 +37398,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -37671,6 +37790,7 @@ export var storyboard = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -37965,6 +38085,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -38134,6 +38255,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -38378,6 +38500,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -38545,6 +38668,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -38712,6 +38836,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -38985,6 +39110,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -39154,6 +39280,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -39370,6 +39497,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -39642,6 +39770,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -39811,6 +39940,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -40131,6 +40261,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -40449,6 +40580,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -40618,6 +40750,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -40895,6 +41028,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -41121,6 +41255,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -41296,6 +41431,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -41596,6 +41732,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -41780,6 +41917,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -42134,6 +42272,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -42310,6 +42449,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -42763,6 +42903,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -42947,6 +43088,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -43303,6 +43445,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -43479,6 +43622,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -43863,6 +44007,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -44031,6 +44176,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -44824,6 +44970,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -44975,6 +45122,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -45126,6 +45274,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -45277,6 +45426,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -45430,6 +45580,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -45581,6 +45732,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -45732,6 +45884,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -45883,6 +46036,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -46102,6 +46256,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -46282,6 +46437,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -46435,6 +46591,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -46586,6 +46743,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -46737,6 +46895,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -46888,6 +47047,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -47039,6 +47199,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -47190,6 +47351,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -47341,6 +47503,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -47492,6 +47655,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -47643,6 +47807,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -47794,6 +47959,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -47945,6 +48111,7 @@ export var App = (props) => { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -48235,6 +48402,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -48404,6 +48572,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -48797,6 +48966,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -49155,6 +49325,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -49372,6 +49543,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -49589,6 +49761,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -49806,6 +49979,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -50096,6 +50270,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -50265,6 +50440,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -50657,6 +50833,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -51014,6 +51191,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -51231,6 +51409,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -51448,6 +51627,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -51665,6 +51845,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -51955,6 +52136,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -52124,6 +52306,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -52560,6 +52743,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -52961,6 +53145,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -53178,6 +53363,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -53395,6 +53581,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -53612,6 +53799,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -53908,6 +54096,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -54092,6 +54281,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -54355,6 +54545,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -54531,6 +54722,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -54805,6 +54997,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -54951,6 +55144,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -55145,6 +55339,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -55301,6 +55496,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -55457,6 +55653,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -55718,6 +55915,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -55864,6 +56062,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -56116,6 +56315,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -56310,6 +56510,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -56467,6 +56668,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -56716,6 +56918,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -56862,6 +57065,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -57124,6 +57328,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -57295,6 +57500,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -57544,6 +57750,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -57690,6 +57897,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -57839,6 +58047,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -58096,6 +58305,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -58242,6 +58452,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -58469,6 +58680,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -58645,6 +58857,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -58896,6 +59109,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -59042,6 +59256,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -59366,6 +59581,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -59556,6 +59772,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -59746,6 +59963,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -59996,6 +60214,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -60142,6 +60361,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -60308,6 +60528,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -60603,6 +60824,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -60772,6 +60994,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -61278,6 +61501,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -61434,6 +61658,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -61704,6 +61929,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -61972,6 +62198,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -62164,6 +62391,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -62354,6 +62582,7 @@ export var storyboard = ( "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -62631,6 +62860,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -62800,6 +63030,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -62998,6 +63229,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -63165,6 +63397,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -63440,6 +63673,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -63609,6 +63843,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -63758,6 +63993,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -64063,6 +64299,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -64232,6 +64469,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -64650,6 +64888,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -65033,6 +65272,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -65264,6 +65504,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -65465,6 +65706,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -65632,6 +65874,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -65863,6 +66106,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -66064,6 +66308,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -66231,6 +66476,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -66462,6 +66708,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -66663,6 +66910,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -66830,6 +67078,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -67104,6 +67353,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -67273,6 +67523,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -67422,6 +67673,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -67706,6 +67958,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -67875,6 +68128,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -68092,6 +68346,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -68279,6 +68534,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, @@ -68436,6 +68692,7 @@ Object { "label": null, "nonRoundedGlobalFrame": null, "specialSizeMeasurements": Object { + "alignContent": null, "alignItems": null, "borderRadius": null, "clientHeight": 0, diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index f3d47c9991f8..e9732e84bfff 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -378,6 +378,8 @@ export type GridData = { gridTemplateColumnsFromProps: GridAutoOrTemplateBase | null gridTemplateRowsFromProps: GridAutoOrTemplateBase | null gap: number | null + justifyContent: string | null + alignContent: string | null rowGap: number | null columnGap: number | null padding: Sides @@ -435,6 +437,8 @@ export function useGridData(elementPaths: ElementPath[]): GridData[] { gap: gap, rowGap: rowGap, columnGap: columnGap, + justifyContent: targetGridContainer.specialSizeMeasurements.justifyContent, + alignContent: targetGridContainer.specialSizeMeasurements.alignContent, padding: padding, rows: rows, columns: columns, @@ -770,6 +774,8 @@ export const GridControls = controlForStrategyMemoized(({ tar border: `1px solid ${ activelyDraggingOrResizingCell != null ? colorTheme.primary.value : 'transparent' }`, + justifyContent: grid.justifyContent ?? 'initial', + alignContent: grid.alignContent ?? 'initial', pointerEvents: 'none', padding: grid.padding == null diff --git a/editor/src/components/canvas/dom-walker.ts b/editor/src/components/canvas/dom-walker.ts index 3ff63324bf26..9a0eae756546 100644 --- a/editor/src/components/canvas/dom-walker.ts +++ b/editor/src/components/canvas/dom-walker.ts @@ -681,6 +681,7 @@ function getSpecialMeasurements( const parentTextDirection = eitherToMaybe(parseDirection(parentElementStyle?.direction, null)) const justifyContent = getFlexJustifyContent(elementStyle.justifyContent) + const alignContent = getFlexAlignment(elementStyle.alignContent) const alignItems = getFlexAlignment(elementStyle.alignItems) const margin = applicative4Either( @@ -877,6 +878,7 @@ function getSpecialMeasurements( gap, flexDirection, justifyContent, + alignContent, alignItems, element.localName, childrenCount, diff --git a/editor/src/components/editor/store/store-deep-equality-instances-3.spec.ts b/editor/src/components/editor/store/store-deep-equality-instances-3.spec.ts index 02cbcf84fcec..808524bc5a1d 100644 --- a/editor/src/components/editor/store/store-deep-equality-instances-3.spec.ts +++ b/editor/src/components/editor/store/store-deep-equality-instances-3.spec.ts @@ -265,6 +265,7 @@ describe('SpecialSizeMeasurementsKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', + alignContent: 'auto', alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -383,6 +384,7 @@ describe('SpecialSizeMeasurementsKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', + alignContent: 'auto', alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -556,6 +558,7 @@ describe('ElementInstanceMetadataKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', + alignContent: 'auto', alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -706,6 +709,7 @@ describe('ElementInstanceMetadataKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', + alignContent: 'auto', alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -881,6 +885,7 @@ describe('ElementInstanceMetadataMapKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', + alignContent: 'auto', alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -1033,6 +1038,7 @@ describe('ElementInstanceMetadataMapKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', + alignContent: 'auto', alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -1185,6 +1191,7 @@ describe('ElementInstanceMetadataMapKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', + alignContent: 'auto', alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, diff --git a/editor/src/components/editor/store/store-deep-equality-instances.ts b/editor/src/components/editor/store/store-deep-equality-instances.ts index e19d4f36fab4..a360d4d1eeca 100644 --- a/editor/src/components/editor/store/store-deep-equality-instances.ts +++ b/editor/src/components/editor/store/store-deep-equality-instances.ts @@ -2276,6 +2276,7 @@ export function SpecialSizeMeasurementsKeepDeepEquality(): KeepDeepEqualityCall< newSize.gap, newSize.flexDirection, newSize.justifyContent, + newSize.alignContent, newSize.alignItems, newSize.htmlElementName, newSize.renderedChildrenCount, diff --git a/editor/src/core/shared/element-template.ts b/editor/src/core/shared/element-template.ts index 7db708de5331..e26e1e1496e1 100644 --- a/editor/src/core/shared/element-template.ts +++ b/editor/src/core/shared/element-template.ts @@ -2810,6 +2810,7 @@ export interface SpecialSizeMeasurements { gap: number | null flexDirection: FlexDirection | null justifyContent: FlexJustifyContent | null + alignContent: FlexAlignment | null alignItems: FlexAlignment | null htmlElementName: string renderedChildrenCount: number @@ -2859,6 +2860,7 @@ export function specialSizeMeasurements( gap: number | null, flexDirection: FlexDirection | null, justifyContent: FlexJustifyContent | null, + alignContent: FlexAlignment | null, alignItems: FlexAlignment | null, htmlElementName: string, renderedChildrenCount: number, @@ -2909,6 +2911,7 @@ export function specialSizeMeasurements( gap, flexDirection, justifyContent, + alignContent, alignItems, htmlElementName, renderedChildrenCount, @@ -2963,6 +2966,7 @@ export const emptySpecialSizeMeasurements = specialSizeMeasurements( null, null, null, + null, 'div', 0, null, From 22bd0734dc07cbd0a0d4e4612cdde0ff3d26f8f2 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Thu, 12 Sep 2024 16:56:53 +0200 Subject: [PATCH 015/272] Fix active grid cell border during move (#6356) **Problem:** The new active cell indicator style introduce in https://github.com/concrete-utopia/utopia/pull/6301 doesn't correctly show the active cell borders. **Fix:** Fix that. | Before | After | |-------------|-----------| | ![Kapture 2024-09-12 at 13 38 42](https://github.com/user-attachments/assets/c040c735-85b9-477e-9390-501536ed531d) | ![Kapture 2024-09-12 at 13 39 10](https://github.com/user-attachments/assets/78820b33-0d11-414c-96a9-3dd8eb2ec3c9) | --- .../components/canvas/controls/grid-controls.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index e9732e84bfff..688df97ef115 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -815,11 +815,13 @@ export const GridControls = controlForStrategyMemoized(({ tar ? features.Grid.dotgridColor : 'transparent' - const borderColor = + const isActiveCell = countedColumn === currentHoveredCell?.column && countedRow === currentHoveredCell?.row - ? colorTheme.brandNeonPink.value - : features.Grid.inactiveGridColor + + const borderColor = isActiveCell + ? colorTheme.brandNeonPink.value + : features.Grid.inactiveGridColor return (
(({ tar borderTop: gridPlaceholderBorder(borderColor), borderLeft: gridPlaceholderBorder(borderColor), borderBottom: - countedRow >= grid.rows || (grid.rowGap != null && grid.rowGap > 0) + isActiveCell || + countedRow >= grid.rows || + (grid.rowGap != null && grid.rowGap > 0) ? gridPlaceholderBorder(borderColor) : undefined, borderRight: + isActiveCell || countedColumn >= grid.columns || (grid.columnGap != null && grid.columnGap > 0) ? gridPlaceholderBorder(borderColor) From 42942aaea3b429a3845145f1582a6d377ab91601 Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Thu, 12 Sep 2024 18:54:16 +0300 Subject: [PATCH 016/272] fix(inspector): queue inspector focus in a microtask to prevent flushSync (#6358) **Problem:** Today triggering a dropdown from the inspector causes a `flushSync` error **Fix:** Queue the `dispatch` in the inspector focus in a microtask to prevent this React error - [X] I opened a hydrogen project and it loaded - [X] I could navigate to various routes in Preview mode --- editor/src/components/inspector/inspector.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/editor/src/components/inspector/inspector.tsx b/editor/src/components/inspector/inspector.tsx index e98d2a548c41..ead15872c320 100644 --- a/editor/src/components/inspector/inspector.tsx +++ b/editor/src/components/inspector/inspector.tsx @@ -341,7 +341,9 @@ export const Inspector = React.memo((props: InspectorProps) => { const onFocus = React.useCallback( (event: React.FocusEvent) => { if (focusedPanel !== 'inspector') { - dispatch([setFocus('inspector')], 'inspector') + queueMicrotask(() => { + dispatch([setFocus('inspector')], 'inspector') + }) } }, [dispatch, focusedPanel], From ba474502fe7772d420a084949e6076039348980b Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:09:44 +0200 Subject: [PATCH 017/272] Update grid placeholders during resize (#6360) **Problem:** The grid placeholders don't resize live while resizing a grid child (with fixed size). **Fix:** Rerender the grid during resize, so its computed template is picked up. | Before | After | |---------|----------| | ![Kapture 2024-09-12 at 18 38 52](https://github.com/user-attachments/assets/ce491425-d5ae-4970-8997-967356610da9) | ![Kapture 2024-09-12 at 18 38 22](https://github.com/user-attachments/assets/978e0923-b9f6-414f-98cd-5a12add04948) | Fixes #6359 --- .../strategies/basic-resize-strategy.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx index ba16fa986e4d..60eccfac3a28 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx @@ -213,11 +213,17 @@ export function basicResizeStrategy( elementParentBounds?.height, ) + const gridsToRerender = selectedElements + .filter((element) => MetadataUtils.isGridCell(canvasState.startingMetadata, element)) + .map(EP.parentPath) + + const elementsToRerender = [...selectedElements, ...gridsToRerender] + return strategyApplicationResult([ adjustCssLengthProperties('always', selectedElement, null, resizeProperties), updateHighlightedViews('mid-interaction', []), setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - setElementsToRerenderCommand(selectedElements), + setElementsToRerenderCommand(elementsToRerender), pushIntendedBoundsAndUpdateGroups( [{ target: selectedElement, frame: resizedBounds }], 'starting-metadata', From 68d13787833be4decd2f0c97a70e75a426ceaeb6 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:50:01 +0200 Subject: [PATCH 018/272] Grid reorder (#6351) **Problem:** Moving grid elements currently means only explicitly setting their grid positioning props (row, column), which has two issues: 1. it does not reorder elements in the code nor the navigator 2. it does not leverage the grid intrinsic ordering, those properties should be set only when strictly necessary **Fix:** Extend the strategy so that it prioritizes reordering instead of explicit positioning, and even in the cases where it needs to use row/col props it will still reorder based on the starting index position in the grid hierarchy (left-right, top-bottom). Fixes #6355 --- .../strategies/flex-reorder-strategy.tsx | 1 - .../strategies/flow-reorder-strategy.tsx | 1 - .../strategies/grid-helpers.ts | 223 ++++++++++++++-- ...-rearrange-move-strategy.spec.browser2.tsx | 249 +++++++++++++++++- .../strategies/reorder-utils.ts | 1 - 5 files changed, 442 insertions(+), 33 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/flex-reorder-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/flex-reorder-strategy.tsx index 71c2ee5e0533..74cdcf6be833 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/flex-reorder-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/flex-reorder-strategy.tsx @@ -96,7 +96,6 @@ export function flexReorderStrategy( return interactionSession == null ? emptyStrategyApplicationResult : applyReorderCommon( - originalTargets, retargetedTargets, canvasState, interactionSession, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/flow-reorder-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/flow-reorder-strategy.tsx index d87eff82e39b..97de575b346f 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/flow-reorder-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/flow-reorder-strategy.tsx @@ -93,7 +93,6 @@ export function flowReorderStrategy( return interactionSession == null ? emptyStrategyApplicationResult : applyReorderCommon( - originalTargets, retargetedTargets, canvasState, interactionSession, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index aa51581ec657..437329d52b4b 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -1,6 +1,10 @@ import type { ElementPath } from 'utopia-shared/src/types' import { MetadataUtils } from '../../../../core/model/element-metadata-utils' -import type { ElementInstanceMetadataMap } from '../../../../core/shared/element-template' +import * as EP from '../../../../core/shared/element-path' +import type { + ElementInstanceMetadataMap, + GridPositionValue, +} from '../../../../core/shared/element-template' import { gridPositionValue, type ElementInstanceMetadata, @@ -19,15 +23,16 @@ import { type WindowPoint, } from '../../../../core/shared/math-utils' import * as PP from '../../../../core/shared/property-path' +import { absolute } from '../../../../utils/utils' +import { cssNumber, isCSSKeyword } from '../../../inspector/common/css-utils' import type { CanvasCommand } from '../../commands/commands' +import { deleteProperties } from '../../commands/delete-properties-command' +import { reorderElement } from '../../commands/reorder-element-command' +import { setCssLengthProperty } from '../../commands/set-css-length-command' import { setProperty } from '../../commands/set-property-command' import { canvasPointToWindowPoint } from '../../dom-lookup' -import type { DragInteractionData } from '../interaction-state' import type { GridCustomStrategyState, InteractionCanvasState } from '../canvas-strategy-types' -import * as EP from '../../../../core/shared/element-path' -import { deleteProperties } from '../../commands/delete-properties-command' -import { cssNumber, isCSSKeyword } from '../../../inspector/common/css-utils' -import { setCssLengthProperty } from '../../commands/set-css-length-command' +import type { DragInteractionData } from '../interaction-state' import type { GridCellCoordinates } from './grid-cell-bounds' import { getCellWindowRect, @@ -114,7 +119,6 @@ export function runGridRearrangeMove( targetRootCell: null, } } - const gridTemplate = containerMetadata.specialSizeMeasurements.containerGridProperties const cellGridProperties = getElementGridProperties(originalElementMetadata, targetCellUnderMouse) @@ -137,20 +141,6 @@ export function runGridRearrangeMove( coordsDiff.column, ) - const targetRootCell = gridCellCoordinates(row.start, column.start) - - const windowRect = getCellWindowRect(targetRootCell) - - const absoluteMoveCommands = - windowRect == null - ? [] - : gridChildAbsoluteMoveCommands( - MetadataUtils.findElementByElementPath(jsxMetadata, targetElement), - windowRect, - interactionData, - { scale: canvasScale, canvasOffset: canvasOffset }, - ) - const gridCellMoveCommands = setGridPropsCommands(targetElement, gridTemplate, { gridColumnStart: gridPositionValue(column.start), gridColumnEnd: gridPositionValue(column.end), @@ -158,12 +148,103 @@ export function runGridRearrangeMove( gridRowStart: gridPositionValue(row.start), }) - return { - commands: [...gridCellMoveCommands, ...absoluteMoveCommands], - targetCell: targetCellData ?? customState.targetCellData, - originalRootCell: rootCell, - draggingFromCell: draggingFromCell, - targetRootCell: targetRootCell, + const gridTemplateColumns = + gridTemplate.gridTemplateColumns?.type === 'DIMENSIONS' + ? gridTemplate.gridTemplateColumns.dimensions.length + : 1 + + // The "pure" index in the grid children for the cell under mouse + const possiblyReorderIndex = getGridPositionIndex({ + row: targetCellUnderMouse.row, + column: targetCellUnderMouse.column, + gridTemplateColumns: gridTemplateColumns, + }) + + // The siblings of the grid element being moved + const siblings = MetadataUtils.getChildrenUnordered(jsxMetadata, EP.parentPath(selectedElement)) + .filter((s) => !EP.pathsEqual(s.elementPath, selectedElement)) + .map( + (s, index): SortableGridElementProperties => ({ + ...s.specialSizeMeasurements.elementGridProperties, + index: index, + path: s.elementPath, + }), + ) + + // Sort the siblings and the cell under mouse ascending based on their grid coordinates, so that + // the indexes grow left-right, top-bottom. + const cellsSortedByPosition = siblings + .concat({ + ...{ + gridColumnStart: gridPositionValue(targetCellUnderMouse.column), + gridColumnEnd: gridPositionValue(targetCellUnderMouse.column), + gridRowStart: gridPositionValue(targetCellUnderMouse.row), + gridRowEnd: gridPositionValue(targetCellUnderMouse.row), + }, + path: selectedElement, + index: siblings.length + 1, + }) + .sort(sortElementsByGridPosition(gridTemplateColumns)) + + // If rearranging, reorder to the index based on the sorted cells arrays. + const indexInSortedCellsForRearrange = cellsSortedByPosition.findIndex((s) => + EP.pathsEqual(selectedElement, s.path), + ) + + const moveType = getGridMoveType({ + originalElementMetadata: originalElementMetadata, + possiblyReorderIndex: possiblyReorderIndex, + cellsSortedByPosition: cellsSortedByPosition, + }) + + switch (moveType) { + case 'rearrange': { + const targetRootCell = gridCellCoordinates(row.start, column.start) + const windowRect = getCellWindowRect(targetRootCell) + const absoluteMoveCommands = + windowRect == null + ? [] + : gridChildAbsoluteMoveCommands( + MetadataUtils.findElementByElementPath(jsxMetadata, targetElement), + windowRect, + interactionData, + { scale: canvasScale, canvasOffset: canvasOffset }, + ) + return { + commands: [ + ...gridCellMoveCommands, + ...absoluteMoveCommands, + reorderElement( + 'always', + selectedElement, + absolute(Math.max(indexInSortedCellsForRearrange, 0)), + ), + ], + targetCell: targetCellData ?? customState.targetCellData, + originalRootCell: rootCell, + draggingFromCell: draggingFromCell, + targetRootCell: gridCellCoordinates(row.start, column.start), + } + } + case 'reorder': { + return { + commands: [ + reorderElement('always', selectedElement, absolute(possiblyReorderIndex)), + deleteProperties('always', selectedElement, [ + PP.create('style', 'gridColumn'), + PP.create('style', 'gridRow'), + PP.create('style', 'gridColumnStart'), + PP.create('style', 'gridColumnEnd'), + PP.create('style', 'gridRowStart'), + PP.create('style', 'gridRowEnd'), + ]), + ], + targetCell: targetCellData ?? customState.targetCellData, + originalRootCell: rootCell, + draggingFromCell: draggingFromCell, + targetRootCell: targetCellUnderMouse, + } + } } } @@ -435,3 +516,91 @@ function gridChildAbsoluteMoveCommands( ), ] } + +type SortableGridElementProperties = GridElementProperties & { path: ElementPath; index: number } + +function sortElementsByGridPosition(gridTemplateColumns: number) { + return function (a: SortableGridElementProperties, b: SortableGridElementProperties): number { + function getPosition(index: number, e: GridElementProperties) { + if ( + e.gridColumnStart == null || + isCSSKeyword(e.gridColumnStart) || + e.gridRowStart == null || + isCSSKeyword(e.gridRowStart) + ) { + return index + } + + const row = e.gridRowStart.numericalPosition ?? 1 + const column = e.gridColumnStart.numericalPosition ?? 1 + + return (row - 1) * gridTemplateColumns + column - 1 + } + + return getPosition(a.index, a) - getPosition(b.index, b) + } +} + +type GridMoveType = + | 'reorder' // reorder the element in the code based on the ascending position, and remove explicit positioning props + | 'rearrange' // set explicit positioning props, and reorder based on the visual location + +function getGridMoveType(params: { + originalElementMetadata: ElementInstanceMetadata + possiblyReorderIndex: number + cellsSortedByPosition: SortableGridElementProperties[] +}): GridMoveType { + // For absolute move, just use rearrange. + // TODO: maybe worth reconsidering in the future? + if (MetadataUtils.isPositionAbsolute(params.originalElementMetadata)) { + return 'rearrange' + } + if (params.possiblyReorderIndex >= params.cellsSortedByPosition.length) { + return 'rearrange' + } + + const elementGridProperties = + params.originalElementMetadata.specialSizeMeasurements.elementGridProperties + + // The first element is intrinsically in order, so try to adjust for that + if (params.possiblyReorderIndex === 0) { + const isTheOnlyChild = params.cellsSortedByPosition.length === 1 + const isAlreadyTheFirstChild = EP.pathsEqual( + params.cellsSortedByPosition[0].path, + params.originalElementMetadata.elementPath, + ) + const isAlreadyAtOrigin = + gridPositionNumberValue(elementGridProperties.gridRowStart) === 1 && + gridPositionNumberValue(elementGridProperties.gridColumnStart) === 1 + if (isTheOnlyChild || isAlreadyTheFirstChild || isAlreadyAtOrigin) { + return 'reorder' + } + } + + const previousElement = params.cellsSortedByPosition.at(params.possiblyReorderIndex - 1) + if (previousElement == null) { + return 'rearrange' + } + const previousElementColumn = previousElement.gridColumnStart ?? null + const previousElementRow = previousElement.gridRowStart ?? null + return isGridPositionNumericValue(previousElementColumn) && + isGridPositionNumericValue(previousElementRow) + ? 'rearrange' + : 'reorder' +} + +function isGridPositionNumericValue(p: GridPosition | null): p is GridPositionValue { + return p != null && !(isCSSKeyword(p) && p.value === 'auto') +} + +function gridPositionNumberValue(p: GridPosition | null): number | null { + return isGridPositionNumericValue(p) ? p.numericalPosition : null +} + +function getGridPositionIndex(props: { + row: number + column: number + gridTemplateColumns: number +}): number { + return (props.row - 1) * props.gridTemplateColumns + props.column - 1 +} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx index ce0becd9726d..c942f983fa55 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx @@ -1,4 +1,7 @@ +import { MetadataUtils } from '../../../../core/model/element-metadata-utils' +import { isLeft } from '../../../../core/shared/either' import * as EP from '../../../../core/shared/element-path' +import { isJSXElement } from '../../../../core/shared/element-template' import { getRectCenter, localRectangle, @@ -11,6 +14,7 @@ import { GridCellTestId } from '../../controls/grid-controls' import { mouseDragFromPointToPoint } from '../../event-helpers.test-utils' import type { EditorRenderResult } from '../../ui-jsx.test-utils' import { renderTestEditorWithCode } from '../../ui-jsx.test-utils' +import type { GridCellCoordinates } from './grid-cell-bounds' import { gridCellTargetId } from './grid-cell-bounds' describe('grid rearrange move strategy', () => { @@ -454,21 +458,149 @@ export var storyboard = ( } }) }) + + describe('reorder', () => { + it('reorders an element without setting positioning (inside contiguous area)', async () => { + const editor = await renderTestEditorWithCode(ProjectCodeReorder, 'await-first-dom-report') + const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd, cells } = + await runReorderTest(editor, 'sb/scene/grid', 'orange', { row: 1, column: 3 }) + + expect({ gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd }).toEqual({ + gridColumnEnd: '', + gridColumnStart: '', + gridRowEnd: '', + gridRowStart: '', + }) + + expect(cells).toEqual(['pink', 'cyan', 'orange', 'blue']) + }) + it('reorders an element without setting positioning (edge of contiguous area)', async () => { + const editor = await renderTestEditorWithCode(ProjectCodeReorder, 'await-first-dom-report') + + const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd, cells } = + await runReorderTest(editor, 'sb/scene/grid', 'orange', { row: 2, column: 1 }) + + expect({ gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd }).toEqual({ + gridColumnEnd: '', + gridColumnStart: '', + gridRowEnd: '', + gridRowStart: '', + }) + + expect(cells).toEqual(['pink', 'cyan', 'blue', 'orange']) + }) + it('reorders an element setting positioning when outside of contiguous area', async () => { + const editor = await renderTestEditorWithCode(ProjectCodeReorder, 'await-first-dom-report') + + const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd, cells } = + await runReorderTest(editor, 'sb/scene/grid', 'orange', { row: 2, column: 2 }) + + expect({ gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd }).toEqual({ + gridColumnEnd: 'auto', + gridColumnStart: '2', + gridRowEnd: 'auto', + gridRowStart: '2', + }) + + expect(cells).toEqual(['pink', 'cyan', 'blue', 'orange']) + }) + it('reorders an element setting positioning also relative to other fixed elements', async () => { + const editor = await renderTestEditorWithCode(ProjectCodeReorder, 'await-first-dom-report') + + const first = await runReorderTest(editor, 'sb/scene/grid', 'orange', { row: 2, column: 2 }) + + expect({ + gridRowStart: first.gridRowStart, + gridRowEnd: first.gridRowEnd, + gridColumnStart: first.gridColumnStart, + gridColumnEnd: first.gridColumnEnd, + }).toEqual({ + gridColumnEnd: 'auto', + gridColumnStart: '2', + gridRowEnd: 'auto', + gridRowStart: '2', + }) + + expect(first.cells).toEqual(['pink', 'cyan', 'blue', 'orange']) + + const second = await runReorderTest(editor, 'sb/scene/grid', 'pink', { row: 2, column: 3 }) + + expect({ + gridRowStart: second.gridRowStart, + gridRowEnd: second.gridRowEnd, + gridColumnStart: second.gridColumnStart, + gridColumnEnd: second.gridColumnEnd, + }).toEqual({ + gridColumnEnd: 'auto', + gridColumnStart: '3', + gridRowEnd: 'auto', + gridRowStart: '2', + }) + + expect(second.cells).toEqual(['cyan', 'blue', 'orange', 'pink']) + }) + + it('reorders and removes positioning when moving back to contiguous', async () => { + const editor = await renderTestEditorWithCode(ProjectCodeReorder, 'await-first-dom-report') + + const first = await runReorderTest(editor, 'sb/scene/grid', 'orange', { row: 2, column: 2 }) + expect({ + gridRowStart: first.gridRowStart, + gridRowEnd: first.gridRowEnd, + gridColumnStart: first.gridColumnStart, + gridColumnEnd: first.gridColumnEnd, + }).toEqual({ + gridColumnEnd: 'auto', + gridColumnStart: '2', + gridRowEnd: 'auto', + gridRowStart: '2', + }) + + expect(first.cells).toEqual(['pink', 'cyan', 'blue', 'orange']) + + const second = await runReorderTest(editor, 'sb/scene/grid', 'orange', { row: 1, column: 1 }) + + expect({ + gridRowStart: second.gridRowStart, + gridRowEnd: second.gridRowEnd, + gridColumnStart: second.gridColumnStart, + gridColumnEnd: second.gridColumnEnd, + }).toEqual({ + gridColumnEnd: '', + gridColumnStart: '', + gridRowEnd: '', + gridRowStart: '', + }) + + expect(second.cells).toEqual(['orange', 'pink', 'cyan', 'blue']) + }) + }) }) async function runMoveTest( editor: EditorRenderResult, - props: { scale: number; pathString: string; testId: string }, + props: { + scale: number + pathString: string + testId: string + targetCell?: GridCellCoordinates + }, ) { const elementPathToDrag = EP.fromString(props.pathString) await selectComponentsForTest(editor, [elementPathToDrag]) - await editor.dispatch([CanvasActions.zoom(props.scale)], true) + if (props.scale !== 1) { + await editor.dispatch([CanvasActions.zoom(props.scale)], true) + } const sourceGridCell = editor.renderedDOM.getByTestId(GridCellTestId(elementPathToDrag)) const targetGridCell = editor.renderedDOM.getByTestId( - gridCellTargetId(EP.fromString('sb/scene/grid'), 2, 3), + gridCellTargetId( + EP.fromString('sb/scene/grid'), + props.targetCell?.row ?? 2, + props.targetCell?.column ?? 3, + ), ) const sourceRect = sourceGridCell.getBoundingClientRect() @@ -493,6 +625,39 @@ async function runMoveTest( return editor.renderedDOM.getByTestId(props.testId).style } +async function runReorderTest( + editor: EditorRenderResult, + gridTestId: string, + testId: string, + targetCell: GridCellCoordinates, +) { + const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd } = await runMoveTest(editor, { + scale: 1, + pathString: `${gridTestId}/${testId}`, + testId: testId, + targetCell: targetCell, + }) + + const element = editor.getEditorState().editor.jsxMetadata[gridTestId] + if (isLeft(element.element) || !isJSXElement(element.element.value)) { + throw new Error('expected jsx element') + } + + const cells = MetadataUtils.getChildrenOrdered( + editor.getEditorState().editor.jsxMetadata, + editor.getEditorState().editor.elementPathTree, + element.elementPath, + ) + + return { + gridRowStart: gridRowStart, + gridRowEnd: gridRowEnd, + gridColumnStart: gridColumnStart, + gridColumnEnd: gridColumnEnd, + cells: cells.map((c) => EP.toUid(c.elementPath)), + } +} + const ProjectCode = `import * as React from 'react' import { Scene, Storyboard, Placeholder } from 'utopia-api' @@ -572,3 +737,81 @@ export var storyboard = ( ) ` + +const ProjectCodeReorder = `import * as React from 'react' +import { Scene, Storyboard } from 'utopia-api' + +export var storyboard = ( + + +
+
+
+
+
+
+ + +) +` diff --git a/editor/src/components/canvas/canvas-strategies/strategies/reorder-utils.ts b/editor/src/components/canvas/canvas-strategies/strategies/reorder-utils.ts index 094a48b0656c..37cbc20bf15d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/reorder-utils.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/reorder-utils.ts @@ -36,7 +36,6 @@ function isRootOfGeneratedElement(target: ElementPath): boolean { } export function applyReorderCommon( - originalTargets: Array, targets: Array, canvasState: InteractionCanvasState, interactionSession: InteractionSession, From c67b665d85456d719c442c66cbc303c8fd1f0877 Mon Sep 17 00:00:00 2001 From: McKayla Lankau Date: Fri, 13 Sep 2024 06:25:17 -0400 Subject: [PATCH 019/272] kill rogue comma (#6362) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a comma floating on the canvas, now it's gone. Screenshot 2024-09-12 at 2 43 58 PM --- editor/src/components/canvas/canvas-component-entry.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/editor/src/components/canvas/canvas-component-entry.tsx b/editor/src/components/canvas/canvas-component-entry.tsx index e9a4faaf3343..52e1365dea3f 100644 --- a/editor/src/components/canvas/canvas-component-entry.tsx +++ b/editor/src/components/canvas/canvas-component-entry.tsx @@ -105,7 +105,6 @@ const CanvasComponentEntryInner = React.memo((props: CanvasComponentEntryProps) /> ) : null}
- , ) }) From a4ac2e49e4714f0a24e34736d13eb0eafd081f44 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:26:56 +0200 Subject: [PATCH 020/272] Fix stubborn elements outside visible area indicator arrow (#6367) **Problem:** The elements outside visible area indicator arrow sometimes shows up even when the element is obviously inside the visible area. **Fix:** Use the fresh metadata to detect the elements outside visible area, because otherwise the frame data might be stale on certain interactions (e.g. insertion). Also, simplified the code by removing some pre-cursor-positioning code that was not relevant anymore. | Before | After | |---------|-----------| | ![Kapture 2024-09-13 at 14 23 17](https://github.com/user-attachments/assets/0e9af6f4-7522-4461-a776-ca92cf6aaf21) | ![Kapture 2024-09-13 at 14 24 03](https://github.com/user-attachments/assets/4a8d9d69-2682-4ae2-b82b-a8d6e8ed8005) | Fixes #6366 --- .../elements-outside-visible-area-hooks.tsx | 91 ++++++------------- ...performance-regression-tests.spec.tsx.snap | 4 - .../performance-regression-tests.spec.tsx | 4 +- 3 files changed, 31 insertions(+), 68 deletions(-) diff --git a/editor/src/components/canvas/controls/elements-outside-visible-area-hooks.tsx b/editor/src/components/canvas/controls/elements-outside-visible-area-hooks.tsx index b256b4cef2e6..4908e3fc23c9 100644 --- a/editor/src/components/canvas/controls/elements-outside-visible-area-hooks.tsx +++ b/editor/src/components/canvas/controls/elements-outside-visible-area-hooks.tsx @@ -1,26 +1,16 @@ import React from 'react' import { MetadataUtils } from '../../../core/model/element-metadata-utils' import { mapDropNulls } from '../../../core/shared/array-utils' -import * as EP from '../../../core/shared/element-path' -import type { CanvasRectangle, WindowPoint, WindowRectangle } from '../../../core/shared/math-utils' +import type { CanvasRectangle, WindowPoint } from '../../../core/shared/math-utils' import { boundingRectangleArray, getRectCenter, - isFiniteRectangle, rectangleIntersection, windowRectangle, } from '../../../core/shared/math-utils' -import type { ElementPath } from '../../../core/shared/project-file-types' -import { Substores, useEditorState, useRefEditorState } from '../../editor/store/store-hook' +import { Substores, useEditorState } from '../../editor/store/store-hook' import { canvasPointToWindowPoint } from '../dom-lookup' -const topBarHeight = 40 // px - -type ElementOutsideVisibleArea = { - path: ElementPath - rect: WindowRectangle -} - export type ElementOutsideVisibleAreaIndicator = { position: WindowPoint } @@ -28,16 +18,6 @@ export type ElementOutsideVisibleAreaIndicator = { export function useElementsOutsideVisibleArea(): ElementOutsideVisibleAreaIndicator | null { const canvasBounds = document.getElementById('canvas-root')?.getBoundingClientRect() - const selectedViews = useEditorState( - Substores.selectedViews, - (store) => store.editor.selectedViews, - 'useElementsOutsideVisibleArea selectedViews', - ) - - const storeRef = useRefEditorState((store) => ({ - jsxMetadata: store.editor.jsxMetadata, - })) - const canvasScale = useEditorState( Substores.canvasOffset, (store) => store.editor.canvas.scale, @@ -49,21 +29,6 @@ export function useElementsOutsideVisibleArea(): ElementOutsideVisibleAreaIndica 'useElementsOutsideVisibleArea canvasOffset', ) - const framesByPathString = React.useMemo(() => { - const frames: { [key: string]: CanvasRectangle } = {} - for (const path of selectedViews) { - const metadata = MetadataUtils.findElementByElementPath(storeRef.current.jsxMetadata, path) - if ( - metadata != null && - metadata.globalFrame != null && - isFiniteRectangle(metadata.globalFrame) - ) { - frames[EP.toString(path)] = metadata.globalFrame - } - } - return frames - }, [storeRef, selectedViews]) - const scaledCanvasArea = React.useMemo(() => { if (canvasBounds == null) { return null @@ -71,54 +36,56 @@ export function useElementsOutsideVisibleArea(): ElementOutsideVisibleAreaIndica const scaleRatio = canvasScale > 1 ? canvasScale : 1 return windowRectangle({ x: canvasBounds.x * scaleRatio, - y: (canvasBounds.y - topBarHeight) * scaleRatio, + y: canvasBounds.y * scaleRatio, width: canvasBounds.width, height: canvasBounds.height, }) }, [canvasBounds, canvasScale]) - const elementsOutsideVisibleArea = React.useMemo(() => { - return mapDropNulls((path: ElementPath): ElementOutsideVisibleArea | null => { - if (scaledCanvasArea == null) { - return null - } - const frame = framesByPathString[EP.toString(path)] - if (frame == null) { + const selectedElementsFrames: CanvasRectangle[] = useEditorState( + Substores.metadata, + (store) => { + return mapDropNulls( + (view) => MetadataUtils.getFrameOrZeroRectInCanvasCoords(view, store.editor.jsxMetadata), + store.editor.selectedViews, + ) + }, + 'useElementsOutsideVisibleArea selectedElementsFrames', + ) + + return React.useMemo(() => { + if (scaledCanvasArea == null) { + return null + } + + const framesOutsideVisibleArea = mapDropNulls((frame) => { + if (frame.width === 0 || frame.height === 0) { return null } const topLeftPoint = canvasPointToWindowPoint(frame, canvasScale, canvasOffset) - const elementRect = windowRectangle({ + const elementWindowRect = windowRectangle({ x: topLeftPoint.x, - y: topLeftPoint.y - topBarHeight, + y: topLeftPoint.y, width: frame.width * canvasScale, height: frame.height * canvasScale, }) - - const isOutsideVisibleArea = rectangleIntersection(scaledCanvasArea, elementRect) == null - if (!isOutsideVisibleArea) { + if (rectangleIntersection(scaledCanvasArea, elementWindowRect) != null) { return null } - return { - path: path, - rect: elementRect, - } - }, selectedViews) - }, [selectedViews, canvasOffset, canvasScale, scaledCanvasArea, framesByPathString]) + return elementWindowRect + }, selectedElementsFrames) - return React.useMemo((): ElementOutsideVisibleAreaIndicator | null => { - if (elementsOutsideVisibleArea.length === 0) { - return null - } - const windowRect = boundingRectangleArray(elementsOutsideVisibleArea.map((a) => a.rect)) + const windowRect = boundingRectangleArray(framesOutsideVisibleArea) if (windowRect == null) { return null } + return { position: getRectCenter(windowRect), } - }, [elementsOutsideVisibleArea]) + }, [selectedElementsFrames, canvasOffset, canvasScale, scaledCanvasArea]) } export function getIndicatorAngleToTarget(from: WindowPoint, to: WindowPoint): number { diff --git a/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap b/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap index 6befd7b80f07..0bd2ca37513e 100644 --- a/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap +++ b/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap @@ -88,8 +88,6 @@ Array [ "/Symbol(react.memo)()///UtopiaSpiedExoticType(Symbol(react.fragment))", "/Symbol(react.forward_ref)(Styled(div))/div/Symbol(react.forward_ref)(Styled(div))/div", "/UtopiaSpiedFunctionComponent(SimpleFlexColumn)/div/ElementsOutsideVisibleAreaIndicator/Symbol(react.memo)(IndicatorArrow)", - "/div/ElementsOutsideVisibleAreaIndicator/IndicatorArrow/Symbol(react.memo)(Icon)", - "/div/ElementsOutsideVisibleAreaIndicator/IndicatorArrow/div:data-testid='indicator-elements-outside-visible-area'", "/div/div/NavigatorComponent/Symbol(react.memo)()", "/div/div/NavigatorComponent/Symbol(react.memo)(NavigatorDragLayer)", "/div/div/NavigatorComponent/UtopiaSpiedClass(AutoSizer)", @@ -750,8 +748,6 @@ Array [ "/Symbol(react.memo)()///UtopiaSpiedExoticType(Symbol(react.fragment))", "/Symbol(react.forward_ref)(Styled(div))/div/Symbol(react.forward_ref)(Styled(div))/div", "/UtopiaSpiedFunctionComponent(SimpleFlexColumn)/div/ElementsOutsideVisibleAreaIndicator/Symbol(react.memo)(IndicatorArrow)", - "/div/ElementsOutsideVisibleAreaIndicator/IndicatorArrow/Symbol(react.memo)(Icon)", - "/div/ElementsOutsideVisibleAreaIndicator/IndicatorArrow/div:data-testid='indicator-elements-outside-visible-area'", "/div/div/NavigatorComponent/Symbol(react.memo)()", "/div/div/NavigatorComponent/Symbol(react.memo)(NavigatorDragLayer)", "/div/div/NavigatorComponent/UtopiaSpiedClass(AutoSizer)", diff --git a/editor/src/core/performance/performance-regression-tests.spec.tsx b/editor/src/core/performance/performance-regression-tests.spec.tsx index 4a03e049119f..3c487db99578 100644 --- a/editor/src/core/performance/performance-regression-tests.spec.tsx +++ b/editor/src/core/performance/performance-regression-tests.spec.tsx @@ -183,7 +183,7 @@ describe('React Render Count Tests -', () => { const renderCountAfter = renderResult.getNumberOfRenders() // if this breaks, GREAT NEWS but update the test please :) - expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`532`) + expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`530`) expect(renderResult.getRenderInfo()).toMatchSnapshot() }) @@ -249,7 +249,7 @@ describe('React Render Count Tests -', () => { const renderCountAfter = renderResult.getNumberOfRenders() // if this breaks, GREAT NEWS but update the test please :) - expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`657`) + expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`655`) expect(renderResult.getRenderInfo()).toMatchSnapshot() }) }) From 9c636e6eebf77706ff0e0d9d5fe4fdcb62162850 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:28:14 +0200 Subject: [PATCH 021/272] Grids: don't use absolute for click to insert (#6364) **Problem:** Click-to-insert into grids uses absolute positioning, which is not ideal. **Fix:** Strip positioning props when click-to-insert. Fixes #6363 --- .../draw-to-insert-strategy.spec.browser2.tsx | 12 ++++++------ .../grid-draw-to-insert-strategy.tsx | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-strategy.spec.browser2.tsx index 09b3c6d1914b..b1d558488842 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-strategy.spec.browser2.tsx @@ -237,9 +237,9 @@ export var storyboard = ( gridColumn: '2', gridRow: '1', height: '100px', - left: '83px', - position: 'absolute', - top: '100px', + left: '', + position: '', + top: '', width: '100px', }) }) @@ -280,9 +280,9 @@ export var storyboard = ( gridColumn: '1', gridRow: '1', height: '100px', - left: '100px', - position: 'absolute', - top: '25px', + left: '', + position: '', + top: '', width: '100px', }) }) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx index a1a518dbef2c..a4fdd42e61e6 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx @@ -52,6 +52,9 @@ import { newReparentSubjects } from './reparent-helpers/reparent-strategy-helper import { getReparentTargetUnified } from './reparent-helpers/reparent-strategy-parent-lookup' import { stripNulls } from '../../../../core/shared/array-utils' import { showGridControls } from '../../commands/show-grid-controls-command' +import * as PP from '../../../../core/shared/property-path' +import { propertyToDelete, updateBulkProperties } from '../../commands/set-property-command' +import { deleteProperties } from '../../commands/delete-properties-command' export const gridDrawToInsertText: CanvasStrategyFactory = ( canvasState: InteractionCanvasState, @@ -218,9 +221,25 @@ const gridDrawToInsertStrategyInner = ? [] : getWrappingCommands(insertedElementPath, maybeWrapperWithUid) + const isClick = interactionData.type === 'DRAG' && interactionData.drag == null + + // for click-to-insert, don't use absolute positioning + const clickToInsertCommands = isClick + ? [ + deleteProperties('always', insertedElementPath, [ + PP.create('style', 'position'), + PP.create('style', 'top'), + PP.create('style', 'left'), + PP.create('style', 'bottom'), + PP.create('style', 'right'), + ]), + ] + : [] + return strategyApplicationResult( [ insertionCommand, + ...clickToInsertCommands, ...setGridPropsCommands(insertedElementPath, gridTemplate, { gridRowStart: { numericalPosition: gridCellCoordinates.row }, gridColumnStart: { numericalPosition: gridCellCoordinates.column }, From 1798bb8c8b5f0abca72d7f60efaea7b9eb1b93a3 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:40:01 +0200 Subject: [PATCH 022/272] Fix draw-to-insert into grid when going top-left of the origin (#6370) **Problem:** Draw-to-insert into a grid does not work if the drag vector goes top/left of the drag origin. **Fix:** Fix the origin calculation. Also, I added a TODO in the code to improve this strategy in an incremental PR. | Before | After | |-------|---------| | ![Kapture 2024-09-13 at 17 40 56](https://github.com/user-attachments/assets/218fb02c-4e6e-476f-9376-c7a963598959) | ![Kapture 2024-09-13 at 17 40 06](https://github.com/user-attachments/assets/9187b0bb-9c79-4859-93f4-168061da8de5) | Fixes #6369 --- .../grid-draw-to-insert-strategy.tsx | 82 +++++++------------ 1 file changed, 29 insertions(+), 53 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx index a4fdd42e61e6..7e4fac06a0b5 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx @@ -1,31 +1,27 @@ import type { ElementPath } from 'utopia-shared/src/types' import { MetadataUtils } from '../../../../core/model/element-metadata-utils' +import { stripNulls } from '../../../../core/shared/array-utils' import * as EP from '../../../../core/shared/element-path' -import type { - CanvasPoint, - CanvasRectangle, - Size, - WindowRectangle, -} from '../../../../core/shared/math-utils' +import type { CanvasPoint, CanvasRectangle, Size } from '../../../../core/shared/math-utils' import { canvasPoint, canvasRectangle, - canvasVector, - offsetPoint, + pointDifference, roundRectangleToNearestWhole, - scaleVector, size, - windowPoint, } from '../../../../core/shared/math-utils' +import * as PP from '../../../../core/shared/property-path' import { assertNever } from '../../../../core/shared/utils' import { EditorModes, type InsertionSubject } from '../../../editor/editor-modes' import { childInsertionPath } from '../../../editor/store/insertion-path' +import { deleteProperties } from '../../commands/delete-properties-command' import type { InsertElementInsertionSubject } from '../../commands/insert-element-insertion-subject' import { insertElementInsertionSubject } from '../../commands/insert-element-insertion-subject' +import { showGridControls } from '../../commands/show-grid-controls-command' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { wildcardPatch } from '../../commands/wildcard-patch-command' import { controlsForGridPlaceholders } from '../../controls/grid-controls' -import { canvasPointToWindowPoint } from '../../dom-lookup' +import { canvasPointToWindowPoint, windowToCanvasCoordinates } from '../../dom-lookup' import { getWrapperWithGeneratedUid, getWrappingCommands, @@ -50,11 +46,6 @@ import { import { getTargetCell, setGridPropsCommands } from './grid-helpers' import { newReparentSubjects } from './reparent-helpers/reparent-strategy-helpers' import { getReparentTargetUnified } from './reparent-helpers/reparent-strategy-parent-lookup' -import { stripNulls } from '../../../../core/shared/array-utils' -import { showGridControls } from '../../commands/show-grid-controls-command' -import * as PP from '../../../../core/shared/property-path' -import { propertyToDelete, updateBulkProperties } from '../../commands/set-property-command' -import { deleteProperties } from '../../commands/delete-properties-command' export const gridDrawToInsertText: CanvasStrategyFactory = ( canvasState: InteractionCanvasState, @@ -193,7 +184,11 @@ const gridDrawToInsertStrategyInner = const { gridCellCoordinates, cellWindowRectangle } = newTargetCell - const offset = getOffsetFromGridCell(interactionData, canvasState, cellWindowRectangle) + const cellCanvasOrigin = windowToCanvasCoordinates( + canvasState.scale, + canvasState.canvasOffset, + cellWindowRectangle, + ).canvasPositionRounded const defaultSize = interactionData.type === 'DRAG' && @@ -205,7 +200,7 @@ const gridDrawToInsertStrategyInner = const insertionCommand = getInsertionCommand( targetParent, insertionSubject, - getFrameForInsertion(interactionData, defaultSize, offset), + getFrameForInsertion(interactionData, defaultSize, cellCanvasOrigin), ) const gridTemplate = parent.specialSizeMeasurements.containerGridProperties @@ -245,6 +240,9 @@ const gridDrawToInsertStrategyInner = gridColumnStart: { numericalPosition: gridCellCoordinates.column }, gridRowEnd: { numericalPosition: gridCellCoordinates.row + 1 }, gridColumnEnd: { numericalPosition: gridCellCoordinates.column + 1 }, + // TODO! this is currently going to assign the element to the cell the interaction started in, + // however it would be good to instead assign the element to _all_ cells overlapping with the final + // inserted frame. }), ...wrappingCommands, ...stripNulls([ @@ -279,17 +277,22 @@ const gridDrawToInsertStrategyInner = function getFrameForInsertion( interactionData: DragInteractionData | HoverInteractionData, defaultSize: Size, - offset: CanvasPoint, + cellOrigin: CanvasPoint, ): CanvasRectangle { if (interactionData.type === 'DRAG') { - const origin = interactionData.drag ?? { x: defaultSize.width / 2, y: defaultSize.height / 2 } - - const { x, y } = { x: offset.x - origin.x, y: offset.y - origin.y } + const dragStart = interactionData.dragStart + const mouseAt = { + x: interactionData.dragStart.x + (interactionData.drag?.x ?? 0), + y: interactionData.dragStart.y + (interactionData.drag?.y ?? 0), + } + const width = Math.abs(interactionData.drag?.x ?? defaultSize.width) + const height = Math.abs(interactionData.drag?.y ?? defaultSize.height) - const { width, height } = - interactionData.drag == null - ? defaultSize - : { width: interactionData.drag.x, height: interactionData.drag.y } + const origin = canvasPoint({ + x: Math.min(dragStart.x, mouseAt.x), + y: Math.min(dragStart.y, mouseAt.y), + }) + const { x, y } = pointDifference(cellOrigin, origin) return roundRectangleToNearestWhole(canvasRectangle({ x, y, width, height })) } @@ -347,30 +350,3 @@ function getGridCellUnderCursor( mouseWindowPoint, ) } - -function getOffsetFromGridCell( - interactionData: DragInteractionData | HoverInteractionData, - canvasState: InteractionCanvasState, - cellWindowRectangle: WindowRectangle, -) { - const windowPointToUse = - interactionData.type === 'DRAG' - ? offsetPoint(interactionData.dragStart, interactionData.drag ?? canvasVector({ x: 0, y: 0 })) - : interactionData.point - - const mouseWindowPoint = canvasPointToWindowPoint( - windowPointToUse, - canvasState.scale, - canvasState.canvasOffset, - ) - - const { x, y } = scaleVector( - windowPoint({ - x: mouseWindowPoint.x - cellWindowRectangle.x, - y: mouseWindowPoint.y - cellWindowRectangle.y, - }), - 1 / canvasState.scale, - ) - - return canvasPoint({ x, y }) -} From efc219cebe57cc9d925d333c83d2b3c0148bafb4 Mon Sep 17 00:00:00 2001 From: Balint Gabor <127662+gbalint@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:47:49 +0200 Subject: [PATCH 023/272] Calculate global frame of grid cells (#6371) **Problem:** Grid strategies use DOM api to find grid cells under the mouse, find their bounding box, etc. That is against the strategy contract: strategies should rely on their input and should not inspect the dom. This PR is a first step to eliminate these: it introduces a function which calculates the global frames of grid cells from some fields of SpecialSizeMeasurements. Note: we use SpecialSizeMeasurements.containerGridProperties`, and that has a way more general type than necessary (it uses the same type as the parsed style prop, so it allows keywords and not just numbers). **TODO:** - [ ] refactor the types, and create a `ComputedGridContainerProperties` which only allows numbers in the dimensions - [ ] memoize the function - [ ] refactor grid helpers to rely on metadata and not on the dom api **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- .../strategies/grid-helpers.spec.browser2.tsx | 261 ++++++++++++++++++ .../strategies/grid-helpers.ts | 68 ++++- 2 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx new file mode 100644 index 000000000000..9712f1d1fb76 --- /dev/null +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx @@ -0,0 +1,261 @@ +import { matchInlineSnapshotBrowser } from '../../../../../test/karma-snapshots' +import { runDOMWalker } from '../../../editor/actions/action-creators' +import { makeTestProjectCodeWithSnippet, renderTestEditorWithCode } from '../../ui-jsx.test-utils' +import { getGlobalFramesOfGridCellsFromMetadata } from './grid-helpers' + +describe('Grids', () => { + it('can calculate global frames of grid cells', async () => { + const editor = await renderTestEditorWithCode( + makeTestProjectCodeWithSnippet(`
+
+
+
+
+
+
+
+
`), + 'await-first-dom-report', + ) + + await editor.dispatch([runDOMWalker()], true) + + // non-grids don't have cell measurements: + expect( + getGlobalFramesOfGridCellsFromMetadata( + editor.getEditorState().editor.jsxMetadata[ + 'utopia-storyboard-uid/scene-aaa/app-entity:grid/child' + ], + ), + ).toBeNull() + + // grids have cell measurements: + matchInlineSnapshotBrowser( + getGlobalFramesOfGridCellsFromMetadata( + editor.getEditorState().editor.jsxMetadata[ + 'utopia-storyboard-uid/scene-aaa/app-entity:grid' + ], + ), + `Array [ + Array [ + Object { + \"height\": 50, + \"width\": 150, + \"x\": 10, + \"y\": 10, + }, + Object { + \"height\": 50, + \"width\": 80, + \"x\": 170, + \"y\": 10, + }, + Object { + \"height\": 50, + \"width\": 119.5, + \"x\": 260, + \"y\": 10, + }, + Object { + \"height\": 50, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 10, + }, + ], + Array [ + Object { + \"height\": 83.25, + \"width\": 150, + \"x\": 10, + \"y\": 70, + }, + Object { + \"height\": 83.25, + \"width\": 80, + \"x\": 170, + \"y\": 70, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 260, + \"y\": 70, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 70, + }, + ], + Array [ + Object { + \"height\": 83.25, + \"width\": 150, + \"x\": 10, + \"y\": 163.25, + }, + Object { + \"height\": 83.25, + \"width\": 80, + \"x\": 170, + \"y\": 163.25, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 260, + \"y\": 163.25, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 163.25, + }, + ], + Array [ + Object { + \"height\": 83.25, + \"width\": 150, + \"x\": 10, + \"y\": 256.5, + }, + Object { + \"height\": 83.25, + \"width\": 80, + \"x\": 170, + \"y\": 256.5, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 260, + \"y\": 256.5, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 256.5, + }, + ], + Array [ + Object { + \"height\": 83.25, + \"width\": 150, + \"x\": 10, + \"y\": 349.75, + }, + Object { + \"height\": 83.25, + \"width\": 80, + \"x\": 170, + \"y\": 349.75, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 260, + \"y\": 349.75, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 349.75, + }, + ], +]`, + ) + }) +}) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index 437329d52b4b..caff66fee4bd 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -4,6 +4,7 @@ import * as EP from '../../../../core/shared/element-path' import type { ElementInstanceMetadataMap, GridPositionValue, + GridTemplate, } from '../../../../core/shared/element-template' import { gridPositionValue, @@ -12,9 +13,14 @@ import { type GridElementProperties, type GridPosition, } from '../../../../core/shared/element-template' -import type { CanvasVector, WindowRectangle } from '../../../../core/shared/math-utils' +import type { + CanvasRectangle, + CanvasVector, + WindowRectangle, +} from '../../../../core/shared/math-utils' import { canvasPoint, + canvasRectangle, isInfinityRectangle, offsetPoint, scaleVector, @@ -40,6 +46,7 @@ import { getGridCellUnderMouseRecursive, gridCellCoordinates, } from './grid-cell-bounds' +import type { Sides } from 'utopia-api/core' export function runGridRearrangeMove( targetElement: ElementPath, @@ -604,3 +611,62 @@ function getGridPositionIndex(props: { }): number { return (props.row - 1) * props.gridTemplateColumns + props.column - 1 } + +export function getGlobalFramesOfGridCellsFromMetadata( + metadata: ElementInstanceMetadata, +): Array> | null { + return getGlobalFramesOfGridCells(metadata.specialSizeMeasurements) +} + +export function getGlobalFramesOfGridCells({ + containerGridProperties, + rowGap, + columnGap, + padding, +}: { + containerGridProperties: GridContainerProperties + rowGap: number | null + columnGap: number | null + padding: Sides +}): Array> | null { + const columnWidths = gridTemplateToNumbers(containerGridProperties.gridTemplateColumns) + + const rowHeights = gridTemplateToNumbers(containerGridProperties.gridTemplateRows) + + if (columnWidths == null || rowHeights == null) { + return null + } + + const cellRects: Array> = [] + let yOffset = padding.top ?? 0 + rowHeights.forEach((height) => { + let xOffset = padding.left ?? 0 + const rowRects: CanvasRectangle[] = [] + columnWidths.forEach((width) => { + const rect = canvasRectangle({ x: xOffset, y: yOffset, width: width, height: height }) + rowRects.push(rect) + xOffset += width + (columnGap ?? 0) + }) + cellRects.push(rowRects) + yOffset += height + (rowGap ?? 0) + }) + + return cellRects +} + +function gridTemplateToNumbers(gridTemplate: GridTemplate | null): Array | null { + if (gridTemplate?.type !== 'DIMENSIONS') { + return null + } + + const result: Array = [] + + for (const dimension of gridTemplate.dimensions) { + if (dimension.type !== 'NUMBER') { + return null + } + result.push(dimension.value.value) + } + + return result +} From 677269af2e34c8a6c175666dcc5c96ae5b624f44 Mon Sep 17 00:00:00 2001 From: RheeseyB <1044774+Rheeseyb@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:49:09 +0100 Subject: [PATCH 024/272] Add ThirdPartyNotices.txt (#6365) **Problem:** Our project was missing a ThirdPartyNotices.txt **Fix:** Add one. This was generated using `@rnx-kit/third-party-notices`, which ironically doesn't have a `ThirdPartyNotices.txt`. --- ThirdPartyNotices.txt | 17465 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 17465 insertions(+) create mode 100644 ThirdPartyNotices.txt diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt new file mode 100644 index 000000000000..81a8cc0bda74 --- /dev/null +++ b/ThirdPartyNotices.txt @@ -0,0 +1,17465 @@ +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION + +This repository incorporates material as listed below or described in the code. + +======================================================================== + +@ampproject/remapping 2.2.1 +-- +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================== + +@babel/code-frame 7.23.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/compat-data 7.23.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/core 7.23.6 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/generator 7.23.6 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-annotate-as-pure 7.22.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-compilation-targets 7.23.6 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-create-class-features-plugin 7.23.6 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-environment-visitor 7.22.20 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-function-name 7.23.0 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-hoist-variables 7.22.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-member-expression-to-functions 7.23.0 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-module-imports 7.22.15 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-module-transforms 7.23.3 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-optimise-call-expression 7.22.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-plugin-utils 7.22.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-replace-supers 7.22.20 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-simple-access 7.22.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-skip-transparent-expression-wrappers 7.22.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-split-export-declaration 7.22.6 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-string-parser 7.23.4 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-validator-identifier 7.22.20 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helper-validator-option 7.23.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/helpers 7.23.6 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/highlight 7.23.4 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/parser 7.24.5 +-- +Copyright (C) 2012-2014 by various contributors (see AUTHORS) + +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. + +======================================================================== + +@babel/plugin-proposal-class-properties 7.16.7 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/plugin-proposal-export-namespace-from 7.14.5 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/plugin-syntax-export-namespace-from 7.8.3 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/plugin-transform-modules-commonjs 7.15.4 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/runtime 7.15.4 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/runtime-corejs3 7.15.4 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/standalone 7.15.7 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/template 7.22.15 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/traverse 7.23.6 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@babel/types 7.23.6 +-- +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +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. + +======================================================================== + +@emotion/cache 10.0.29 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/core 10.1.1 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/css 10.0.27 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/hash 0.8.0 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/is-prop-valid 1.1.0 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/memoize 0.7.4 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/react 11.1.2 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/serialize 0.11.16 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/sheet 0.9.4 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/styled 11.0.0 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/stylis 0.8.5 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/unitless 0.7.5 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/utils 0.11.3 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@emotion/weak-memoize 0.2.5 +-- +MIT License + +Copyright (c) Emotion team and other contributors + +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. + +======================================================================== + +@floating-ui/core 1.5.0 +-- +MIT License + +Copyright (c) 2021-present Floating UI contributors + +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. + +======================================================================== + +@floating-ui/dom 1.5.3 +-- +MIT License + +Copyright (c) 2021-present Floating UI contributors + +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. + +======================================================================== + +@floating-ui/react-dom 2.0.4 +-- +MIT License + +Copyright (c) 2021-present Floating UI contributors + +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. + +======================================================================== + +@floating-ui/utils 0.1.4 +-- +MIT License + +Copyright (c) 2021-present Floating UI contributors + +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. + +======================================================================== + +@jridgewell/gen-mapping 0.3.3 +-- +Copyright 2022 Justin Ridgewell + +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. + +======================================================================== + +@jridgewell/resolve-uri 3.1.0 +-- +Copyright 2019 Justin Ridgewell + +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. + +======================================================================== + +@jridgewell/set-array 1.1.2 +-- +Copyright 2022 Justin Ridgewell + +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. + +======================================================================== + +@jridgewell/sourcemap-codec 1.4.15 +-- +The MIT License + +Copyright (c) 2015 Rich Harris + +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. + +======================================================================== + +@jridgewell/trace-mapping 0.3.18 +-- +Copyright 2022 Justin Ridgewell + +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. + +======================================================================== + +@juggle/resize-observer 3.4.0 +-- +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 JUGGLE LTD + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================== + +@liveblocks/core 1.10.0 +-- +Licensed under Apache-2.0 (https://spdx.org/licenses/Apache-2.0.html) + +======================================================================== + +@liveblocks/react 1.10.0 +-- +Licensed under Apache-2.0 (https://spdx.org/licenses/Apache-2.0.html) + +======================================================================== + +@liveblocks/react-comments 1.10.0 +-- +Licensed under Apache-2.0 (https://spdx.org/licenses/Apache-2.0.html) + +======================================================================== + +@liveblocks/yjs 1.10.0 +-- +Licensed under Apache-2.0 (https://spdx.org/licenses/Apache-2.0.html) + +======================================================================== + +@popperjs/core 2.4.4 +-- +The MIT License (MIT) + +Copyright (c) 2019 Federico Zivolo + +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. + +======================================================================== + +@radix-ui/number 1.1.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/primitive 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-arrow 1.1.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-collection 1.1.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-compose-refs 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-context 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-direction 1.1.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-dismissable-layer 1.0.5 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-dropdown-menu 2.1.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-focus-guards 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-focus-scope 1.0.4 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-id 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-menu 2.1.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-popover 1.0.7 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-popper 1.1.3 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-portal 1.0.4 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-presence 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-primitive 1.0.3 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-roving-focus 1.1.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-select 2.1.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-slot 1.0.2 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-toggle 1.0.3 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-tooltip 1.0.7 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-use-callback-ref 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-use-controllable-state 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-use-escape-keydown 1.0.3 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-use-layout-effect 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-use-previous 1.1.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-use-size 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@radix-ui/react-visually-hidden 1.0.3 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@react-spring/animated 9.0.0-rc.3 +-- +MIT License + +Copyright (c) 2018-present Paul Henschel, Alec Larson + +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. + +======================================================================== + +@react-spring/core 9.0.0-rc.3 +-- +MIT License + +Copyright (c) 2018-present Paul Henschel, Alec Larson + +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. + +======================================================================== + +@react-spring/shared 9.0.0-rc.3 +-- +MIT License + +Copyright (c) 2018-present Paul Henschel, Alec Larson + +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. + +======================================================================== + +@react-spring/web 9.0.0-rc.3 +-- +MIT License + +Copyright (c) 2018-present Paul Henschel, Alec Larson + +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. + +======================================================================== + +@remix-run/react 2.0.1 +-- +MIT License + +Copyright (c) Remix Software Inc. 2020-2021 +Copyright (c) Shopify Inc. 2022-2023 + +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. + +======================================================================== + +@remix-run/router 1.13.0 +-- +MIT License + +Copyright (c) React Training LLC 2015-2019 +Copyright (c) Remix Software Inc. 2020-2021 +Copyright (c) Shopify Inc. 2022-2023 + +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. + +======================================================================== + +@remix-run/server-runtime 2.3.1 +-- +MIT License + +Copyright (c) Remix Software Inc. 2020-2021 +Copyright (c) Shopify Inc. 2022-2023 + +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. + +======================================================================== + +@root/encoding 1.0.1 +-- +Mozilla Public License Version 2.0 + + 1. Definitions + +1.1. "Contributor" means each individual or legal entity that creates, contributes +to the creation of, or owns Covered Software. + +1.2. "Contributor Version" means the combination of the Contributions of others +(if any) used by a Contributor and that particular Contributor's Contribution. + + 1.3. "Contribution" means Covered Software of a particular Contributor. + +1.4. "Covered Software" means Source Code Form to which the initial Contributor +has attached the notice in Exhibit A, the Executable Form of such Source Code +Form, and Modifications of such Source Code Form, in each case including portions +thereof. + + 1.5. "Incompatible With Secondary Licenses" means + +(a) that the initial Contributor has attached the notice described in Exhibit +B to the Covered Software; or + +(b) that the Covered Software was made available under the terms of version +1.1 or earlier of the License, but not also under the terms of a Secondary +License. + +1.6. "Executable Form" means any form of the work other than Source Code Form. + +1.7. "Larger Work" means a work that combines Covered Software with other +material, in a separate file or files, that is not Covered Software. + + 1.8. "License" means this document. + +1.9. "Licensable" means having the right to grant, to the maximum extent possible, +whether at the time of the initial grant or subsequently, any and all of the +rights conveyed by this License. + + 1.10. "Modifications" means any of the following: + +(a) any file in Source Code Form that results from an addition to, deletion +from, or modification of the contents of Covered Software; or + +(b) any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor means any patent claim(s), including +without limitation, method, process, and apparatus claims, in any patent Licensable +by such Contributor that would be infringed, but for the grant of the License, +by the making, using, selling, offering for sale, having made, import, or +transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" means either the GNU General Public License, Version +2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General +Public License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") means an individual or a legal entity exercising rights +under this License. For legal entities, "You" includes any entity that controls, +is controlled by, or is under common control with You. For purposes of this +definition, "control" means (a) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or otherwise, +or (b) ownership of more than fifty percent (50%) of the outstanding shares +or beneficial ownership of such entity. + + 2. License Grants and Conditions + + 2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive +license: + +(a) under intellectual property rights (other than patent or trademark) Licensable +by such Contributor to use, reproduce, make available, modify, display, perform, +distribute, and otherwise exploit its Contributions, either on an unmodified +basis, with Modifications, or as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer for +sale, have made, import, and otherwise transfer either its Contributions or +its Contributor Version. + + 2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution become +effective for each Contribution on the date the Contributor first distributes +such Contribution. + + 2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under this +License. No additional rights or licenses will be implied from the distribution +or licensing of Covered Software under this License. Notwithstanding Section +2.1(b) above, no patent license is granted by a Contributor: + +(a) for any code that a Contributor has removed from Covered Software; or + +(b) for infringements caused by: (i) Your and any other third party's modifications +of Covered Software, or (ii) the combination of its Contributions with other +software (except as part of its Contributor Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of its +Contributions. + +This License does not grant any rights in the trademarks, service marks, or +logos of any Contributor (except as may be necessary to comply with the notice +requirements in Section 3.4). + + 2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to distribute +the Covered Software under a subsequent version of this License (see Section +10.2) or under the terms of a Secondary License (if permitted under the terms +of Section 3.3). + + 2.5. Representation + +Each Contributor represents that the Contributor believes its Contributions +are its original creation(s) or it has sufficient rights to grant the rights +to its Contributions conveyed by this License. + + 2.6. Fair Use + +This License is not intended to limit any rights You have under applicable +copyright doctrines of fair use, fair dealing, or other equivalents. + + 2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in +Section 2.1. + + 3. Responsibilities + + 3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any Modifications +that You create or to which You contribute, must be under the terms of this +License. You must inform recipients that the Source Code Form of the Covered +Software is governed by the terms of this License, and how they can obtain +a copy of this License. You may not attempt to alter or restrict the recipients' +rights in the Source Code Form. + + 3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code Form, +as described in Section 3.1, and You must inform recipients of the Executable +Form how they can obtain a copy of such Source Code Form by reasonable means +in a timely manner, at a charge no more than the cost of distribution to the +recipient; and + +(b) You may distribute such Executable Form under the terms of this License, +or sublicense it under different terms, provided that the license for the +Executable Form does not attempt to limit or alter the recipients' rights +in the Source Code Form under this License. + + 3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, provided +that You also comply with the requirements of this License for the Covered +Software. If the Larger Work is a combination of Covered Software with a work +governed by one or more Secondary Licenses, and the Covered Software is not +Incompatible With Secondary Licenses, this License permits You to additionally +distribute such Covered Software under the terms of such Secondary License(s), +so that the recipient of the Larger Work may, at their option, further distribute +the Covered Software under the terms of either this License or such Secondary +License(s). + + 3.4. Notices + +You may not remove or alter the substance of any license notices (including +copyright notices, patent notices, disclaimers of warranty, or limitations +of liability) contained within the Source Code Form of the Covered Software, +except that You may alter any license notices to the extent required to remedy +known factual inaccuracies. + + 3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, indemnity +or liability obligations to one or more recipients of Covered Software. However, +You may do so only on Your own behalf, and not on behalf of any Contributor. +You must make it absolutely clear that any such warranty, support, indemnity, +or liability obligation is offered by You alone, and You hereby agree to indemnify +every Contributor for any liability incurred by such Contributor as a result +of warranty, support, indemnity or liability terms You offer. You may include +additional disclaimers of warranty and limitations of liability specific to +any jurisdiction. + + 4. Inability to Comply Due to Statute or Regulation + +If it is impossible for You to comply with any of the terms of this License +with respect to some or all of the Covered Software due to statute, judicial +order, or regulation then You must: (a) comply with the terms of this License +to the maximum extent possible; and (b) describe the limitations and the code +they affect. Such description must be placed in a text file included with +all distributions of the Covered Software under this License. Except to the +extent prohibited by statute or regulation, such description must be sufficiently +detailed for a recipient of ordinary skill to be able to understand it. + + 5. Termination + +5.1. The rights granted under this License will terminate automatically if +You fail to comply with any of its terms. However, if You become compliant, +then the rights granted under this License from a particular Contributor are +reinstated (a) provisionally, unless and until such Contributor explicitly +and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor +fails to notify You of the non-compliance by some reasonable means prior to +60 days after You have come back into compliance. Moreover, Your grants from +a particular Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the first +time You have received notice of non-compliance with this License from such +Contributor, and You become compliant prior to 30 days after Your receipt +of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent infringement +claim (excluding declaratory judgment actions, counter-claims, and cross-claims) +alleging that a Contributor Version directly or indirectly infringes any patent, +then the rights granted to You by any and all Contributors for the Covered +Software under Section 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end +user license agreements (excluding distributors and resellers) which have +been validly granted by You or Your distributors under this License prior +to termination shall survive termination. + + 6. Disclaimer of Warranty + +Covered Software is provided under this License on an "as is" basis, without +warranty of any kind, either expressed, implied, or statutory, including, +without limitation, warranties that the Covered Software is free of defects, +merchantable, fit for a particular purpose or non-infringing. The entire risk +as to the quality and performance of the Covered Software is with You. Should +any Covered Software prove defective in any respect, You (not any Contributor) +assume the cost of any necessary servicing, repair, or correction. This disclaimer +of warranty constitutes an essential part of this License. No use of any Covered +Software is authorized under this License except under this disclaimer. + + 7. Limitation of Liability + +Under no circumstances and under no legal theory, whether tort (including +negligence), contract, or otherwise, shall any Contributor, or anyone who +distributes Covered Software as permitted above, be liable to You for any +direct, indirect, special, incidental, or consequential damages of any character +including, without limitation, damages for lost profits, loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial +damages or losses, even if such party shall have been informed of the possibility +of such damages. This limitation of liability shall not apply to liability +for death or personal injury resulting from such party's negligence to the +extent applicable law prohibits such limitation. Some jurisdictions do not +allow the exclusion or limitation of incidental or consequential damages, +so this exclusion and limitation may not apply to You. + + 8. Litigation + +Any litigation relating to this License may be brought only in the courts +of a jurisdiction where the defendant maintains its principal place of business +and such litigation shall be governed by laws of that jurisdiction, without +reference to its conflict-of-law provisions. Nothing in this Section shall +prevent a party's ability to bring cross-claims or counter-claims. + + 9. Miscellaneous + +This License represents the complete agreement concerning the subject matter +hereof. If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it enforceable. +Any law or regulation which provides that the language of a contract shall +be construed against the drafter shall not be used to construe this License +against a Contributor. + + 10. Versions of the License + + 10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section 10.3, +no one other than the license steward has the right to modify or publish new +versions of this License. Each version will be given a distinguishing version +number. + + 10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version of +the License under which You originally received the Covered Software, or under +the terms of any subsequent version published by the license steward. + + 10.3. Modified Versions + +If you create software not governed by this License, and you want to create +a new license for such software, you may create and use a modified version +of this License if you rename the license and remove any references to the +name of the license steward (except to note that such modified license differs +from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + +If You choose to distribute Source Code Form that is Incompatible With Secondary +Licenses under the terms of this version of the License, the notice described +in Exhibit B of this License must be attached. Exhibit A - Source Code Form +License Notice + +This Source Code Form is subject to the terms of the Mozilla Public License, +v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + +This Source Code Form is "Incompatible With Secondary Licenses", as defined +by the Mozilla Public License, v. 2.0. + +======================================================================== + +@seznam/compose-react-refs 1.0.6 +-- +Copyright (c) 2019, Seznam.cz, a.s. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +@shopify/hydrogen 2024.4.1 +-- +Copyright 2023-present, Shopify 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. + +======================================================================== + +@shopify/hydrogen-react 2024.4.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@stitches/react 1.2.8 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +@tippyjs/react 4.1.0 +-- +MIT License + +Copyright (c) 2018 atomiks + +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. + +======================================================================== + +@twind/core 1.1.3 +-- +MIT License + +Copyright (c) 2022 [these people](https://github.com/tw-in-js/twind/graphs/contributors) + +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. + +======================================================================== + +@twind/preset-autoprefix 1.0.7 +-- +MIT License + +Copyright (c) 2022 [these people](https://github.com/tw-in-js/twind/graphs/contributors) + +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. + +======================================================================== + +@twind/preset-tailwind 1.1.4 +-- +MIT License + +Copyright (c) 2022 [these people](https://github.com/tw-in-js/twind/graphs/contributors) + +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. + +======================================================================== + +@use-it/interval 0.1.3 +-- +MIT License + +Copyright (c) 2019-present Donavon West + +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. + +======================================================================== + +@vercel/stega 0.1.0 +-- +# Mozilla Public License Version 2.0 + +1. Definitions + +--- + +1.1. "Contributor" +means each individual or legal entity that creates, contributes to +the creation of, or owns Covered Software. + +1.2. "Contributor Version" +means the combination of the Contributions of others (if any) used +by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" +means Covered Software of a particular Contributor. + +1.4. "Covered Software" +means Source Code Form to which the initial Contributor has attached +the notice in Exhibit A, the Executable Form of such Source Code +Form, and Modifications of such Source Code Form, in each case +including portions thereof. + +1.5. "Incompatible With Secondary Licenses" +means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" +means any form of the work other than Source Code Form. + +1.7. "Larger Work" +means a work that combines Covered Software with other material, in +a separate file or files, that is not Covered Software. + +1.8. "License" +means this document. + +1.9. "Licensable" +means having the right to grant, to the maximum extent possible, +whether at the time of the initial grant or subsequently, any and +all of the rights conveyed by this License. + +1.10. "Modifications" +means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor +means any patent claim(s), including without limitation, method, +process, and apparatus claims, in any patent Licensable by such +Contributor that would be infringed, but for the grant of the +License, by the making, using, selling, offering for sale, having +made, import, or transfer of either its Contributions or its +Contributor Version. + +1.12. "Secondary License" +means either the GNU General Public License, Version 2.0, the GNU +Lesser General Public License, Version 2.1, the GNU Affero General +Public License, Version 3.0, or any later versions of those +licenses. + +1.13. "Source Code Form" +means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") +means an individual or a legal entity exercising rights under this +License. For legal entities, "You" includes any entity that +controls, is controlled by, or is under common control with You. For +purposes of this definition, "control" means (a) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (b) ownership of more than +fifty percent (50%) of the outstanding shares or beneficial +ownership of such entity. + +2. License Grants and Conditions + +--- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) +Licensable by such Contributor to use, reproduce, make available, +modify, display, perform, distribute, and otherwise exploit its +Contributions, either on an unmodified basis, with Modifications, or +as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer +for sale, have made, import, and otherwise transfer either its +Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; +or + +(b) for infringements caused by: (i) Your and any other third party's +modifications of Covered Software, or (ii) the combination of its +Contributions with other software (except as part of its Contributor +Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of +its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities + +--- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code +Form, as described in Section 3.1, and You must inform recipients of +the Executable Form how they can obtain a copy of such Source Code +Form by reasonable means in a timely manner, at a charge no more +than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this +License, or sublicense it under different terms, provided that the +license for the Executable Form does not attempt to limit or alter +the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + +--- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination + +--- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +--- + +- * +- 6. Disclaimer of Warranty \* +- ------------------------- \* +- * +- Covered Software is provided under this License on an "as is" \* +- basis, without warranty of any kind, either expressed, implied, or \* +- statutory, including, without limitation, warranties that the \* +- Covered Software is free of defects, merchantable, fit for a \* +- particular purpose or non-infringing. The entire risk as to the \* +- quality and performance of the Covered Software is with You. \* +- Should any Covered Software prove defective in any respect, You \* +- (not any Contributor) assume the cost of any necessary servicing, \* +- repair, or correction. This disclaimer of warranty constitutes an \* +- essential part of this License. No use of any Covered Software is \* +- authorized under this License except under this disclaimer. \* +- * + +--- + +--- + +- * +- 7. Limitation of Liability \* +- -------------------------- \* +- * +- Under no circumstances and under no legal theory, whether tort \* +- (including negligence), contract, or otherwise, shall any \* +- Contributor, or anyone who distributes Covered Software as \* +- permitted above, be liable to You for any direct, indirect, \* +- special, incidental, or consequential damages of any character \* +- including, without limitation, damages for lost profits, loss of \* +- goodwill, work stoppage, computer failure or malfunction, or any \* +- and all other commercial damages or losses, even if such party \* +- shall have been informed of the possibility of such damages. This \* +- limitation of liability shall not apply to liability for death or \* +- personal injury resulting from such party's negligence to the \* +- extent applicable law prohibits such limitation. Some \* +- jurisdictions do not allow the exclusion or limitation of \* +- incidental or consequential damages, so this exclusion and \* +- limitation may not apply to You. \* +- * + +--- + +8. Litigation + +--- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous + +--- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License + +--- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +## Exhibit A - Source Code Form License Notice + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +## Exhibit B - "Incompatible With Secondary Licenses" Notice + +This Source Code Form is "Incompatible With Secondary Licenses", as +defined by the Mozilla Public License, v. 2.0. + +======================================================================== + +@web3-storage/multipart-parser 1.0.0 +-- +Copyright vasco-santos; licensed under (Apache-2.0 AND MIT) (https://spdx.org/licenses/Apache-2.0.html https://spdx.org/licenses/MIT.html) + +======================================================================== + +acorn 7.4.1 +-- +MIT License + +Copyright (C) 2012-2018 by various contributors (see AUTHORS) + +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. + +======================================================================== + +acorn-jsx 5.3.2 +-- +Copyright (C) 2012-2017 by Ingvar Stepanyan + +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. + +======================================================================== + +add-dom-event-listener 1.1.0 +-- +The MIT License (MIT) + +Copyright (c) 2014-present yiminghe + +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. + +======================================================================== + +ajv 6.12.6 +-- +The MIT License (MIT) + +Copyright (c) 2015-2017 Evgeny Poberezkin + +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. + +======================================================================== + +anser 2.1.0 +-- +The MIT License (MIT) + +Copyright (c) 2012-21 Ionică Bizău (https://ionicabizau.net) + +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. + +======================================================================== + +ansi-regex 5.0.1 +-- +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. + +======================================================================== + +ansi-styles 3.2.1 +-- +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. + +======================================================================== + +aria-hidden 1.2.3 +-- +MIT License + +Copyright (c) 2017 Anton Korzunov + +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. + +======================================================================== + +aria-query 4.2.2 +-- +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "{}" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright 2020 A11yance + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +======================================================================== + +array-includes 3.1.4 +-- +The MIT License (MIT) + +Copyright (C) 2015 Jordan Harband + +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. + +======================================================================== + +array.prototype.flatmap 1.2.4 +-- +MIT License + +Copyright (c) 2017 ECMAScript Shims + +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. + +======================================================================== + +assert 1.3.0 +-- +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +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. + +======================================================================== + +axobject-query 2.2.0 +-- +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "{}" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright 2020 A11yance + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +======================================================================== + +babel-eslint 10.0.1 +-- +Copyright (c) 2014-2016 Sebastian McKenzie + +MIT License + +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. + +======================================================================== + +babel-helper-builder-react-jsx 6.26.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +babel-plugin-dynamic-import-node 2.3.3 +-- +MIT License + +Copyright (c) 2016 Airbnb + +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. + +======================================================================== + +babel-plugin-syntax-jsx 6.18.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +babel-plugin-transform-react-jsx 6.24.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +babel-runtime 6.26.0 +-- +Copyright Sebastian McKenzie ; licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +babel-types 6.26.0 +-- +Copyright Sebastian McKenzie ; licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +balanced-match 1.0.2 +-- +(MIT) + +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> + +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. + +======================================================================== + +base64-js 1.5.1 +-- +The MIT License (MIT) + +Copyright (c) 2014 Jameson Little + +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. + +======================================================================== + +binaryextensions 4.18.0 +-- + + +

License

+ +Unless stated otherwise all works are: + + + +and licensed under: + + + +

MIT License

+ +
+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.
+
+ + + +======================================================================== + +brace-expansion 1.1.11 +-- +MIT License + +Copyright (c) 2013 Julian Gruber + +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. + +======================================================================== + +browserfs 2.0.0 +-- +BrowserFS's license follows: + +==== + +Copyright (c) 2013, 2014, 2015, 2016, 2017 John Vilk and other BrowserFS contributors. + +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. + +==== + +This license applies to all parts of BrowserFS, except for the following items: + +- The unit tests from Node, located in `test/tests/**/node-*.js`, and their + test fixtures, located in `test/fixtures/files/node`. Their license follows: + """ + Copyright Joyent, Inc. and other Node contributors. All rights reserved. + 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. + """ + +- The Emscripten file system in src/generic/emscripten_fs.ts is a modified + version of Emscripten's NODEFS. Emscripten's license follows: + """ + Emscripten is available under 2 licenses, the MIT license and the + University of Illinois/NCSA Open Source License. + + Both are permissive open source licenses, with little if any + practical difference between them. + + The reason for offering both is that (1) the MIT license is + well-known, while (2) the University of Illinois/NCSA Open Source + License allows Emscripten's code to be integrated upstream into + LLVM, which uses that license, should the opportunity arise. + + The full text of both licenses follows. + + ============================================================================== + + Copyright (c) 2010-2011 Emscripten authors, see AUTHORS file. + + 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. + + ============================================================================== + + Copyright (c) 2010-2011 Emscripten authors, see AUTHORS file. + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal with 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: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimers. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimers + in the documentation and/or other materials provided with the + distribution. + + Neither the names of Mozilla, + nor the names of its contributors may be used to endorse + or promote products derived from this Software without specific prior + written permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. + """ + +======================================================================== + +browserslist 4.22.2 +-- +The MIT License (MIT) + +Copyright 2014 Andrey Sitnik and other contributors + +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. + +======================================================================== + +buffer 6.0.3 +-- +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh, and other contributors. + +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. + +======================================================================== + +call-bind 1.0.2 +-- +MIT License + +Copyright (c) 2020 Jordan Harband + +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. + +======================================================================== + +caniuse-lite 1.0.30001570 +-- +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + +======================================================================== + +chalk 2.4.2 +-- +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. + +======================================================================== + +chroma-js 2.1.0 +-- +###* + * @license + * + * chroma.js - JavaScript library for color conversions + * + * Copyright (c) 2011-2017, Gregor Aisch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name Gregor Aisch may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +### + +======================================================================== + +classnames 2.2.6 +-- +The MIT License (MIT) + +Copyright (c) 2017 Jed Watson + +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. + +======================================================================== + +clipboard-polyfill 2.4.6 +-- +# License + +The MIT License (MIT) + +Copyright (c) 2014 Lucas Garron + +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. + +======================================================================== + +clsx 1.2.1 +-- +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +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. + +======================================================================== + +color-convert 1.9.3 +-- +Copyright (c) 2011-2016 Heather Arthur + +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. + +======================================================================== + +color-name 1.1.3 +-- +The MIT License (MIT) +Copyright (c) 2015 Dmitry Ivanov + +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. + +======================================================================== + +component-classes 1.2.6 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +compute-scroll-into-view 1.0.17 +-- +MIT License + +Copyright (c) 2018 Cody Olsen + +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. + +======================================================================== + +concat-map 0.0.1 +-- +This software is released under the MIT license: + +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. + +======================================================================== + +content-security-policy-builder 2.1.1 +-- +The MIT License (MIT) + +Copyright (c) 2015-2022 Evan Hahn + +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. + +======================================================================== + +convert-source-map 2.0.0 +-- +Copyright 2013 Thorsten Lorenz. +All rights reserved. + +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. + +======================================================================== + +cookie 0.5.0 +-- +(The MIT License) + +Copyright (c) 2012-2014 Roman Shtylman +Copyright (c) 2015 Douglas Christopher Wilson + +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. + +======================================================================== + +core-js 2.6.12 +-- +Copyright (c) 2014-2020 Denis Pushkarev + +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. + +======================================================================== + +core-js-pure 3.18.1 +-- +Copyright (c) 2014-2021 Denis Pushkarev + +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. + +======================================================================== + +create-react-class 15.6.3 +-- +MIT License + +Copyright (c) 2013-present, Facebook, 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. + +======================================================================== + +css-animation 1.6.1 +-- +The MIT License (MIT) + +Copyright (c) 2014-present yiminghe + +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. + +======================================================================== + +css-loader 0.28.4 +-- +Copyright JS Foundation and other contributors + +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. + +======================================================================== + +css-tree 2.3.1 +-- +Copyright (C) 2016-2022 by Roman Dvornov + +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. + +======================================================================== + +damerau-levenshtein 1.0.7 +-- +BSD 2-Clause License + +Copyright (c) 2018, Tadeusz Łazurski +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +debug 4.3.4 +-- +(The MIT License) + +Copyright (c) 2014-2017 TJ Holowaychuk +Copyright (c) 2018-2021 Josh Junon + +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. + +======================================================================== + +deepmerge 4.2.2 +-- +The MIT License (MIT) + +Copyright (c) 2012 James Halliday, Josh Duff, and other contributors + +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. + +======================================================================== + +define-properties 1.2.0 +-- +The MIT License (MIT) + +Copyright (C) 2015 Jordan Harband + +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. + +======================================================================== + +direction 1.0.4 +-- +(The MIT License) + +Copyright (c) 2014 Titus Wormer + +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. + +======================================================================== + +dnd-core 16.0.1 +-- +The MIT License (MIT) + +Copyright (c) 2015 Dan Abramov + +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. + +======================================================================== + +doctrine 3.0.0 +-- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +dom-align 1.12.4 +-- +The MIT License (MIT) + +Copyright (c) 2014-present yiminghe + +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. + +======================================================================== + +dom-serializer 2.0.0 +-- +License + +(The MIT License) + +Copyright (c) 2014 The cheeriojs contributors + +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. + +======================================================================== + +domelementtype 2.3.0 +-- +Copyright (c) Felix Böhm +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +domhandler 5.0.3 +-- +Copyright (c) Felix Böhm +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +domutils 3.1.0 +-- +Copyright (c) Felix Böhm +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +electron-to-chromium 1.4.613 +-- +Copyright 2018 Kilian Valkhof + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +emoji-regex 9.2.2 +-- +Copyright Mathias Bynens + +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. + +======================================================================== + +entities 4.5.0 +-- +Copyright (c) Felix Böhm +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +es-abstract 1.21.3 +-- +The MIT License (MIT) + +Copyright (C) 2015 Jordan Harband + +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. + +======================================================================== + +es-to-primitive 1.2.1 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +escape-string-regexp 4.0.0 +-- +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +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. + +======================================================================== + +eslint 7.32.0 +-- +Copyright JS Foundation and other contributors, https://js.foundation + +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. + +======================================================================== + +eslint-module-utils 2.8.0 +-- +The MIT License (MIT) + +Copyright (c) 2015 Ben Mosher + +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. + +======================================================================== + +eslint-plugin-import 2.25.3 +-- +The MIT License (MIT) + +Copyright (c) 2015 Ben Mosher + +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. + +======================================================================== + +eslint-plugin-jsx-a11y 6.5.1 +-- +The MIT License (MIT) +Copyright (c) 2016 Ethan Cohen + +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. + +======================================================================== + +eslint-plugin-react 7.23.2 +-- +The MIT License (MIT) + +Copyright (c) 2014 Yannick Croissant + +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. + +======================================================================== + +eslint-plugin-react-hooks 4.2.0 +-- +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +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. + +======================================================================== + +eslint-scope 5.1.1 +-- +Copyright JS Foundation and other contributors, https://js.foundation +Copyright (C) 2012-2013 Yusuke Suzuki (twitter: @Constellation) and other contributors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +eslint-utils 1.4.3 +-- +MIT License + +Copyright (c) 2018 Toru Nagashima + +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. + +======================================================================== + +eslint-visitor-keys 1.3.0 +-- +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================== + +espree 6.2.1 +-- +Espree +Copyright JS Foundation and other contributors, https://js.foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +esquery 1.4.0 +-- +Copyright (c) 2013, Joel Feenstra +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the ESQuery nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL JOEL FEENSTRA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +esrecurse 4.3.0 +-- +Licensed under BSD-2-Clause (https://spdx.org/licenses/BSD-2-Clause.html) + +======================================================================== + +estraverse 5.3.0 +-- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +esutils 2.0.3 +-- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +events 1.1.1 +-- +MIT + +Copyright Joyent, Inc. and other Node contributors. + +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. + +======================================================================== + +fast-deep-equal 3.1.3 +-- +MIT License + +Copyright (c) 2017 Evgeny Poberezkin + +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. + +======================================================================== + +fast-equals 3.0.3 +-- +MIT License + +Copyright (c) 2017 Tony Quetano + +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. + +======================================================================== + +fast-json-stable-stringify 2.1.0 +-- +This software is released under the MIT license: + +Copyright (c) 2017 Evgeny Poberezkin +Copyright (c) 2013 James Halliday + +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. + +======================================================================== + +fast-memoize 2.5.2 +-- +The MIT License (MIT) + +Copyright (c) 2016 Caio Gondim + +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. + +======================================================================== + +fbjs 0.8.17 +-- +MIT License + +Copyright (c) 2013-present, Facebook, 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. + +======================================================================== + +fluids 0.1.10 +-- +Copyright Alec Larson; licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +framer-motion 11.2.13 +-- +The MIT License (MIT) + +Copyright (c) 2018 Framer B.V. + +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. + +======================================================================== + +friendly-words 1.1.10 +-- +MIT License + +Copyright (c) 2018 Glitch + +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. + +======================================================================== + +function-bind 1.1.1 +-- +Copyright (c) 2013 Raynos. + +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. + +======================================================================== + +functional-red-black-tree 1.0.1 +-- +The MIT License (MIT) + +Copyright (c) 2013 Mikola Lysenko + +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. + +======================================================================== + +functions-have-names 1.2.3 +-- +MIT License + +Copyright (c) 2019 Jordan Harband + +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. + +======================================================================== + +gensync 1.0.0-beta.2 +-- +Copyright 2018 Logan Smyth + +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. + +======================================================================== + +get-intrinsic 1.2.1 +-- +MIT License + +Copyright (c) 2020 Jordan Harband + +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. + +======================================================================== + +get-nonce 1.0.1 +-- +MIT License + +Copyright (c) 2020 Anton Korzunov + +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. + +======================================================================== + +glob-to-regexp 0.4.1 +-- +Copyright Nick Fitzgerald ; licensed under BSD-2-Clause (https://spdx.org/licenses/BSD-2-Clause.html) + +======================================================================== + +globals 11.12.0 +-- +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. + +======================================================================== + +gopd 1.0.1 +-- +MIT License + +Copyright (c) 2022 Jordan Harband + +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. + +======================================================================== + +has 1.0.3 +-- +Copyright (c) 2013 Thiago de Arruda + +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. + +======================================================================== + +has-property-descriptors 1.0.0 +-- +MIT License + +Copyright (c) 2022 Inspect JS + +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. + +======================================================================== + +has-proto 1.0.1 +-- +MIT License + +Copyright (c) 2022 Inspect JS + +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. + +======================================================================== + +has-symbols 1.0.3 +-- +MIT License + +Copyright (c) 2016 Jordan Harband + +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. + +======================================================================== + +has-tostringtag 1.0.0 +-- +MIT License + +Copyright (c) 2021 Inspect JS + +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. + +======================================================================== + +he 1.2.0 +-- +Copyright Mathias Bynens + +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. + +======================================================================== + +hoist-non-react-statics 3.3.2 +-- +Software License Agreement (BSD License) +======================================== + +Copyright (c) 2015, Yahoo! Inc. All rights reserved. +---------------------------------------------------- + +Redistribution and use of this software in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Yahoo! Inc. nor the names of YUI's contributors may be + used to endorse or promote products derived from this software without + specific prior written permission of Yahoo! Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +hosted-git-info 4.0.2 +-- +Copyright (c) 2015, Rebecca Turner + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +html-dom-parser 0.3.0 +-- +MIT License + +Copyright (c) 2016 Menglin "Mark" Xu + +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. + +======================================================================== + +html-entities 1.2.1 +-- +Copyright (c) 2013 Dulin Marat + +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. + +======================================================================== + +html-react-parser 0.13.0 +-- +The MIT License + +Copyright (c) 2016 Menglin "Mark" Xu + +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. + +======================================================================== + +htmlparser2 8.0.2 +-- +Copyright 2010, 2011, Chris Winberry . All rights reserved. +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. + +======================================================================== + +ieee754 1.2.1 +-- +Copyright 2008 Fair Oaks Labs, Inc. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +ignore 4.0.6 +-- +Copyright (c) 2013 Kael Zhang , contributors +http://kael.me/ + +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. + +======================================================================== + +immediate 3.0.6 +-- +Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, Domenic Denicola, Brian Cavalier + +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. + +======================================================================== + +immer 9.0.21 +-- +MIT License + +Copyright (c) 2017 Michel Weststrate + +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. + +======================================================================== + +immutability-helper 3.1.1 +-- +MIT License + +Copyright (c) 2017 Moshe Kolodny + +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. + +======================================================================== + +inherits 2.0.4 +-- +The ISC License + +Copyright (c) Isaac Z. Schlueter + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +inline-style-parser 0.1.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +internal-slot 1.0.5 +-- +MIT License + +Copyright (c) 2019 Jordan Harband + +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. + +======================================================================== + +is-callable 1.2.7 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +is-core-module 2.12.1 +-- +The MIT License (MIT) + +Copyright (c) 2014 Dave Justice + +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. + +======================================================================== + +is-date-object 1.0.5 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +is-hotkey 0.1.8 +-- +The MIT License + +Copyright © 2017, [Ian Storm Taylor](https://ianstormtaylor.com) + +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. + +======================================================================== + +is-plain-object 5.0.0 +-- +The MIT License (MIT) + +Copyright (c) 2014-2017, Jon Schlinkert. + +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. + +======================================================================== + +is-regex 1.1.4 +-- +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +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. + +======================================================================== + +is-string 1.0.7 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +is-symbol 1.0.4 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +isobject 3.0.1 +-- +The MIT License (MIT) + +Copyright (c) 2014-2017, Jon Schlinkert. + +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. + +======================================================================== + +istextorbinary 5.11.0 +-- + + +

License

+ +Unless stated otherwise all works are: + + + +and licensed under: + + + +

MIT License

+ +
+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 (including the next paragraph) 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.
+
+ + + +======================================================================== + +jotai 2.4.3 +-- +MIT License + +Copyright (c) 2020-2023 Poimandres + +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. + +======================================================================== + +jotai-devtools 0.6.2 +-- +MIT License + +Copyright (c) 2023 Jotai Labs + +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. + +======================================================================== + +js-base64 3.7.5 +-- +Copyright (c) 2014, Dan Kogai +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of {{{project}}} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +js-tokens 4.0.0 +-- +The MIT License (MIT) + +Copyright (c) 2014, 2015, 2016, 2017, 2018 Simon Lydell + +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. + +======================================================================== + +jsesc 2.5.2 +-- +Copyright Mathias Bynens + +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. + +======================================================================== + +json-schema-traverse 0.4.1 +-- +MIT License + +Copyright (c) 2017 Evgeny Poberezkin + +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. + +======================================================================== + +json5 0.5.1 +-- +MIT License + +Copyright (c) 2012-2016 Aseem Kishore, and [others](https://github.com/aseemk/json5/contributors). + +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. + +======================================================================== + +jsx-ast-utils 3.2.1 +-- +The MIT License (MIT) +Copyright (c) 2016 Ethan Cohen + +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. + +======================================================================== + +jszip 3.5.0 +-- +JSZip is dual licensed. You may use it under the MIT license *or* the GPLv3 +license. + +The MIT License +=============== + +Copyright (c) 2009-2016 Stuart Knightley, David Duponchel, Franz Buchinger, António Afonso + +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. + + +GPL version 3 +============= + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + +======================================================================== + +language-tags 1.0.5 +-- +Copyright Matthew Caruana Galizia ; licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +levn 0.3.0 +-- +Copyright (c) George Zahariev + +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. + +======================================================================== + +lib0 0.2.87 +-- +The MIT License (MIT) + +Copyright (c) 2019 Kevin Jahns . + +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. + +======================================================================== + +lie 3.3.0 +-- +#Copyright (c) 2014-2018 Calvin Metcalf, Jordan Harband + +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.** + +======================================================================== + +localforage 1.7.3 +-- +Copyright 2014 Mozilla + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +======================================================================== + +lodash 4.17.21 +-- +Copyright OpenJS Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +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. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + +======================================================================== + +lodash.clamp 4.0.3 +-- +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +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. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + +======================================================================== + +lodash.debounce 4.0.8 +-- +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +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. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + +======================================================================== + +lodash.findlastindex 4.6.0 +-- +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +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. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + +======================================================================== + +lodash.throttle 4.1.1 +-- +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +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. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + +======================================================================== + +lru-cache 7.10.1 +-- +The ISC License + +Copyright (c) 2010-2022 Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +memoize-one 5.2.1 +-- +MIT License + +Copyright (c) 2019 Alexander Reardon + +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. + +======================================================================== + +micro-memoize 4.0.14 +-- +MIT License + +Copyright (c) 2018 Tony Quetano + +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. + +======================================================================== + +mime-db 1.40.0 +-- +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong me@jongleberry.com + +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. + +======================================================================== + +mime-types 2.1.24 +-- +(The MIT License) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2015 Douglas Christopher Wilson + +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. + +======================================================================== + +minimatch 3.0.4 +-- +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +moize 6.1.4 +-- +MIT License + +Copyright (c) 2016 Tony Quetano + +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. + +======================================================================== + +ms 2.1.2 +-- +The MIT License (MIT) + +Copyright (c) 2016 Zeit, 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. + +======================================================================== + +murmurhash3js 3.0.1 +-- +The MIT License (MIT) + +Copyright (c) 2012-2015 Karan Lyons, Sascha Droste + +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. + +======================================================================== + +nanoid 3.3.6 +-- +The MIT License (MIT) + +Copyright 2017 Andrey Sitnik + +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. + +======================================================================== + +natural-compare 1.4.0 +-- +Copyright Lauri Rooden (https://github.com/litejs/natural-compare-lite); licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +node-diff3 3.1.2 +-- +### The MIT License (MIT) + +diff function extracted from Project Synchrotron. + +For more detail please visit: +- https://leastfixedpoint.com/tonyg/kcbbs/projects/synchrotron.html +- https://github.com/tonyg/synchrotron + +Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
+Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
+Copyright (c) 2019 Bryan Housel <bhousel@gmail.com>
+ +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. + +======================================================================== + +node-html-parser 1.2.20 +-- +Copyright 2019 Tao Qiufeng + +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. + +======================================================================== + +npm-package-arg 8.1.5 +-- +The ISC License + +Copyright (c) npm, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +object-assign 4.1.1 +-- +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. + +======================================================================== + +object-inspect 1.12.3 +-- +MIT License + +Copyright (c) 2013 James Halliday + +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. + +======================================================================== + +object-keys 1.1.1 +-- +The MIT License (MIT) + +Copyright (C) 2013 Jordan Harband + +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. + +======================================================================== + +object-path 0.11.4 +-- +The MIT License (MIT) + +Copyright (c) 2015 Mario Casciaro + +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. + +======================================================================== + +object-path-immutable 3.0.0 +-- +The MIT License (MIT) + +Copyright (c) 2015 Mario Casciaro + +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. + +======================================================================== + +object.assign 4.1.4 +-- +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +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. + +======================================================================== + +object.entries 1.1.4 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +object.fromentries 2.0.4 +-- +MIT License + +Copyright (c) 2018 Jordan Harband + +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. + +======================================================================== + +object.values 1.1.4 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +pako 1.0.11 +-- +(The MIT License) + +Copyright (C) 2014-2017 by Vitaly Puzrin and Andrei Tuputcyn + +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. + +======================================================================== + +parse-srcset 1.0.2 +-- +The MIT License (MIT) + +Copyright (c) 2014 Alex Bell + +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. + +======================================================================== + +path 0.12.7 +-- +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +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. + +======================================================================== + +path-browserify 1.0.1 +-- +MIT License + +Copyright (c) 2013 James Halliday + +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. + +======================================================================== + +path-parse 1.0.7 +-- +The MIT License (MIT) + +Copyright (c) 2015 Javier Blanco + +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. + +======================================================================== + +picocolors 1.0.0 +-- +ISC License + +Copyright (c) 2021 Alexey Raspopov, Kostiantyn Denysov, Anton Verinov + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +platform-detect 3.0.0 +-- +MIT License + +Copyright (c) 2018 Mike Kovařík, Mutiny.cz + +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. + +======================================================================== + +postcss 8.4.27 +-- +The MIT License (MIT) + +Copyright 2013 Andrey Sitnik + +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. + +======================================================================== + +prelude-ls 1.1.2 +-- +Copyright (c) George Zahariev + +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. + +======================================================================== + +prettier 2.8.8 +-- +# Prettier license + +Prettier is released under the MIT license: + +Copyright © James Long and contributors + +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. + +## Licenses of bundled dependencies + +The published Prettier artifact additionally contains code with the following licenses: +MIT, ISC, BSD-2-Clause, BSD-3-Clause, Apache-2.0, 0BSD + +## Bundled dependencies + +### @angular/compiler@v12.2.16 + +License: MIT +By: angular +Repository: + +---------------------------------------- + +### @babel/code-frame@v7.18.6 + +License: MIT +By: The Babel Team +Repository: + +> MIT License +> +> Copyright (c) 2014-present Sebastian McKenzie and other contributors +> +> 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. + +---------------------------------------- + +### @babel/helper-validator-identifier@v7.19.1 + +License: MIT +By: The Babel Team +Repository: + +> MIT License +> +> Copyright (c) 2014-present Sebastian McKenzie and other contributors +> +> 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. + +---------------------------------------- + +### @babel/highlight@v7.18.6 + +License: MIT +By: The Babel Team +Repository: + +> MIT License +> +> Copyright (c) 2014-present Sebastian McKenzie and other contributors +> +> 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. + +---------------------------------------- + +### @babel/parser@v7.21.3 + +License: MIT +By: The Babel Team +Repository: + +> Copyright (C) 2012-2014 by various contributors (see AUTHORS) +> +> 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. + +---------------------------------------- + +### @glimmer/env@v0.1.7 + +License: MIT + +> Copyright (c) 2017 Martin Muñoz and contributors. +> +> 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. + +---------------------------------------- + +### @glimmer/syntax@v0.84.2 + +License: MIT + +> Copyright (c) 2015 Tilde, 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. + +---------------------------------------- + +### @glimmer/util@v0.84.2 + +License: MIT + +> Copyright (c) 2015 Tilde, 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. + +---------------------------------------- + +### @handlebars/parser@v2.0.0 + +License: ISC +Repository: + +---------------------------------------- + +### @iarna/toml@v2.2.5 + +License: ISC +By: Rebecca Turner +Repository: + +> Copyright (c) 2016, Rebecca Turner +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +> OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### @nodelib/fs.scandir@v2.1.5 + +License: MIT + +> The MIT License (MIT) +> +> Copyright (c) Denis Malinochkin +> +> 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. + +---------------------------------------- + +### @nodelib/fs.stat@v2.0.5 + +License: MIT + +> The MIT License (MIT) +> +> Copyright (c) Denis Malinochkin +> +> 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. + +---------------------------------------- + +### @nodelib/fs.walk@v1.2.8 + +License: MIT + +> The MIT License (MIT) +> +> Copyright (c) Denis Malinochkin +> +> 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. + +---------------------------------------- + +### @typescript-eslint/types@v5.55.0 + +License: MIT +Repository: + +> MIT License +> +> Copyright (c) 2019 typescript-eslint and other contributors +> +> 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. + +---------------------------------------- + +### @typescript-eslint/typescript-estree@v5.55.0 + +License: BSD-2-Clause +Repository: + +> TypeScript ESTree +> +> Originally extracted from: +> +> TypeScript ESLint Parser +> Copyright JS Foundation and other contributors, https://js.foundation +> +> Redistribution and use in source and binary forms, with or without +> modification, are permitted provided that the following conditions are met: +> +> - Redistributions of source code must retain the above copyright +> notice, this list of conditions and the following disclaimer. +> - Redistributions in binary form must reproduce the above copyright +> notice, this list of conditions and the following disclaimer in the +> documentation and/or other materials provided with the distribution. +> +> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +> ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +> DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +> (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +> ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +> THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------- + +### @typescript-eslint/visitor-keys@v5.55.0 + +License: MIT +Repository: + +> MIT License +> +> Copyright (c) 2019 typescript-eslint and other contributors +> +> 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. + +---------------------------------------- + +### acorn@v8.8.1 + +License: MIT +Repository: + +> MIT License +> +> Copyright (C) 2012-2022 by various contributors (see AUTHORS) +> +> 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. + +---------------------------------------- + +### acorn-jsx@v5.3.2 + +License: MIT +Repository: + +> Copyright (C) 2012-2017 by Ingvar Stepanyan +> +> 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. + +---------------------------------------- + +### aggregate-error@v3.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### angular-estree-parser@v2.5.1 + +License: MIT +By: Ika + +> MIT License +> +> Copyright (c) Ika (https://github.com/ikatyang) +> +> 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. + +---------------------------------------- + +### angular-html-parser@v1.8.0 + +License: MIT +By: Ika + +> MIT License +> +> Copyright (c) Ika (https://github.com/ikatyang) +> +> 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. + +---------------------------------------- + +### ansi-regex@v6.0.1 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### ansi-styles@v3.2.1 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### array-union@v2.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### bail@v1.0.5 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### balanced-match@v1.0.2 + +License: MIT +By: Julian Gruber +Repository: + +> (MIT) +> +> Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> +> +> 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. + +---------------------------------------- + +### brace-expansion@v1.1.11 + +License: MIT +By: Julian Gruber +Repository: + +> MIT License +> +> Copyright (c) 2013 Julian Gruber +> +> 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. + +---------------------------------------- + +### braces@v3.0.2 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2014-2018, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### camelcase@v6.3.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### ccount@v1.1.0 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### chalk@v2.4.2 + +License: MIT + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### chalk@v5.0.1 + +License: MIT + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### character-entities@v1.2.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### character-entities-legacy@v1.1.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### character-reference-invalid@v1.1.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### ci-info@v3.3.0 + +License: MIT +By: Thomas Watson Steen +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2016-2021 Thomas Watson Steen +> +> 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. + +---------------------------------------- + +### clean-stack@v2.2.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### clone@v1.0.4 + +License: MIT +By: Paul Vorbach +Repository: + +> Copyright © 2011-2015 Paul Vorbach +> +> 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, OUT OF OR IN CONNECTION WITH THE +> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +---------------------------------------- + +### collapse-white-space@v1.0.6 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### color-convert@v1.9.3 + +License: MIT +By: Heather Arthur + +> Copyright (c) 2011-2016 Heather Arthur +> +> 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. + +---------------------------------------- + +### color-name@v1.1.3 + +License: MIT +By: DY +Repository: + +> The MIT License (MIT) +> Copyright (c) 2015 Dmitry Ivanov +> +> 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. + +---------------------------------------- + +### commondir@v1.0.1 + +License: MIT +By: James Halliday +Repository: + +> The MIT License +> +> Copyright (c) 2013 James Halliday (mail@substack.net) +> +> 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. + +---------------------------------------- + +### concat-map@v0.0.1 + +License: MIT +By: James Halliday +Repository: + +> This software is released under the MIT license: +> +> 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. + +---------------------------------------- + +### cosmiconfig@v7.0.1 + +License: MIT +By: David Clark +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2015 David Clark +> +> 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. + +---------------------------------------- + +### cross-spawn@v7.0.3 + +License: MIT +By: André Cruz +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2018 Made With MOXY Lda +> +> 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. + +---------------------------------------- + +### crypto-random-string@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### css-units-list@v1.1.0 + +License: MIT +By: fisker Cheung + +> MIT License +> +> Copyright (c) fisker Cheung (https://www.fiskercheung.com/) +> +> 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. + +---------------------------------------- + +### dashify@v2.0.0 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2015-present, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### defaults@v1.0.4 + +License: MIT +By: Elijah Insua +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2022 Sindre Sorhus +> Copyright (c) 2015 Elijah Insua +> +> 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. + +---------------------------------------- + +### del@v6.1.1 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### detect-newline@v3.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### diff@v5.0.0 + +License: BSD-3-Clause +Repository: + +> Software License Agreement (BSD License) +> +> Copyright (c) 2009-2015, Kevin Decker +> +> All rights reserved. +> +> Redistribution and use of this software in source and binary forms, with or without modification, +> are permitted provided that the following conditions are met: +> +> * Redistributions of source code must retain the above +> copyright notice, this list of conditions and the +> following disclaimer. +> +> * Redistributions in binary form must reproduce the above +> copyright notice, this list of conditions and the +> following disclaimer in the documentation and/or other +> materials provided with the distribution. +> +> * Neither the name of Kevin Decker nor the names of its +> contributors may be used to endorse or promote products +> derived from this software without specific prior +> written permission. +> +> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +> IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +> FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +> CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +> DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +> IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +> OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------- + +### dir-glob@v3.0.1 + +License: MIT +By: Kevin Mårtensson + +> MIT License +> +> Copyright (c) Kevin Mårtensson (github.com/kevva) +> +> 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. + +---------------------------------------- + +### editorconfig@v0.15.3 + +License: MIT +By: EditorConfig Team +Repository: + +> Copyright © 2012 EditorConfig Team +> +> 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. + +---------------------------------------- + +### editorconfig-to-prettier@v1.0.0 + +License: ISC +By: Joseph Frazier +Repository: + +---------------------------------------- + +### emoji-regex@v9.2.2 + +License: MIT +By: Mathias Bynens +Repository: + +> Copyright Mathias Bynens +> +> 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. + +---------------------------------------- + +### error-ex@v1.3.2 + +License: MIT + +> The MIT License (MIT) +> +> Copyright (c) 2015 JD Ballard +> +> 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. + +---------------------------------------- + +### escape-string-regexp@v1.0.5 + +License: MIT +By: Sindre Sorhus + +> The MIT License (MIT) +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### escape-string-regexp@v5.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### eslint-visitor-keys@v3.3.0 + +License: Apache-2.0 +By: Toru Nagashima + +> Apache License +> Version 2.0, January 2004 +> http://www.apache.org/licenses/ +> +> TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +> +> 1. Definitions. +> +> "License" shall mean the terms and conditions for use, reproduction, +> and distribution as defined by Sections 1 through 9 of this document. +> +> "Licensor" shall mean the copyright owner or entity authorized by +> the copyright owner that is granting the License. +> +> "Legal Entity" shall mean the union of the acting entity and all +> other entities that control, are controlled by, or are under common +> control with that entity. For the purposes of this definition, +> "control" means (i) the power, direct or indirect, to cause the +> direction or management of such entity, whether by contract or +> otherwise, or (ii) ownership of fifty percent (50%) or more of the +> outstanding shares, or (iii) beneficial ownership of such entity. +> +> "You" (or "Your") shall mean an individual or Legal Entity +> exercising permissions granted by this License. +> +> "Source" form shall mean the preferred form for making modifications, +> including but not limited to software source code, documentation +> source, and configuration files. +> +> "Object" form shall mean any form resulting from mechanical +> transformation or translation of a Source form, including but +> not limited to compiled object code, generated documentation, +> and conversions to other media types. +> +> "Work" shall mean the work of authorship, whether in Source or +> Object form, made available under the License, as indicated by a +> copyright notice that is included in or attached to the work +> (an example is provided in the Appendix below). +> +> "Derivative Works" shall mean any work, whether in Source or Object +> form, that is based on (or derived from) the Work and for which the +> editorial revisions, annotations, elaborations, or other modifications +> represent, as a whole, an original work of authorship. For the purposes +> of this License, Derivative Works shall not include works that remain +> separable from, or merely link (or bind by name) to the interfaces of, +> the Work and Derivative Works thereof. +> +> "Contribution" shall mean any work of authorship, including +> the original version of the Work and any modifications or additions +> to that Work or Derivative Works thereof, that is intentionally +> submitted to Licensor for inclusion in the Work by the copyright owner +> or by an individual or Legal Entity authorized to submit on behalf of +> the copyright owner. For the purposes of this definition, "submitted" +> means any form of electronic, verbal, or written communication sent +> to the Licensor or its representatives, including but not limited to +> communication on electronic mailing lists, source code control systems, +> and issue tracking systems that are managed by, or on behalf of, the +> Licensor for the purpose of discussing and improving the Work, but +> excluding communication that is conspicuously marked or otherwise +> designated in writing by the copyright owner as "Not a Contribution." +> +> "Contributor" shall mean Licensor and any individual or Legal Entity +> on behalf of whom a Contribution has been received by Licensor and +> subsequently incorporated within the Work. +> +> 2. Grant of Copyright License. Subject to the terms and conditions of +> this License, each Contributor hereby grants to You a perpetual, +> worldwide, non-exclusive, no-charge, royalty-free, irrevocable +> copyright license to reproduce, prepare Derivative Works of, +> publicly display, publicly perform, sublicense, and distribute the +> Work and such Derivative Works in Source or Object form. +> +> 3. Grant of Patent License. Subject to the terms and conditions of +> this License, each Contributor hereby grants to You a perpetual, +> worldwide, non-exclusive, no-charge, royalty-free, irrevocable +> (except as stated in this section) patent license to make, have made, +> use, offer to sell, sell, import, and otherwise transfer the Work, +> where such license applies only to those patent claims licensable +> by such Contributor that are necessarily infringed by their +> Contribution(s) alone or by combination of their Contribution(s) +> with the Work to which such Contribution(s) was submitted. If You +> institute patent litigation against any entity (including a +> cross-claim or counterclaim in a lawsuit) alleging that the Work +> or a Contribution incorporated within the Work constitutes direct +> or contributory patent infringement, then any patent licenses +> granted to You under this License for that Work shall terminate +> as of the date such litigation is filed. +> +> 4. Redistribution. You may reproduce and distribute copies of the +> Work or Derivative Works thereof in any medium, with or without +> modifications, and in Source or Object form, provided that You +> meet the following conditions: +> +> (a) You must give any other recipients of the Work or +> Derivative Works a copy of this License; and +> +> (b) You must cause any modified files to carry prominent notices +> stating that You changed the files; and +> +> (c) You must retain, in the Source form of any Derivative Works +> that You distribute, all copyright, patent, trademark, and +> attribution notices from the Source form of the Work, +> excluding those notices that do not pertain to any part of +> the Derivative Works; and +> +> (d) If the Work includes a "NOTICE" text file as part of its +> distribution, then any Derivative Works that You distribute must +> include a readable copy of the attribution notices contained +> within such NOTICE file, excluding those notices that do not +> pertain to any part of the Derivative Works, in at least one +> of the following places: within a NOTICE text file distributed +> as part of the Derivative Works; within the Source form or +> documentation, if provided along with the Derivative Works; or, +> within a display generated by the Derivative Works, if and +> wherever such third-party notices normally appear. The contents +> of the NOTICE file are for informational purposes only and +> do not modify the License. You may add Your own attribution +> notices within Derivative Works that You distribute, alongside +> or as an addendum to the NOTICE text from the Work, provided +> that such additional attribution notices cannot be construed +> as modifying the License. +> +> You may add Your own copyright statement to Your modifications and +> may provide additional or different license terms and conditions +> for use, reproduction, or distribution of Your modifications, or +> for any such Derivative Works as a whole, provided Your use, +> reproduction, and distribution of the Work otherwise complies with +> the conditions stated in this License. +> +> 5. Submission of Contributions. Unless You explicitly state otherwise, +> any Contribution intentionally submitted for inclusion in the Work +> by You to the Licensor shall be under the terms and conditions of +> this License, without any additional terms or conditions. +> Notwithstanding the above, nothing herein shall supersede or modify +> the terms of any separate license agreement you may have executed +> with Licensor regarding such Contributions. +> +> 6. Trademarks. This License does not grant permission to use the trade +> names, trademarks, service marks, or product names of the Licensor, +> except as required for reasonable and customary use in describing the +> origin of the Work and reproducing the content of the NOTICE file. +> +> 7. Disclaimer of Warranty. Unless required by applicable law or +> agreed to in writing, Licensor provides the Work (and each +> Contributor provides its Contributions) on an "AS IS" BASIS, +> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +> implied, including, without limitation, any warranties or conditions +> of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +> PARTICULAR PURPOSE. You are solely responsible for determining the +> appropriateness of using or redistributing the Work and assume any +> risks associated with Your exercise of permissions under this License. +> +> 8. Limitation of Liability. In no event and under no legal theory, +> whether in tort (including negligence), contract, or otherwise, +> unless required by applicable law (such as deliberate and grossly +> negligent acts) or agreed to in writing, shall any Contributor be +> liable to You for damages, including any direct, indirect, special, +> incidental, or consequential damages of any character arising as a +> result of this License or out of the use or inability to use the +> Work (including but not limited to damages for loss of goodwill, +> work stoppage, computer failure or malfunction, or any and all +> other commercial damages or losses), even if such Contributor +> has been advised of the possibility of such damages. +> +> 9. Accepting Warranty or Additional Liability. While redistributing +> the Work or Derivative Works thereof, You may choose to offer, +> and charge a fee for, acceptance of support, warranty, indemnity, +> or other liability obligations and/or rights consistent with this +> License. However, in accepting such obligations, You may act only +> on Your own behalf and on Your sole responsibility, not on behalf +> of any other Contributor, and only if You agree to indemnify, +> defend, and hold each Contributor harmless for any liability +> incurred by, or claims asserted against, such Contributor by reason +> of your accepting any such warranty or additional liability. +> +> END OF TERMS AND CONDITIONS +> +> APPENDIX: How to apply the Apache License to your work. +> +> To apply the Apache License to your work, attach the following +> boilerplate notice, with the fields enclosed by brackets "{}" +> replaced with your own identifying information. (Don't include +> the brackets!) The text should be enclosed in the appropriate +> comment syntax for the file format. We also recommend that a +> file or class name and description of purpose be included on the +> same "printed page" as the copyright notice for easier +> identification within third-party archives. +> +> Copyright contributors +> +> Licensed under the Apache License, Version 2.0 (the "License"); +> you may not use this file except in compliance with the License. +> You may obtain a copy of the License at +> +> http://www.apache.org/licenses/LICENSE-2.0 +> +> Unless required by applicable law or agreed to in writing, software +> distributed under the License is distributed on an "AS IS" BASIS, +> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +> See the License for the specific language governing permissions and +> limitations under the License. + +---------------------------------------- + +### espree@v9.4.1 + +License: BSD-2-Clause +By: Nicholas C. Zakas + +> BSD 2-Clause License +> +> Copyright (c) Open JS Foundation +> All rights reserved. +> +> Redistribution and use in source and binary forms, with or without +> modification, are permitted provided that the following conditions are met: +> +> 1. Redistributions of source code must retain the above copyright notice, this +> list of conditions and the following disclaimer. +> +> 2. Redistributions in binary form must reproduce the above copyright notice, +> this list of conditions and the following disclaimer in the documentation +> and/or other materials provided with the distribution. +> +> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------- + +### esutils@v2.0.3 + +License: BSD-2-Clause +Repository: + +> Redistribution and use in source and binary forms, with or without +> modification, are permitted provided that the following conditions are met: +> +> * Redistributions of source code must retain the above copyright +> notice, this list of conditions and the following disclaimer. +> * Redistributions in binary form must reproduce the above copyright +> notice, this list of conditions and the following disclaimer in the +> documentation and/or other materials provided with the distribution. +> +> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +> ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +> DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +> (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +> ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +> THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------- + +### execa@v6.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### extend@v3.0.2 + +License: MIT +By: Stefan Thomas +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2014 Stefan Thomas +> +> 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. + +---------------------------------------- + +### fast-glob@v3.2.12 + +License: MIT +By: Denis Malinochkin + +> The MIT License (MIT) +> +> Copyright (c) Denis Malinochkin +> +> 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. + +---------------------------------------- + +### fast-json-stable-stringify@v2.1.0 + +License: MIT +By: James Halliday +Repository: + +> This software is released under the MIT license: +> +> Copyright (c) 2017 Evgeny Poberezkin +> Copyright (c) 2013 James Halliday +> +> 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. + +---------------------------------------- + +### fastq@v1.14.0 + +License: ISC +By: Matteo Collina +Repository: + +> Copyright (c) 2015-2020, Matteo Collina +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +> OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### file-entry-cache@v6.0.1 + +License: MIT +By: Roy Riojas + +> The MIT License (MIT) +> +> Copyright (c) 2015 Roy Riojas +> +> 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. + +---------------------------------------- + +### fill-range@v7.0.1 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2014-present, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### find-cache-dir@v3.3.2 + +License: MIT + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### find-parent-dir@v0.3.1 + +License: MIT +By: Thorsten Lorenz +Repository: + +> Copyright 2013 Thorsten Lorenz. +> All rights reserved. +> +> 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. + +---------------------------------------- + +### find-up@v4.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### flat-cache@v3.0.4 + +License: MIT +By: Roy Riojas + +> The MIT License (MIT) +> +> Copyright (c) 2015 Roy Riojas +> +> 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. + +---------------------------------------- + +### flatted@v3.2.7 + +License: ISC +By: Andrea Giammarchi +Repository: + +> ISC License +> +> Copyright (c) 2018-2020, Andrea Giammarchi, @WebReflection +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +> REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +> AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +> INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +> LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +> OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +> PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### flatten@v1.0.3 + +License: MIT +By: Joshua Holbrook +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2016 Joshua Holbrook +> +> 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. + +---------------------------------------- + +### flow-parser@v0.180.0 + +License: MIT +By: Flow Team +Repository: + +---------------------------------------- + +### fs.realpath@v1.0.0 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +> +> ---- +> +> This library bundles a version of the `fs.realpath` and `fs.realpathSync` +> methods from Node.js v0.10 under the terms of the Node.js MIT license. +> +> Node's license follows, also included at the header of `old.js` which contains +> the licensed code: +> +> Copyright Joyent, Inc. and other Node contributors. +> +> 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. + +---------------------------------------- + +### function-bind@v1.1.1 + +License: MIT +By: Raynos + +> Copyright (c) 2013 Raynos. +> +> 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. + +---------------------------------------- + +### get-stdin@v8.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### get-stream@v6.0.1 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### glob@v7.2.3 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +> +> ## Glob Logo +> +> Glob's logo created by Tanya Brassie , licensed +> under a Creative Commons Attribution-ShareAlike 4.0 International License +> https://creativecommons.org/licenses/by-sa/4.0/ + +---------------------------------------- + +### glob-parent@v5.1.2 + +License: ISC +By: Gulp Team + +> The ISC License +> +> Copyright (c) 2015, 2019 Elan Shanker +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### globby@v11.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### graceful-fs@v4.2.10 + +License: ISC +Repository: + +> The ISC License +> +> Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### graphql@v15.6.1 + +License: MIT +Repository: + +> MIT License +> +> Copyright (c) GraphQL Contributors +> +> 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. + +---------------------------------------- + +### has@v1.0.3 + +License: MIT +By: Thiago de Arruda +Repository: + +> Copyright (c) 2013 Thiago de Arruda +> +> 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. + +---------------------------------------- + +### has-flag@v3.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### html-element-attributes@v3.1.0 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### html-tag-names@v2.0.1 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### human-signals@v3.0.1 + +License: Apache-2.0 +By: ehmicky + +> Apache License +> Version 2.0, January 2004 +> http://www.apache.org/licenses/ +> +> TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +> +> 1. Definitions. +> +> "License" shall mean the terms and conditions for use, reproduction, +> and distribution as defined by Sections 1 through 9 of this document. +> +> "Licensor" shall mean the copyright owner or entity authorized by +> the copyright owner that is granting the License. +> +> "Legal Entity" shall mean the union of the acting entity and all +> other entities that control, are controlled by, or are under common +> control with that entity. For the purposes of this definition, +> "control" means (i) the power, direct or indirect, to cause the +> direction or management of such entity, whether by contract or +> otherwise, or (ii) ownership of fifty percent (50%) or more of the +> outstanding shares, or (iii) beneficial ownership of such entity. +> +> "You" (or "Your") shall mean an individual or Legal Entity +> exercising permissions granted by this License. +> +> "Source" form shall mean the preferred form for making modifications, +> including but not limited to software source code, documentation +> source, and configuration files. +> +> "Object" form shall mean any form resulting from mechanical +> transformation or translation of a Source form, including but +> not limited to compiled object code, generated documentation, +> and conversions to other media types. +> +> "Work" shall mean the work of authorship, whether in Source or +> Object form, made available under the License, as indicated by a +> copyright notice that is included in or attached to the work +> (an example is provided in the Appendix below). +> +> "Derivative Works" shall mean any work, whether in Source or Object +> form, that is based on (or derived from) the Work and for which the +> editorial revisions, annotations, elaborations, or other modifications +> represent, as a whole, an original work of authorship. For the purposes +> of this License, Derivative Works shall not include works that remain +> separable from, or merely link (or bind by name) to the interfaces of, +> the Work and Derivative Works thereof. +> +> "Contribution" shall mean any work of authorship, including +> the original version of the Work and any modifications or additions +> to that Work or Derivative Works thereof, that is intentionally +> submitted to Licensor for inclusion in the Work by the copyright owner +> or by an individual or Legal Entity authorized to submit on behalf of +> the copyright owner. For the purposes of this definition, "submitted" +> means any form of electronic, verbal, or written communication sent +> to the Licensor or its representatives, including but not limited to +> communication on electronic mailing lists, source code control systems, +> and issue tracking systems that are managed by, or on behalf of, the +> Licensor for the purpose of discussing and improving the Work, but +> excluding communication that is conspicuously marked or otherwise +> designated in writing by the copyright owner as "Not a Contribution." +> +> "Contributor" shall mean Licensor and any individual or Legal Entity +> on behalf of whom a Contribution has been received by Licensor and +> subsequently incorporated within the Work. +> +> 2. Grant of Copyright License. Subject to the terms and conditions of +> this License, each Contributor hereby grants to You a perpetual, +> worldwide, non-exclusive, no-charge, royalty-free, irrevocable +> copyright license to reproduce, prepare Derivative Works of, +> publicly display, publicly perform, sublicense, and distribute the +> Work and such Derivative Works in Source or Object form. +> +> 3. Grant of Patent License. Subject to the terms and conditions of +> this License, each Contributor hereby grants to You a perpetual, +> worldwide, non-exclusive, no-charge, royalty-free, irrevocable +> (except as stated in this section) patent license to make, have made, +> use, offer to sell, sell, import, and otherwise transfer the Work, +> where such license applies only to those patent claims licensable +> by such Contributor that are necessarily infringed by their +> Contribution(s) alone or by combination of their Contribution(s) +> with the Work to which such Contribution(s) was submitted. If You +> institute patent litigation against any entity (including a +> cross-claim or counterclaim in a lawsuit) alleging that the Work +> or a Contribution incorporated within the Work constitutes direct +> or contributory patent infringement, then any patent licenses +> granted to You under this License for that Work shall terminate +> as of the date such litigation is filed. +> +> 4. Redistribution. You may reproduce and distribute copies of the +> Work or Derivative Works thereof in any medium, with or without +> modifications, and in Source or Object form, provided that You +> meet the following conditions: +> +> (a) You must give any other recipients of the Work or +> Derivative Works a copy of this License; and +> +> (b) You must cause any modified files to carry prominent notices +> stating that You changed the files; and +> +> (c) You must retain, in the Source form of any Derivative Works +> that You distribute, all copyright, patent, trademark, and +> attribution notices from the Source form of the Work, +> excluding those notices that do not pertain to any part of +> the Derivative Works; and +> +> (d) If the Work includes a "NOTICE" text file as part of its +> distribution, then any Derivative Works that You distribute must +> include a readable copy of the attribution notices contained +> within such NOTICE file, excluding those notices that do not +> pertain to any part of the Derivative Works, in at least one +> of the following places: within a NOTICE text file distributed +> as part of the Derivative Works; within the Source form or +> documentation, if provided along with the Derivative Works; or, +> within a display generated by the Derivative Works, if and +> wherever such third-party notices normally appear. The contents +> of the NOTICE file are for informational purposes only and +> do not modify the License. You may add Your own attribution +> notices within Derivative Works that You distribute, alongside +> or as an addendum to the NOTICE text from the Work, provided +> that such additional attribution notices cannot be construed +> as modifying the License. +> +> You may add Your own copyright statement to Your modifications and +> may provide additional or different license terms and conditions +> for use, reproduction, or distribution of Your modifications, or +> for any such Derivative Works as a whole, provided Your use, +> reproduction, and distribution of the Work otherwise complies with +> the conditions stated in this License. +> +> 5. Submission of Contributions. Unless You explicitly state otherwise, +> any Contribution intentionally submitted for inclusion in the Work +> by You to the Licensor shall be under the terms and conditions of +> this License, without any additional terms or conditions. +> Notwithstanding the above, nothing herein shall supersede or modify +> the terms of any separate license agreement you may have executed +> with Licensor regarding such Contributions. +> +> 6. Trademarks. This License does not grant permission to use the trade +> names, trademarks, service marks, or product names of the Licensor, +> except as required for reasonable and customary use in describing the +> origin of the Work and reproducing the content of the NOTICE file. +> +> 7. Disclaimer of Warranty. Unless required by applicable law or +> agreed to in writing, Licensor provides the Work (and each +> Contributor provides its Contributions) on an "AS IS" BASIS, +> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +> implied, including, without limitation, any warranties or conditions +> of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +> PARTICULAR PURPOSE. You are solely responsible for determining the +> appropriateness of using or redistributing the Work and assume any +> risks associated with Your exercise of permissions under this License. +> +> 8. Limitation of Liability. In no event and under no legal theory, +> whether in tort (including negligence), contract, or otherwise, +> unless required by applicable law (such as deliberate and grossly +> negligent acts) or agreed to in writing, shall any Contributor be +> liable to You for damages, including any direct, indirect, special, +> incidental, or consequential damages of any character arising as a +> result of this License or out of the use or inability to use the +> Work (including but not limited to damages for loss of goodwill, +> work stoppage, computer failure or malfunction, or any and all +> other commercial damages or losses), even if such Contributor +> has been advised of the possibility of such damages. +> +> 9. Accepting Warranty or Additional Liability. While redistributing +> the Work or Derivative Works thereof, You may choose to offer, +> and charge a fee for, acceptance of support, warranty, indemnity, +> or other liability obligations and/or rights consistent with this +> License. However, in accepting such obligations, You may act only +> on Your own behalf and on Your sole responsibility, not on behalf +> of any other Contributor, and only if You agree to indemnify, +> defend, and hold each Contributor harmless for any liability +> incurred by, or claims asserted against, such Contributor by reason +> of your accepting any such warranty or additional liability. +> +> END OF TERMS AND CONDITIONS +> +> APPENDIX: How to apply the Apache License to your work. +> +> To apply the Apache License to your work, attach the following +> boilerplate notice, with the fields enclosed by brackets "[]" +> replaced with your own identifying information. (Don't include +> the brackets!) The text should be enclosed in the appropriate +> comment syntax for the file format. We also recommend that a +> file or class name and description of purpose be included on the +> same "printed page" as the copyright notice for easier +> identification within third-party archives. +> +> Copyright 2021 ehmicky +> +> Licensed under the Apache License, Version 2.0 (the "License"); +> you may not use this file except in compliance with the License. +> You may obtain a copy of the License at +> +> http://www.apache.org/licenses/LICENSE-2.0 +> +> Unless required by applicable law or agreed to in writing, software +> distributed under the License is distributed on an "AS IS" BASIS, +> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +> See the License for the specific language governing permissions and +> limitations under the License. + +---------------------------------------- + +### ignore@v5.2.0 + +License: MIT +By: kael +Repository: + +> Copyright (c) 2013 Kael Zhang , contributors +> http://kael.me/ +> +> 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. + +---------------------------------------- + +### ignore@v5.2.4 + +License: MIT +By: kael +Repository: + +> Copyright (c) 2013 Kael Zhang , contributors +> http://kael.me/ +> +> 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-fresh@v3.3.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### indent-string@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### indexes-of@v1.0.1 + +License: MIT +By: Dominic Tarr +Repository: + +> Copyright (c) 2013 Dominic Tarr +> +> 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. + +---------------------------------------- + +### inflight@v1.0.6 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### inherits@v2.0.4 + +License: ISC + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +> REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +> FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +> INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +> LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +> OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +> PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### is-alphabetical@v1.0.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### is-alphanumerical@v1.0.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### is-arrayish@v0.2.1 + +License: MIT +By: Qix +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2015 JD Ballard +> +> 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. + +---------------------------------------- + +### is-buffer@v2.0.5 + +License: MIT +By: Feross Aboukhadijeh +Repository: + +> The MIT License (MIT) +> +> Copyright (c) Feross Aboukhadijeh +> +> 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. + +---------------------------------------- + +### is-core-module@v2.11.0 + +License: MIT +By: Jordan Harband +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2014 Dave Justice +> +> 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. + +---------------------------------------- + +### is-decimal@v1.0.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### is-extglob@v2.1.1 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2014-2016, Jon Schlinkert +> +> 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. + +---------------------------------------- + +### is-fullwidth-code-point@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### is-glob@v4.0.3 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2014-2017, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### is-hexadecimal@v1.0.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### is-number@v7.0.0 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2014-present, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### is-path-cwd@v2.2.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### is-path-inside@v3.0.3 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### is-plain-obj@v2.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### is-stream@v3.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### is-whitespace-character@v1.0.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### is-word-character@v1.0.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### isexe@v2.0.0 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### jest-docblock@v28.1.1 + +License: MIT +Repository: + +> MIT License +> +> Copyright (c) Facebook, Inc. and its affiliates. +> +> 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. + +---------------------------------------- + +### js-tokens@v4.0.0 + +License: MIT +By: Simon Lydell + +> The MIT License (MIT) +> +> Copyright (c) 2014, 2015, 2016, 2017, 2018 Simon Lydell +> +> 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. + +---------------------------------------- + +### json-parse-even-better-errors@v2.3.1 + +License: MIT +By: Kat Marchán + +> Copyright 2017 Kat Marchán +> Copyright npm, 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. +> +> --- +> +> This library is a fork of 'better-json-errors' by Kat Marchán, extended and +> distributed under the terms of the MIT license above. + +---------------------------------------- + +### json5@v2.2.2 + +License: MIT +By: Aseem Kishore +Repository: + +> MIT License +> +> Copyright (c) 2012-2018 Aseem Kishore, and [others]. +> +> 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. +> +> [others]: https://github.com/json5/json5/contributors + +---------------------------------------- + +### leven@v2.1.0 + +License: MIT +By: Sindre Sorhus + +> The MIT License (MIT) +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### leven@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### lines-and-columns@v1.2.4 + +License: MIT +By: Brian Donovan +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2015 Brian Donovan +> +> 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. + +---------------------------------------- + +### lines-and-columns@v2.0.3 + +License: MIT +By: Brian Donovan +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2015 Brian Donovan +> +> 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. + +---------------------------------------- + +### linguist-languages@v7.21.0 + +License: MIT +By: Ika + +> MIT License +> +> Copyright (c) Ika (https://github.com/ikatyang) +> +> 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. + +---------------------------------------- + +### locate-path@v5.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### lru-cache@v4.1.5 + +License: ISC +By: Isaac Z. Schlueter + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### lru-cache@v6.0.0 + +License: ISC +By: Isaac Z. Schlueter + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### make-dir@v3.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### map-age-cleaner@v0.1.3 + +License: MIT +By: Sam Verschueren + +> MIT License +> +> Copyright (c) Sam Verschueren (github.com/SamVerschueren) +> +> 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. + +---------------------------------------- + +### markdown-escapes@v1.0.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### mem@v9.0.2 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### merge-stream@v2.0.0 + +License: MIT +By: Stephen Sugden + +> The MIT License (MIT) +> +> Copyright (c) Stephen Sugden (stephensugden.com) +> +> 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. + +---------------------------------------- + +### merge2@v1.4.1 + +License: MIT +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2014-2020 Teambition +> +> 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. + +---------------------------------------- + +### meriyah@v4.2.1 + +License: ISC +By: Kenny F. +Repository: + +> ISC License +> +> Copyright (c) 2019 and later, KFlash and others. +> +> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### micromatch@v4.0.5 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2014-present, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### mimic-fn@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### minimatch@v3.1.2 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### minimist@v1.2.6 + +License: MIT +By: James Halliday +Repository: + +> This software is released under the MIT license: +> +> 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. + +---------------------------------------- + +### n-readlines@v1.0.1 + +License: MIT +By: Yoan Arnaudov +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2013 Liucw +> +> 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. + +---------------------------------------- + +### npm-run-path@v5.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### once@v1.4.0 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### onetime@v6.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### outdent@v0.8.0 + +License: MIT +By: Andrew Bradley +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2016 Andrew Bradley +> +> 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. + +---------------------------------------- + +### p-defer@v1.0.0 + +License: MIT +By: Sindre Sorhus + +> The MIT License (MIT) +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### p-limit@v2.3.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### p-locate@v4.1.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### p-map@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### p-try@v2.2.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### parse-entities@v2.0.0 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### parse-json@v5.2.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### parse-srcset@v1.0.2 + +License: MIT +By: Alex Bell +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2014 Alex Bell +> +> 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. + +---------------------------------------- + +### path-exists@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### path-is-absolute@v1.0.1 + +License: MIT +By: Sindre Sorhus + +> The MIT License (MIT) +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### path-key@v3.1.1 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### path-parse@v1.0.7 + +License: MIT +By: Javier Blanco +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2015 Javier Blanco +> +> 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. + +---------------------------------------- + +### path-type@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### picocolors@v0.2.1 + +License: ISC +By: Alexey Raspopov + +> ISC License +> +> Copyright (c) 2021 Alexey Raspopov, Kostiantyn Denysov, Anton Verinov +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +> OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### picomatch@v2.3.1 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2017-present, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### pkg-dir@v4.2.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### please-upgrade-node@v3.2.0 + +License: MIT +By: typicode +Repository: + +> MIT License +> +> Copyright (c) 2017 +> +> 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. + +---------------------------------------- + +### postcss@v7.0.39 + +License: MIT +By: Andrey Sitnik + +> The MIT License (MIT) +> +> Copyright 2013 Andrey Sitnik +> +> 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. + +---------------------------------------- + +### postcss-less@v3.1.4 + +License: MIT +By: Denys Kniazevych + +> The MIT License (MIT) +> +> Copyright (c) 2013 Andrey Sitnik +> Copyright (c) 2016 Denys Kniazevych +> Copyright (c) 2016 Pat Sissons +> Copyright (c) 2017 Andrew Powell +> +> 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. + +---------------------------------------- + +### postcss-media-query-parser@v0.2.3 + +License: MIT +By: dryoma +Repository: + +---------------------------------------- + +### postcss-scss@v2.1.1 + +License: MIT +By: Andrey Sitnik + +> The MIT License (MIT) +> +> Copyright 2013 Andrey Sitnik +> +> 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. + +---------------------------------------- + +### postcss-selector-parser@v2.2.3 + +License: MIT +By: Ben Briggs + +> Copyright (c) Ben Briggs (http://beneb.info) +> +> 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. + +---------------------------------------- + +### postcss-values-parser@v2.0.1 + +License: MIT +By: Andrew Powell (shellscape) + +> Copyright (c) Andrew Powell +> +> 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. + +---------------------------------------- + +### pseudomap@v1.0.2 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### queue-microtask@v1.2.3 + +License: MIT +By: Feross Aboukhadijeh +Repository: + +> The MIT License (MIT) +> +> Copyright (c) Feross Aboukhadijeh +> +> 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. + +---------------------------------------- + +### remark-footnotes@v2.0.0 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2020 Titus Wormer +> +> 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. + +---------------------------------------- + +### remark-math@v3.0.1 + +License: MIT +By: Junyoung Choi + +---------------------------------------- + +### remark-parse@v8.0.3 + +License: MIT +By: Titus Wormer + +---------------------------------------- + +### repeat-string@v1.6.1 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2014-2016, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### resolve@v1.22.1 + +License: MIT +By: James Halliday +Repository: + +> MIT License +> +> Copyright (c) 2012 James Halliday +> +> 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. + +---------------------------------------- + +### resolve-from@v4.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### reusify@v1.0.4 + +License: MIT +By: Matteo Collina +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2015 Matteo Collina +> +> 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. + +---------------------------------------- + +### rimraf@v3.0.2 + +License: ISC +By: Isaac Z. Schlueter + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### rollup-plugin-node-polyfills@v0.2.1 + +License: MIT +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2019 these people +> +> 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. + +---------------------------------------- + +### run-parallel@v1.2.0 + +License: MIT +By: Feross Aboukhadijeh +Repository: + +> The MIT License (MIT) +> +> Copyright (c) Feross Aboukhadijeh +> +> 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. + +---------------------------------------- + +### sdbm@v2.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### semver@v6.3.0 + +License: ISC + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### semver@v7.3.7 + +License: ISC +By: GitHub Inc. +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### semver@v7.3.8 + +License: ISC +By: GitHub Inc. +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### semver-compare@v1.0.0 + +License: MIT +By: James Halliday +Repository: + +> This software is released under the MIT license: +> +> 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. + +---------------------------------------- + +### shebang-command@v2.0.0 + +License: MIT +By: Kevin Mårtensson + +> MIT License +> +> Copyright (c) Kevin Mårtensson (github.com/kevva) +> +> 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. + +---------------------------------------- + +### shebang-regex@v3.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### sigmund@v1.0.1 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### signal-exit@v3.0.7 + +License: ISC +By: Ben Coe +Repository: + +> The ISC License +> +> Copyright (c) 2015, Contributors +> +> Permission to use, copy, modify, and/or distribute this software +> for any purpose with or without fee is hereby granted, provided +> that the above copyright notice and this permission notice +> appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +> OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +> LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +> OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +> WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +> ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### simple-html-tokenizer@v0.5.11 + +License: MIT +Repository: + +> Copyright (c) 2014 Yehuda Katz and contributors +> +> 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. + +---------------------------------------- + +### slash@v3.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### state-toggle@v1.0.3 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### string-width@v5.0.1 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### strip-ansi@v7.0.1 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### strip-final-newline@v3.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### supports-color@v5.5.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### temp-dir@v2.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (sindresorhus.com) +> +> 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. + +---------------------------------------- + +### tempy@v2.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### to-regex-range@v5.0.1 + +License: MIT +By: Jon Schlinkert + +> The MIT License (MIT) +> +> Copyright (c) 2015-present, Jon Schlinkert. +> +> 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. + +---------------------------------------- + +### trim@v0.0.1 + +By: TJ Holowaychuk + +---------------------------------------- + +### trim-trailing-lines@v1.1.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### trough@v1.0.5 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### tslib@v1.14.1 + +License: 0BSD +By: Microsoft Corp. +Repository: + +> Copyright (c) Microsoft Corporation. +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +> REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +> AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +> INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +> LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +> OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +> PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### tsutils@v3.21.0 + +License: MIT +By: Klaus Meinhardt +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2017 Klaus Meinhardt +> +> 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. + +---------------------------------------- + +### typescript@v5.0.2 + +License: Apache-2.0 +By: Microsoft Corp. +Repository: + +> Apache License +> +> Version 2.0, January 2004 +> +> http://www.apache.org/licenses/ +> +> TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +> +> 1. Definitions. +> +> "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. +> +> "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. +> +> "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. +> +> "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. +> +> "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. +> +> "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. +> +> "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). +> +> "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. +> +> "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." +> +> "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. +> +> 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. +> +> 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. +> +> 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +> +> You must give any other recipients of the Work or Derivative Works a copy of this License; and +> +> You must cause any modified files to carry prominent notices stating that You changed the files; and +> +> You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +> +> If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +> +> 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. +> +> 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. +> +> 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. +> +> 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. +> +> 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. +> +> END OF TERMS AND CONDITIONS + +---------------------------------------- + +### unherit@v1.1.3 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### unified@v9.2.1 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### uniq@v1.0.1 + +License: MIT +By: Mikola Lysenko +Repository: + +> The MIT License (MIT) +> +> Copyright (c) 2013 Mikola Lysenko +> +> 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. + +---------------------------------------- + +### unique-string@v3.0.0 + +License: MIT +By: Sindre Sorhus + +> MIT License +> +> Copyright (c) Sindre Sorhus (https://sindresorhus.com) +> +> 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. + +---------------------------------------- + +### unist-util-is@v4.1.0 + +License: MIT +By: Titus Wormer + +> (The MIT license) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### unist-util-remove-position@v2.0.1 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### unist-util-stringify-position@v2.0.3 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### unist-util-visit@v2.0.3 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### unist-util-visit-parents@v3.1.1 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### vfile@v4.2.1 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2015 Titus Wormer +> +> 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. + +---------------------------------------- + +### vfile-location@v3.2.0 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2016 Titus Wormer +> +> 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. + +---------------------------------------- + +### vfile-message@v2.0.4 + +License: MIT +By: Titus Wormer + +> (The MIT License) +> +> Copyright (c) 2017 Titus Wormer +> +> 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. + +---------------------------------------- + +### vnopts@v1.0.2 + +License: MIT +By: Ika + +> MIT License +> +> Copyright (c) Ika (https://github.com/ikatyang) +> +> 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. + +---------------------------------------- + +### wcwidth@v1.0.1 + +License: MIT +By: Tim Oxley +Repository: + +> wcwidth.js: JavaScript Portng of Markus Kuhn's wcwidth() Implementation +> ======================================================================= +> +> Copyright (C) 2012 by Jun Woong. +> +> This package is a JavaScript porting of `wcwidth()` implementation +> [by Markus Kuhn](http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c). +> +> 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. +> +> +> THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +> INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +> FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR +> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +> EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +> PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +> BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +> IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +> POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------- + +### which@v2.0.2 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### wrappy@v1.0.2 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### xtend@v4.0.2 + +License: MIT +By: Raynos + +> The MIT License (MIT) +> Copyright (c) 2012-2014 Raynos. +> +> 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. + +---------------------------------------- + +### yallist@v2.1.2 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### yallist@v4.0.0 + +License: ISC +By: Isaac Z. Schlueter +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + +### yaml@v1.10.2 + +License: ISC +By: Eemeli Aro + +> Copyright 2018 Eemeli Aro +> +> Permission to use, copy, modify, and/or distribute this software for any purpose +> with or without fee is hereby granted, provided that the above copyright notice +> and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +> REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +> FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +> INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +> OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +> TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +> THIS SOFTWARE. + +---------------------------------------- + +### yaml-unist-parser@v1.3.1 + +License: MIT +By: Ika + +> MIT License +> +> Copyright (c) Ika (https://github.com/ikatyang) +> +> 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. + +======================================================================== + +prop-types 15.8.1 +-- +MIT License + +Copyright (c) 2013-present, Facebook, 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. + +======================================================================== + +pubsub-js 1.9.3 +-- +The MIT License (MIT) +===================== + +Copyright © `2010` [Morgan Roderick](https://roderick.dk), [http://roderick.dk/](https://roderick.dk) <[morgan@roderick.dk](mailto:morgan@roderick.dk)> + +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. + +======================================================================== + +punycode 1.3.2 +-- +Copyright Mathias Bynens + +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. + +======================================================================== + +querystring 0.2.0 +-- +Copyright 2012 Irakli Gozalishvili. All rights reserved. +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. + +======================================================================== + +rc-align 2.4.5 +-- +The MIT License (MIT) + +Copyright (c) 2014-present yiminghe + +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. + +======================================================================== + +rc-animate 2.11.1 +-- +The MIT License (MIT) + +Copyright (c) 2014-present yiminghe + +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. + +======================================================================== + +rc-slider 8.6.0 +-- +The MIT License (MIT) +Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ + +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. + +======================================================================== + +rc-tooltip 3.7.3 +-- +The MIT License (MIT) +Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ + +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. + +======================================================================== + +rc-trigger 2.6.5 +-- +The MIT License (MIT) +Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ + +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. + +======================================================================== + +rc-util 4.21.1 +-- +The MIT License (MIT) + +Copyright (c) 2014-present yiminghe +Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ + +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. + +======================================================================== + +re-reselect 4.0.1 +-- +Copyright (c) Andrea Carraro + +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. + +======================================================================== + +re-resizable 6.9.1 +-- +The MIT License (MIT) + +Copyright (c) 2018 @bokuweb + +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. + +======================================================================== + +react 18.1.0 +-- +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +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. + +======================================================================== + +react-contexify 6.0.0 +-- +MIT License + +Copyright (c) 2020 Fadi Khadra + +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. + +======================================================================== + +react-dnd 16.0.0 +-- +The MIT License (MIT) + +Copyright (c) 2016 Dan Abramov + +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. + +======================================================================== + +react-dnd-html5-backend 16.0.0 +-- +The MIT License (MIT) + +Copyright (c) 2015 Dan Abramov + +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. + +======================================================================== + +react-dom 18.1.0 +-- +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +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. + +======================================================================== + +react-fast-compare 3.2.0 +-- +MIT License + +Copyright (c) 2018 Formidable Labs +Copyright (c) 2017 Evgeny Poberezkin + +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. + +======================================================================== + +react-helmet 6.1.0 +-- +Copyright (c) 2015 NFL + +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. + +======================================================================== + +react-highlight-words 0.17.0 +-- +The MIT License (MIT) + +Copyright (c) 2015 Treasure Data + +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. + +======================================================================== + +react-hot-loader 4.12.12 +-- +MIT License + +Copyright (c) 2016 Dan Abramov + +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. + +======================================================================== + +react-input-autosize 2.2.2 +-- +The MIT License (MIT) + +Copyright (c) 2018 Jed Watson + +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. + +======================================================================== + +react-is 16.13.1 +-- +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +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. + +======================================================================== + +react-layout-effect 1.0.5 +-- +MIT License + +Copyright (c) Alec Larson + +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. + +======================================================================== + +react-lifecycles-compat 3.0.4 +-- +MIT License + +Copyright (c) 2013-present, Facebook, 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. + +======================================================================== + +react-onclickoutside 6.9.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +react-popper 2.2.3 +-- +The MIT License (MIT) + +Copyright (c) 2018 React Popper authors + +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. + +======================================================================== + +react-property 1.0.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +react-remove-scroll 2.5.5 +-- +MIT License + +Copyright (c) 2017 Anton Korzunov + +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. + +======================================================================== + +react-remove-scroll-bar 2.3.4 +-- +Copyright Anton Korzunov ; licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +react-router 6.16.0 +-- +MIT License + +Copyright (c) React Training LLC 2015-2019 +Copyright (c) Remix Software Inc. 2020-2021 +Copyright (c) Shopify Inc. 2022-2023 + +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. + +======================================================================== + +react-router-dom 6.16.0 +-- +MIT License + +Copyright (c) React Training LLC 2015-2019 +Copyright (c) Remix Software Inc. 2020-2021 +Copyright (c) Shopify Inc. 2022-2023 + +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. + +======================================================================== + +react-select 3.1.0 +-- +Copyright Jed Watson; licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +react-side-effect 2.1.1 +-- +The MIT License (MIT) + +Copyright (c) 2015 Dan Abramov + +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. + +======================================================================== + +react-style-singleton 2.2.1 +-- +Copyright Anton Korzunov (thekashey@gmail.com); licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +react-timeago 7.1.0 +-- +The MIT License (MIT) + +Copyright (c) 2014 Naman Goel + +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. + +======================================================================== + +react-use-gesture 6.0.2 +-- +Copyright (c) 2018-present Paul Henschel + +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. + +======================================================================== + +react-virtualized-auto-sizer 1.0.2 +-- +Copyright Brian Vaughn (https://github.com/bvaughn/); licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +react-virtuoso 4.6.2 +-- +MIT License + +Copyright (c) 2020 Petyo Ivanov + +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. + +======================================================================== + +react-vtree 2.0.0 +-- +MIT License + +Copyright (c) 2018-present Vladimir Rindevich + +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. + +======================================================================== + +react-window 1.8.7 +-- +The MIT License (MIT) + +Copyright (c) 2018 Brian Vaughn + +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. + +======================================================================== + +readable-stream 3.6.0 +-- +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +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. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +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. +""" + +======================================================================== + +redux 4.2.0 +-- +The MIT License (MIT) + +Copyright (c) 2015-present Dan Abramov + +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. + +======================================================================== + +regexp.prototype.flags 1.5.0 +-- +The MIT License (MIT) + +Copyright (C) 2014 Jordan Harband + +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. + +======================================================================== + +regexpp 2.0.1 +-- +MIT License + +Copyright (c) 2018 Toru Nagashima + +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. + +======================================================================== + +reselect 4.1.7 +-- +The MIT License (MIT) + +Copyright (c) 2015-2018 Reselect Contributors + +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. + +======================================================================== + +resize-observer-polyfill 1.5.0 +-- +The MIT License (MIT) + +Copyright (c) 2016 Denis Rul + +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. + +======================================================================== + +resolve 2.0.0-next.3 +-- +MIT License + +Copyright (c) 2012 James Halliday + +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. + +======================================================================== + +safe-buffer 5.2.1 +-- +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +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. + +======================================================================== + +safe-regex-test 1.0.0 +-- +MIT License + +Copyright (c) 2022 Jordan Harband + +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. + +======================================================================== + +sanitize-html 2.11.0 +-- +Copyright (c) 2013, 2014, 2015 P'unk Avenue LLC + +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. + +======================================================================== + +scheduler 0.22.0 +-- +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +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. + +======================================================================== + +scroll-into-view-if-needed 2.2.28 +-- +MIT License + +Copyright (c) 2017 Stian Didriksen + +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. + +======================================================================== + +semver 7.3.5 +-- +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +set-cookie-parser 2.6.0 +-- +The MIT License (MIT) + +Copyright (c) 2015 Nathan Friedly (http://nfriedly.com/) + +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. + +======================================================================== + +set-immediate-shim 1.0.1 +-- +Copyright Sindre Sorhus; licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +settle-promise 1.0.0 +-- +Copyright Joe Haddad ; licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +sha.js 2.4.11 +-- +Copyright (c) 2013-2018 sha.js contributors + +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. + + +Copyright (c) 1998 - 2009, Paul Johnston & Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of the author nor the names of its contributors may be used to +endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +shallowequal 1.1.0 +-- +MIT License + +Copyright (c) 2017 Alberto Leal (github.com/dashed) + +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. + +======================================================================== + +side-channel 1.0.4 +-- +MIT License + +Copyright (c) 2019 Jordan Harband + +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. + +======================================================================== + +slate 0.94.1 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +slate-history 0.93.0 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +slate-react 0.98.4 +-- +Licensed under MIT (https://spdx.org/licenses/MIT.html) + +======================================================================== + +source-map 0.5.6 +-- +Copyright (c) 2009-2011, Mozilla Foundation and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the names of the Mozilla Foundation nor the names of project + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +source-map-js 1.0.2 +-- +Copyright (c) 2009-2011, Mozilla Foundation and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the names of the Mozilla Foundation nor the names of project + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +stream-browserify 3.0.0 +-- +MIT License + +Copyright (c) James Halliday + +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. + +======================================================================== + +string-hash 1.1.3 +-- +Copyright The Dark Sky Company; licensed under CC0-1.0 (https://spdx.org/licenses/CC0-1.0.html) + +======================================================================== + +string.prototype.matchall 4.0.5 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +string.prototype.trim 1.2.7 +-- +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +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. + +======================================================================== + +string_decoder 1.3.0 +-- +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +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. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +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. +""" + +======================================================================== + +strip-ansi 6.0.0 +-- +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. + +======================================================================== + +style-loader 0.18.2 +-- +Copyright JS Foundation and other contributors + +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. + +======================================================================== + +style-to-object 0.3.0 +-- +The MIT License (MIT) + +Copyright (c) 2017 Menglin "Mark" Xu + +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. + +======================================================================== + +style-vendorizer 2.2.3 +-- +The MIT License (MIT) + +Copyright (c) 2020-2022 Kristóf Poduszló + +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. + +======================================================================== + +stylis 4.0.10 +-- +MIT License + +Copyright (c) 2016-present Sultan Tarimo + +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. + +======================================================================== + +supports-color 5.5.0 +-- +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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. + +======================================================================== + +textextensions 5.14.0 +-- + + +

License

+ +Unless stated otherwise all works are: + + + +and licensed under: + + + +

MIT License

+ +
+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.
+
+ + + +======================================================================== + +tippy.js 6.2.6 +-- +MIT License + +Copyright (c) 2017-present atomiks + +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. + +======================================================================== + +to-fast-properties 2.0.0 +-- +MIT License + +Copyright (c) 2014 Petka Antonov + 2015 Sindre Sorhus + +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. + +======================================================================== + +tslib 2.6.2 +-- +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +type-check 0.3.2 +-- +Copyright (c) George Zahariev + +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. + +======================================================================== + +typescript 4.6.4 +-- +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and + +You must cause any modified files to carry prominent notices stating that You changed the files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +======================================================================== + +uri-js 4.4.1 +-- +Copyright 2011 Gary Court. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY GARY COURT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Gary Court. + +======================================================================== + +url 0.11.0 +-- +The MIT License (MIT) + +Copyright Joyent, Inc. and other Node contributors. + +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. + +======================================================================== + +url-join 4.0.1 +-- +MIT License + +Copyright (c) 2015 José F. Romaniello + +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. + +======================================================================== + +use-callback-ref 1.3.0 +-- +MIT License + +Copyright (c) 2017 Anton Korzunov + +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. + +======================================================================== + +use-context-selector 1.3.9 +-- +The MIT License (MIT) + +Copyright (c) 2019-2021 Daishi Kato + +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. + +======================================================================== + +use-memo-one 1.1.2 +-- +MIT License + +Copyright (c) 2019 Alexander Reardon + +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. + +======================================================================== + +use-sidecar 1.1.2 +-- +MIT License + +Copyright (c) 2017 Anton Korzunov + +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. + +======================================================================== + +use-sync-external-store 1.2.0 +-- +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +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. + +======================================================================== + +util 0.10.4 +-- +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +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. + +======================================================================== + +util-deprecate 1.0.2 +-- +(The MIT License) + +Copyright (c) 2014 Nathan Rajlich + +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. + +======================================================================== + +uuid 8.3.2 +-- +The MIT License (MIT) + +Copyright (c) 2010-2020 Robert Kieffer and other contributors + +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. + +======================================================================== + +validate-npm-package-name 3.0.0 +-- +Copyright (c) 2015, npm, Inc + + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +warning 3.0.0 +-- +BSD License + +For React software + +Copyright (c) 2013-2015, Facebook, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +worktop 0.7.3 +-- +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +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. + +======================================================================== + +xstate 4.23.1 +-- +The MIT License (MIT) + +Copyright (c) 2015 David Khourshid + +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. + +======================================================================== + +yallist 4.0.0 +-- +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +======================================================================== + +yjs 13.6.8 +-- +The MIT License (MIT) + +Copyright (c) 2014 + - Kevin Jahns . + - Chair of Computer Science 5 (Databases & Information Systems), RWTH Aachen University, Germany + +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. + +======================================================================== + +zustand 4.1.5 +-- +MIT License + +Copyright (c) 2019 Paul Henschel + +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. + +======================================================================== + +microsoft/vscode 1.91.1 +-- +MIT License + +Copyright (c) 2015 - present Microsoft Corporation + +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. \ No newline at end of file From 31d2174817569da3facd27fc01a1362465731157 Mon Sep 17 00:00:00 2001 From: Sean Parsons <217400+seanparsons@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:50:42 +0100 Subject: [PATCH 025/272] fix(editor) Reparenting sets the elements to re-render correctly. (#6361) - `applyGridReparent` invokes `setElementsToRerenderCommand`. - `baseFlexReparentToAbsoluteStrategy` invokes `setElementsToRerenderCommand`. --- .../strategies/flex-reparent-to-absolute-strategy.tsx | 5 +++++ .../canvas-strategies/strategies/grid-reparent-strategy.tsx | 2 ++ 2 files changed, 7 insertions(+) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx index b36ceb998322..60941a9865e5 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx @@ -1,6 +1,7 @@ import { canvasPoint } from '../../../../core/shared/math-utils' import type { EditorStatePatch } from '../../../editor/store/editor-state' import { foldAndApplyCommandsInner } from '../../commands/commands' +import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' import { updateFunctionCommand } from '../../commands/update-function-command' import { ParentBounds } from '../../controls/parent-bounds' import { ParentOutlines } from '../../controls/parent-outlines' @@ -104,6 +105,10 @@ export function baseFlexReparentToAbsoluteStrategy( [ ...placeholderCommands.commands, ...escapeHatchCommands, + setElementsToRerenderCommand([ + newParent.intendedParentPath, + ...filteredSelectedElements, + ]), updateFunctionCommand( 'always', (editorState, commandLifecycle): Array => { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx index 6af2b2f095a9..24bb761a39f2 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx @@ -49,6 +49,7 @@ import type { ReparentTarget } from './reparent-helpers/reparent-strategy-helper import { getReparentOutcome, pathToReparent } from './reparent-utils' import { flattenSelection } from './shared-move-strategies-helpers' import type { GridCellCoordinates } from './grid-cell-bounds' +import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' export function gridReparentStrategy( reparentTarget: ReparentTarget, @@ -258,6 +259,7 @@ export function applyGridReparent( updateSelectedViews('always', newPaths), setCursorCommand(CSSCursor.Reparent), showGridControls('mid-interaction', reparentTarget.newParent.intendedParentPath), + setElementsToRerenderCommand(elementsToRerender), ], { elementsToRerender: elementsToRerender, From c7d1524646159f347efb45135054a26a9c09c4b8 Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Mon, 16 Sep 2024 16:42:15 +0300 Subject: [PATCH 026/272] feat(grid): advanced grid controls (#6354) This PR adds advanced grid controls: * add inspector modal for advanced controls * justify + Align items - as chain controls * justify + Align content - as dropdowns * adding the ability to unset by clicking on the same button Reviewers: the main logic is in [`editor/src/components/inspector/controls/advanced-grid-modal.tsx`](https://github.com/concrete-utopia/utopia/pull/6354/files#diff-0c658c76e054ebe3b417768607e4f5b50552cef5825e33d0cf694a966a04bc36) **Manual Tests:** I hereby swear that: - [X] I opened a hydrogen project and it loaded - [X] I could navigate to various routes in Preview mode --- .../components/canvas/design-panel-root.tsx | 173 ++++++----- editor/src/components/canvas/dom-walker.ts | 2 +- .../store-deep-equality-instances-3.spec.ts | 14 +- .../add-remove-layout-system-control.tsx | 136 ++++++--- .../components/inspector/common/css-utils.ts | 13 +- .../controls/advanced-grid-modal.tsx | 280 ++++++++++++++++++ .../components/inspector/controls/control.ts | 1 + .../controls/option-chain-control.tsx | 6 +- .../flex-container-controls.tsx | 4 +- .../package-manager/utopia-api-typings.ts | 4 +- editor/src/core/layout/layout-helpers-new.ts | 1 + editor/src/core/shared/element-template.ts | 4 +- editor/src/uuiui/radix-components.tsx | 11 +- editor/src/uuiui/styles/theme/utopia-theme.ts | 3 +- utopia-api/src/layout/flex.ts | 2 +- utopia-api/src/layout/layout.ts | 2 +- 16 files changed, 520 insertions(+), 136 deletions(-) create mode 100644 editor/src/components/inspector/controls/advanced-grid-modal.tsx diff --git a/editor/src/components/canvas/design-panel-root.tsx b/editor/src/components/canvas/design-panel-root.tsx index cfd85994fbef..5852f12f0e23 100644 --- a/editor/src/components/canvas/design-panel-root.tsx +++ b/editor/src/components/canvas/design-panel-root.tsx @@ -171,95 +171,116 @@ export const RightPane = React.memo((props) => { const allowedToEdit = useAllowedToEditProject() + const designPanelRef = React.useRef(null) + if (!isRightMenuExpanded) { return null } + const panelWidth = designPanelRef.current?.offsetWidth ?? 0 + const panelHeight = designPanelRef.current?.offsetHeight ?? 0 + return ( - - - + - - {when( - allowedToEdit, - <> - {when( - IS_TEST_ENVIRONMENT, - , - )} - , - )} - {when( - canComment, + + , - )} - - {when( - isFeatureEnabled('Roll Your Own'), + label={'Inspector'} + selected={selectedTab === RightMenuTab.Inspector} + onClick={onClickInspectorTab} + /> + {when( + allowedToEdit, + <> + {when( + IS_TEST_ENVIRONMENT, + , + )} + , + )} + {when( + canComment, + , + )} , - )} - - - {when(selectedTab === RightMenuTab.Inspector, )} - {when(selectedTab === RightMenuTab.Settings, )} - {when(selectedTab === RightMenuTab.Comments, )} - {when(selectedTab === RightMenuTab.RollYourOwn, )} - - - + label={'Settings'} + selected={selectedTab === RightMenuTab.Settings} + onClick={onClickSettingsTab} + /> + {when( + isFeatureEnabled('Roll Your Own'), + , + )} + + + {when(selectedTab === RightMenuTab.Inspector, )} + {when(selectedTab === RightMenuTab.Settings, )} + {when(selectedTab === RightMenuTab.Comments, )} + {when(selectedTab === RightMenuTab.RollYourOwn, )} + + + + ) }) +// a context provider for the design panel measurements +export const DesignPanelContext = React.createContext<{ + panelWidth: number + panelHeight: number +}>({ + panelWidth: 0, + panelHeight: 0, +}) + +export const useDesignPanelContext = () => { + return React.useContext(DesignPanelContext) +} + interface CodeEditorPaneProps { panelData: StoredPanel small: boolean diff --git a/editor/src/components/canvas/dom-walker.ts b/editor/src/components/canvas/dom-walker.ts index 9a0eae756546..0051199c8df8 100644 --- a/editor/src/components/canvas/dom-walker.ts +++ b/editor/src/components/canvas/dom-walker.ts @@ -681,7 +681,7 @@ function getSpecialMeasurements( const parentTextDirection = eitherToMaybe(parseDirection(parentElementStyle?.direction, null)) const justifyContent = getFlexJustifyContent(elementStyle.justifyContent) - const alignContent = getFlexAlignment(elementStyle.alignContent) + const alignContent = getFlexJustifyContent(elementStyle.alignContent) const alignItems = getFlexAlignment(elementStyle.alignItems) const margin = applicative4Either( diff --git a/editor/src/components/editor/store/store-deep-equality-instances-3.spec.ts b/editor/src/components/editor/store/store-deep-equality-instances-3.spec.ts index 808524bc5a1d..30b51566aba5 100644 --- a/editor/src/components/editor/store/store-deep-equality-instances-3.spec.ts +++ b/editor/src/components/editor/store/store-deep-equality-instances-3.spec.ts @@ -265,7 +265,7 @@ describe('SpecialSizeMeasurementsKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', - alignContent: 'auto', + alignContent: null, alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -384,7 +384,7 @@ describe('SpecialSizeMeasurementsKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', - alignContent: 'auto', + alignContent: null, alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -558,7 +558,7 @@ describe('ElementInstanceMetadataKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', - alignContent: 'auto', + alignContent: null, alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -709,7 +709,7 @@ describe('ElementInstanceMetadataKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', - alignContent: 'auto', + alignContent: null, alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -885,7 +885,7 @@ describe('ElementInstanceMetadataMapKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', - alignContent: 'auto', + alignContent: null, alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -1038,7 +1038,7 @@ describe('ElementInstanceMetadataMapKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', - alignContent: 'auto', + alignContent: null, alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, @@ -1191,7 +1191,7 @@ describe('ElementInstanceMetadataMapKeepDeepEquality', () => { gap: 11, flexDirection: 'column', justifyContent: 'center', - alignContent: 'auto', + alignContent: null, alignItems: 'auto', htmlElementName: 'div', renderedChildrenCount: 10, diff --git a/editor/src/components/inspector/add-remove-layout-system-control.tsx b/editor/src/components/inspector/add-remove-layout-system-control.tsx index 26499eb80cef..9ddf99588922 100644 --- a/editor/src/components/inspector/add-remove-layout-system-control.tsx +++ b/editor/src/components/inspector/add-remove-layout-system-control.tsx @@ -15,10 +15,16 @@ import { executeFirstApplicableStrategy } from './inspector-strategies/inspector import { useDispatch } from '../editor/store/dispatch-context' import { NO_OP, assertNever } from '../../core/shared/utils' import type { DropdownMenuItem } from '../../uuiui/radix-components' -import { DropdownMenu, regularDropdownMenuItem } from '../../uuiui/radix-components' +import { + DropdownMenu, + regularDropdownMenuItem, + separatorDropdownMenuItem, +} from '../../uuiui/radix-components' import { stripNulls } from '../../core/shared/array-utils' import { layoutSystemSelector } from './flex-section' -import { optionalMap } from '../../core/shared/optional-utils' +import { AdvancedGridModal } from './controls/advanced-grid-modal' +import { when } from '../../utils/react-conditionals' +import { useDesignPanelContext } from '../canvas/design-panel-root' export const AddRemoveLayoutSystemControlTestId = (): string => 'AddRemoveLayoutSystemControlTestId' export const AddFlexLayoutOptionId = 'add-flex-layout' @@ -27,7 +33,19 @@ export const RemoveLayoutSystemOptionId = 'remove-layout-system' interface AddRemoveLayoutSystemControlProps {} +// adjusting the modal position to have some space from the left edge of the design panel +const X_OFFSET = 20 +const Y_OFFSET = 20 + export const AddRemoveLayoutSystemControl = React.memo(() => { + const [popupOpen, setPopupOpen] = React.useState(false) + const closePopup = React.useCallback(() => { + setPopupOpen(false) + }, []) + const openPopup = React.useCallback(() => { + setPopupOpen(true) + }, []) + const layoutSystem = useEditorState( Substores.metadata, layoutSystemSelector, @@ -87,41 +105,71 @@ export const AddRemoveLayoutSystemControl = React.memo ( - - {layoutSystem == null ? : } + const addLayoutSystemOpenerButton = React.useCallback(() => { + return ( + + {layoutSystem == null ? ( + + ) : ( + + )} - ), - [layoutSystem], - ) + ) + }, [layoutSystem, popupOpen]) - const addLayoutSystemMenuDropdownItems = React.useMemo( - (): DropdownMenuItem[] => - stripNulls([ - regularDropdownMenuItem({ - id: AddFlexLayoutOptionId, - label: 'Convert to Flex', - onSelect: addFlexLayoutSystem, - }), - regularDropdownMenuItem({ - id: AddGridLayoutOptionId, - label: 'Convert to Grid', - onSelect: addGridLayoutSystem, - }), - optionalMap( - () => - regularDropdownMenuItem({ - id: RemoveLayoutSystemOptionId, - label: 'Remove layout system', - onSelect: removeLayoutSystem, - danger: true, - }), - layoutSystem, - ), - ]), - [addFlexLayoutSystem, addGridLayoutSystem, layoutSystem, removeLayoutSystem], - ) + const addLayoutSystemMenuDropdownItems = React.useMemo((): DropdownMenuItem[] => { + const gridItems: DropdownMenuItem[] = [ + regularDropdownMenuItem({ + id: 'more-settings', + label: 'Advanced', + onSelect: openPopup, + }), + regularDropdownMenuItem({ + id: AddFlexLayoutOptionId, + label: 'Convert to Flex', + onSelect: addFlexLayoutSystem, + }), + separatorDropdownMenuItem('dropdown-separator'), + regularDropdownMenuItem({ + id: RemoveLayoutSystemOptionId, + label: 'Remove Grid', + onSelect: removeLayoutSystem, + danger: true, + }), + ] + + const flexItems: DropdownMenuItem[] = [ + regularDropdownMenuItem({ + id: AddGridLayoutOptionId, + label: 'Convert to Grid', + onSelect: addGridLayoutSystem, + }), + separatorDropdownMenuItem('dropdown-separator'), + regularDropdownMenuItem({ + id: RemoveLayoutSystemOptionId, + label: 'Remove Flex', + onSelect: removeLayoutSystem, + danger: true, + }), + ] + + const noLayoutItems: DropdownMenuItem[] = [ + regularDropdownMenuItem({ + id: AddFlexLayoutOptionId, + label: 'Flex', + onSelect: addFlexLayoutSystem, + }), + regularDropdownMenuItem({ + id: AddGridLayoutOptionId, + label: 'Grid', + onSelect: addGridLayoutSystem, + }), + ] + + return stripNulls( + layoutSystem === 'grid' ? gridItems : layoutSystem === 'flex' ? flexItems : noLayoutItems, + ) + }, [addFlexLayoutSystem, addGridLayoutSystem, layoutSystem, removeLayoutSystem, openPopup]) const label = () => { switch (layoutSystem) { @@ -136,6 +184,13 @@ export const AddRemoveLayoutSystemControl = React.memo { + const x = -1 * (panelWidth + X_OFFSET) + const y = -1 * Y_OFFSET + return { x: x, y: y } + }, [panelWidth]) + return ( {label()} + {when( + popupOpen, + , + )}
void + modalOffset: { + x: number + y: number + } +} + +export const AdvancedGridModal = React.memo((props: AdvancedGridModalProps) => { + const modalOffset = props.modalOffset ?? { x: 0, y: 0 } + const [dropdownOpen, setDropdownOpen] = React.useState({ + justifyContent: false, + alignContent: false, + }) + const toggleJustifyContentDropdown = React.useCallback((state: boolean) => { + setDropdownOpen((prev) => ({ ...prev, justifyContent: state })) + }, []) + const toggleAlignContentDropdown = React.useCallback((state: boolean) => { + setDropdownOpen((prev) => ({ ...prev, alignContent: state })) + }, []) + const closePopup = React.useCallback(() => { + if (!dropdownOpen.justifyContent && !dropdownOpen.alignContent) { + props.closePopup() + } + }, [dropdownOpen, props]) + + const alignItemsLayoutInfo = useInspectorLayoutInfo('alignItems') + const justifyItemsLayoutInfo = useInspectorLayoutInfo('justifyItems') + const alignContentLayoutInfo = useInspectorLayoutInfo('alignContent') + const justifyContentLayoutInfo = useInspectorLayoutInfo('justifyContent') + + const currentJustifyContentValue = React.useMemo( + () => getLayoutInfoValue(justifyContentLayoutInfo), + [justifyContentLayoutInfo], + ) + + const currentAlignContentValue = React.useMemo( + () => getLayoutInfoValue(alignContentLayoutInfo), + [alignContentLayoutInfo], + ) + + const currentJustifyItemsValue = React.useMemo( + () => getValueOrUnset(justifyItemsLayoutInfo), + [justifyItemsLayoutInfo], + ) + + const currentAlignItemsValue = React.useMemo( + () => getValueOrUnset(alignItemsLayoutInfo), + [alignItemsLayoutInfo], + ) + + const contentOptions = [ + unsetSelectOption, + separatorRadixSelectOption(), + ...Object.values(FlexJustifyContent).map(selectOption), + ] + + const onSubmitJustifyContent = React.useCallback( + (value: string) => { + if (value === 'unset') { + justifyContentLayoutInfo.onUnsetValues() + } else { + justifyContentLayoutInfo.onSubmitValue(value as FlexJustifyContent) + } + }, + [justifyContentLayoutInfo], + ) + + const onSubmitAlignContent = React.useCallback( + (value: string) => { + if (value === 'unset') { + alignContentLayoutInfo.onUnsetValues() + } else { + alignContentLayoutInfo.onSubmitValue(value as FlexJustifyContent) + } + }, + [alignContentLayoutInfo], + ) + + const advancedGridModal = ( + + + +

+ Grid Settings +

+ + + × + +
+ + Items + + + + Justify + + + + Align + + + + Entire Grid + + + Justify + + + + Align + + +
+
+ ) + + return ( +
+ {props.popupOpen ? advancedGridModal : null} +
+ ) +}) + +AdvancedGridModal.displayName = 'AdvancedGridModal' + +const itemsOptions = (alignOrJustify: 'align' | 'justify') => + [ + { + value: 'flex-start', + tooltip: PrettyLabel[alignOrJustify === 'justify' ? 'left' : 'top'], + icon: { + category: `inspector-element`, + type: `${alignOrJustify}Items-start`, + color: 'secondary', + width: 16, + height: 16, + }, + }, + { + value: 'center', + tooltip: 'Center', + icon: { + category: `inspector-element`, + type: `${alignOrJustify}Items-center`, + color: 'secondary', + width: 16, + height: 16, + }, + }, + { + value: 'flex-end', + tooltip: PrettyLabel[alignOrJustify === 'justify' ? 'right' : 'bottom'], + icon: { + category: `inspector-element`, + type: `${alignOrJustify}Items-end`, + color: 'secondary', + width: 16, + height: 16, + }, + }, + { + value: 'stretch', + tooltip: 'Stretch', + icon: { + category: `inspector-element`, + type: `${alignOrJustify}Items-stretch`, + color: 'secondary', + width: 16, + height: 16, + }, + }, + ] as Array> + +const justifyItemsOptions = itemsOptions('justify') +const alignItemsOptions = itemsOptions('align') +const rowVariant: GridRowVariant = '|--67px--|<--------1fr-------->' + +function selectOption(value: FlexJustifyContent) { + return regularRadixSelectOption({ + label: value.replace('-', ' '), + value: value, + placeholder: true, + }) +} + +const unsetSelectOption = regularRadixSelectOption({ + label: 'unset', + value: 'unset', + placeholder: true, +}) + +const isUnset = (control: InspectorInfo): boolean => + control.controlStatus === 'detected' || control.controlStatus === 'unset' + +const getLayoutInfoValue = (control: InspectorInfo) => + isUnset(control) ? unsetSelectOption : optionalMap(selectOption, control.value) ?? undefined + +const getValueOrUnset = (control: InspectorInfo): string => + isUnset(control) ? 'unset' : control.value diff --git a/editor/src/components/inspector/controls/control.ts b/editor/src/components/inspector/controls/control.ts index 316cebc6cd34..7d02aca9defe 100644 --- a/editor/src/components/inspector/controls/control.ts +++ b/editor/src/components/inspector/controls/control.ts @@ -32,6 +32,7 @@ export interface DEPRECATEDControlProps { readOnly?: boolean selected?: boolean options?: ReadonlyArray | ReadonlyArray> + onUnsetValues?: () => void DEPRECATED_controlOptions?: | DEPRECATEDGenericControlOptions | DEPRECATEDOptionControlOptions diff --git a/editor/src/components/inspector/controls/option-chain-control.tsx b/editor/src/components/inspector/controls/option-chain-control.tsx index b65cb235a863..cdcf1b84b9fa 100644 --- a/editor/src/components/inspector/controls/option-chain-control.tsx +++ b/editor/src/components/inspector/controls/option-chain-control.tsx @@ -92,9 +92,11 @@ export const OptionChainControl: React.FunctionComponent< }} value={props.value === option.value} // eslint-disable-next-line react/jsx-no-bind - onSubmitValue={(value: boolean) => { - if (value || option.forceCallOnSubmitValue) { + onSubmitValue={(isChecked: boolean) => { + if (isChecked || option.forceCallOnSubmitValue) { props.onSubmitValue(option.value) + } else { + props.onUnsetValues?.() } }} /> diff --git a/editor/src/components/inspector/sections/layout-section/flex-container-subsection/flex-container-controls.tsx b/editor/src/components/inspector/sections/layout-section/flex-container-subsection/flex-container-controls.tsx index 12d47839dd42..ed42986db729 100644 --- a/editor/src/components/inspector/sections/layout-section/flex-container-subsection/flex-container-controls.tsx +++ b/editor/src/components/inspector/sections/layout-section/flex-container-subsection/flex-container-controls.tsx @@ -58,7 +58,7 @@ type prettyLabel = | 'Horizontal' | 'Vertical' -const PrettyLabel: { [K in uglyLabel]: prettyLabel } = { +export const PrettyLabel: { [K in uglyLabel]: prettyLabel } = { left: 'Left', center: 'Center', right: 'Right', @@ -71,7 +71,7 @@ const PrettyLabel: { [K in uglyLabel]: prettyLabel } = { vertical: 'Vertical', } -interface FlexFieldControlProps { +export interface FlexFieldControlProps { value: T controlStatus: ControlStatus controlStyles: ControlStyles diff --git a/editor/src/core/es-modules/package-manager/utopia-api-typings.ts b/editor/src/core/es-modules/package-manager/utopia-api-typings.ts index 0ff2781b6c41..f8e666fc8fdf 100644 --- a/editor/src/core/es-modules/package-manager/utopia-api-typings.ts +++ b/editor/src/core/es-modules/package-manager/utopia-api-typings.ts @@ -106,7 +106,7 @@ declare module 'utopia-api/layout/flex' { export function getMarginProps(props: FlexElementProps, parentProps: FlexParentProps, index: number, siblingsCount: number): Partial; export interface FlexParentProps { flexDirection?: FlexDirection; - alignContent?: FlexAlignment; + alignContent?: FlexJustifyContent; alignItems?: FlexAlignment; justifyContent?: FlexJustifyContent; flexWrap?: FlexWrap; @@ -253,7 +253,7 @@ declare module 'utopia-api/layout/layout' { flexGrow?: number; flexShrink?: number; flexDirection?: FlexDirection; - alignContent?: FlexAlignment; + alignContent?: FlexJustifyContent; alignItems?: FlexAlignment; justifyContent?: FlexJustifyContent; wrap?: FlexWrap; diff --git a/editor/src/core/layout/layout-helpers-new.ts b/editor/src/core/layout/layout-helpers-new.ts index de27ec709569..c3329258a2e6 100644 --- a/editor/src/core/layout/layout-helpers-new.ts +++ b/editor/src/core/layout/layout-helpers-new.ts @@ -77,6 +77,7 @@ export type StyleLayoutProp = | 'flexShrink' | 'gap' | 'alignItems' + | 'justifyItems' | 'alignContent' | 'justifyContent' | 'padding' diff --git a/editor/src/core/shared/element-template.ts b/editor/src/core/shared/element-template.ts index e26e1e1496e1..63442cce8e72 100644 --- a/editor/src/core/shared/element-template.ts +++ b/editor/src/core/shared/element-template.ts @@ -2810,7 +2810,7 @@ export interface SpecialSizeMeasurements { gap: number | null flexDirection: FlexDirection | null justifyContent: FlexJustifyContent | null - alignContent: FlexAlignment | null + alignContent: FlexJustifyContent | null alignItems: FlexAlignment | null htmlElementName: string renderedChildrenCount: number @@ -2860,7 +2860,7 @@ export function specialSizeMeasurements( gap: number | null, flexDirection: FlexDirection | null, justifyContent: FlexJustifyContent | null, - alignContent: FlexAlignment | null, + alignContent: FlexJustifyContent | null, alignItems: FlexAlignment | null, htmlElementName: string, renderedChildrenCount: number, diff --git a/editor/src/uuiui/radix-components.tsx b/editor/src/uuiui/radix-components.tsx index b0baf300de1b..1e5e446bd83d 100644 --- a/editor/src/uuiui/radix-components.tsx +++ b/editor/src/uuiui/radix-components.tsx @@ -241,14 +241,21 @@ export const RadixSelect = React.memo( value: RegularRadixSelectOption | null options: RadixSelectOption[] style?: CSSProperties + contentStyle?: CSSProperties onValueChange?: (value: string) => void + contentClassName?: string + onOpenChange?: (open: boolean) => void }) => { const stopPropagation = React.useCallback((e: React.KeyboardEvent) => { e.stopPropagation() }, []) return ( - + diff --git a/editor/src/uuiui/styles/theme/utopia-theme.ts b/editor/src/uuiui/styles/theme/utopia-theme.ts index 69b700155941..e89bafd1aad6 100644 --- a/editor/src/uuiui/styles/theme/utopia-theme.ts +++ b/editor/src/uuiui/styles/theme/utopia-theme.ts @@ -162,8 +162,7 @@ const fontStyles = { const popup: React.CSSProperties = { background: colorTheme.neutralBackground.value, boxShadow: shadowStyles.high.boxShadow, - paddingTop: 4, - paddingBottom: 4, + padding: '4px 0', borderRadius: 4, } diff --git a/utopia-api/src/layout/flex.ts b/utopia-api/src/layout/flex.ts index 2fd2d1504956..23a2a0df37a6 100644 --- a/utopia-api/src/layout/flex.ts +++ b/utopia-api/src/layout/flex.ts @@ -169,7 +169,7 @@ export function getMarginProps( export interface FlexParentProps { flexDirection?: FlexDirection - alignContent?: FlexAlignment + alignContent?: FlexJustifyContent alignItems?: FlexAlignment justifyContent?: FlexJustifyContent flexWrap?: FlexWrap diff --git a/utopia-api/src/layout/layout.ts b/utopia-api/src/layout/layout.ts index a543f34a1632..42dffb17abc6 100644 --- a/utopia-api/src/layout/layout.ts +++ b/utopia-api/src/layout/layout.ts @@ -41,7 +41,7 @@ export interface LayoutBaseProps { flexShrink?: number // flex parent flexDirection?: FlexDirection - alignContent?: FlexAlignment + alignContent?: FlexJustifyContent alignItems?: FlexAlignment justifyContent?: FlexJustifyContent wrap?: FlexWrap From 043570d3d3a8d3f4409750a5d8f564a33f0f12ce Mon Sep 17 00:00:00 2001 From: Balazs Bajorics <2226774+balazsbajorics@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:13:47 +0200 Subject: [PATCH 027/272] Fix slider number control performance (#6374) **Problem:** When using the slider in the SliderNumber controls (such as the PromiseCard's BorderRadius in my screenshot) in the component inspector section, the displayed number updates unbearably slowly. image The reason is that the slider and number are actually two separate controls, and the number control only gets its state updated in low priority mode once the interaction is finished. **Fix:** Use a shared local state for the value we immediately set while using the slider. **Commit Details:** - Use `usePropControlledStateV2` as shared local state for the transient updates **Bonus mini fixes:** - wrap RemixNavigationBar in LowPriorityState - speeding up Tooltip / tippy **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- .../src/components/editor/canvas-toolbar.tsx | 5 +- .../property-control-controls.tsx | 31 +++- ...performance-regression-tests.spec.tsx.snap | 160 +++++++++--------- editor/src/uuiui/tooltip.tsx | 102 +++++------ 4 files changed, 154 insertions(+), 144 deletions(-) diff --git a/editor/src/components/editor/canvas-toolbar.tsx b/editor/src/components/editor/canvas-toolbar.tsx index d7c42dcc9670..9ebb819f7aa5 100644 --- a/editor/src/components/editor/canvas-toolbar.tsx +++ b/editor/src/components/editor/canvas-toolbar.tsx @@ -72,6 +72,7 @@ import { keyToString, shortcutDetailsWithDefaults, } from './shortcut-definitions' +import { LowPriorityStoreProvider } from './store/store-context-providers' export const InsertMenuButtonTestId = 'insert-menu-button' export const InsertOrEditTextButtonTestId = 'insert-or-edit-text-button' @@ -579,7 +580,9 @@ export const CanvasToolbar = React.memo(() => { ) : null} {/* Live Mode */} - {showRemixNavBar ? wrapInSubmenu() : null} + + {showRemixNavBar ? wrapInSubmenu() : null} + ) }) diff --git a/editor/src/components/inspector/sections/component-section/property-control-controls.tsx b/editor/src/components/inspector/sections/component-section/property-control-controls.tsx index 2925f9ba8ee3..3012824768e8 100644 --- a/editor/src/components/inspector/sections/component-section/property-control-controls.tsx +++ b/editor/src/components/inspector/sections/component-section/property-control-controls.tsx @@ -1,5 +1,6 @@ import fastDeepEquals from 'fast-deep-equal' import React from 'react' +import ReactDOM from 'react-dom' import { MetadataUtils } from '../../../../core/model/element-metadata-utils' import { isRight } from '../../../../core/shared/either' import { isJSXElement } from '../../../../core/shared/element-template' @@ -69,6 +70,7 @@ import type { DEPRECATEDSliderControlOptions } from '../../controls/slider-contr import { StringControl } from '../../controls/string-control' import { UIGridRow } from '../../widgets/ui-grid-row' import { HtmlPreview, ImagePreview } from './property-content-preview' +import { usePropControlledStateV2 } from '../../common/inspector-utils' export interface ControlForPropProps { propPath: PropertyPath @@ -492,9 +494,26 @@ const NumberWithSliderControl = React.memo( }, ) => { const { propName, propMetadata, controlDescription } = props + const { onTransientSubmitValue, onSubmitValue } = propMetadata const controlId = `${propName}-slider-property-control` - const value = getValueOrUndefinedFromPropMetadata(propMetadata) ?? 0 + const valueComingFromProps = getValueOrUndefinedFromPropMetadata(propMetadata) ?? 0 + + const [valueToShow, setValueToShow] = usePropControlledStateV2(valueComingFromProps) + + const onChangeValue = React.useCallback( + (value: any, transient: boolean = false) => { + ReactDOM.flushSync(() => { + setValueToShow(value) + }) + if (transient) { + onTransientSubmitValue(value) + } else { + onSubmitValue(value, transient) + } + }, + [setValueToShow, onTransientSubmitValue, onSubmitValue], + ) return ( |--45px--|'}> @@ -502,10 +521,10 @@ const NumberWithSliderControl = React.memo( key={`${controlId}-slider`} id={`${controlId}-slider`} testId={`${controlId}-slider`} - value={value} - onTransientSubmitValue={propMetadata.onTransientSubmitValue} - onForcedSubmitValue={propMetadata.onSubmitValue} - onSubmitValue={propMetadata.onSubmitValue} + value={valueToShow} + onTransientSubmitValue={onChangeValue} + onForcedSubmitValue={onChangeValue} + onSubmitValue={onChangeValue} controlStatus={propMetadata.controlStatus} controlStyles={propMetadata.controlStyles} DEPRECATED_controlOptions={props.controlOptions} @@ -514,7 +533,7 @@ const NumberWithSliderControl = React.memo( id={`${controlId}-number`} testId={`${controlId}-number`} key={`${controlId}-number`} - value={value} + value={valueToShow} onTransientSubmitValue={propMetadata.onTransientSubmitValue} onForcedSubmitValue={propMetadata.onSubmitValue} onSubmitValue={propMetadata.onSubmitValue} diff --git a/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap b/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap index 0bd2ca37513e..911b3ef6a132 100644 --- a/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap +++ b/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap @@ -183,10 +183,10 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/Symbol(react.memo)(Icon)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div:data-testid='plus-button-onMouseDown'", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)", - "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/div/div/Icon/img", "/div/div/ControlForProp/Symbol(react.memo)()", @@ -206,11 +206,11 @@ Array [ "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/span", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedClass(Tooltip)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedFunctionComponent(Tooltip)", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", - "/Symbol(react.forward_ref)()/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)()/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))/div", @@ -232,7 +232,7 @@ Array [ "/Symbol(react.forward_ref)(Styled(div))/div/Symbol(react.forward_ref)(Styled(div))/div", "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())", "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/Symbol(react.forward_ref)(Styled(div)):data-testid='editor-fix-problems-button'", - "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/Symbol(react.forward_ref)(Styled(div)):data-testid='editor-contract-dropdown'", "/div/EditorContractDropdown/Symbol(react.forward_ref)(Styled(div))/div:data-testid='editor-contract-dropdown'", "/div/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", @@ -379,7 +379,7 @@ Array [ "/div/div//Symbol(react.memo)()", "/div/div//Symbol(react.memo)()", "/div///Symbol(react.forward_ref)(Styled(div)):data-testid='radius-cycle-mode'", - "/div///UtopiaSpiedClass(Tooltip)", + "/div///UtopiaSpiedFunctionComponent(Tooltip)", "/div///Symbol(react.memo)()", "/div///div", "//div//Symbol(react.memo)(NumberInput)", @@ -395,9 +395,9 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.memo)(Symbol(react.forward_ref)())", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(Styled(input)):data-testid='radius-one'", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(Styled(input))/input:data-testid='radius-one'", - "//div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "//div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(Styled(div))/div:data-testid='radius-cycle-mode'", "/div/div//Symbol(react.memo)()", @@ -462,10 +462,10 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/Symbol(react.memo)(Icon)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div:data-testid='plus-button-onMouseDown'", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)", - "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/div/div/ControlForProp/Symbol(react.memo)()", "/div/div/ControlForProp/Symbol(react.memo)()", @@ -484,11 +484,11 @@ Array [ "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/span", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedClass(Tooltip)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedFunctionComponent(Tooltip)", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", - "/Symbol(react.forward_ref)()/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)()/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))/div", @@ -596,7 +596,7 @@ Array [ "/TextSubsection/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/TextSubsection/div//Symbol(react.forward_ref)(Styled(div))", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/Symbol(react.memo)()", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", @@ -831,7 +831,7 @@ Array [ "/Symbol(react.forward_ref)(Styled(div))/div/Symbol(react.forward_ref)(Styled(div))/div", "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())", "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/Symbol(react.forward_ref)(Styled(div)):data-testid='editor-fix-problems-button'", - "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(Styled(div))/div/EditorContractDropdown/Symbol(react.forward_ref)(Styled(div)):data-testid='editor-contract-dropdown'", "/div/EditorContractDropdown/Symbol(react.forward_ref)(Styled(div))/div:data-testid='editor-contract-dropdown'", "/div/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", @@ -978,7 +978,7 @@ Array [ "/div/div//Symbol(react.memo)()", "/div/div//Symbol(react.memo)()", "/div///Symbol(react.forward_ref)(Styled(div)):data-testid='radius-cycle-mode'", - "/div///UtopiaSpiedClass(Tooltip)", + "/div///UtopiaSpiedFunctionComponent(Tooltip)", "/div///Symbol(react.memo)()", "/div///div", "//div//Symbol(react.memo)(NumberInput)", @@ -994,9 +994,9 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.memo)(Symbol(react.forward_ref)())", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(Styled(input)):data-testid='radius-one'", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(Styled(input))/input:data-testid='radius-one'", - "//div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "//div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(Styled(div))/div:data-testid='radius-cycle-mode'", "/div/div//Symbol(react.memo)()", @@ -1137,7 +1137,7 @@ Array [ "/TextSubsection/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/TextSubsection/div//Symbol(react.forward_ref)(Styled(div))", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/Symbol(react.memo)()", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", @@ -1268,16 +1268,16 @@ Array [ "////UtopiaSpiedExoticType(Symbol(react.provider))", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/UtopiaSpiedFunctionComponent()/UtopiaSpiedExoticType(Symbol(react.provider))", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/UtopiaSpiedFunctionComponent(MenuProvider)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/UtopiaSpiedFunctionComponent(ContextMenu)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/Symbol(react.forward_ref)(EmotionCssPropInternal)", "//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(MenuProvider)/div", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedClass(StateManager)", @@ -1412,7 +1412,7 @@ Array [ "/TextSubsection/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/TextSubsection/div//Symbol(react.forward_ref)(Styled(div))", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/Symbol(react.memo)()", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", @@ -1602,10 +1602,10 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/Symbol(react.memo)(Icon)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div:data-testid='plus-button-onMouseDown'", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)", - "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/div/div/ControlForProp/Symbol(react.memo)()", "/div/div/ControlForProp/Symbol(react.memo)()", @@ -1624,11 +1624,11 @@ Array [ "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/span", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedClass(Tooltip)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedFunctionComponent(Tooltip)", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", - "/Symbol(react.forward_ref)()/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)()/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))/div", @@ -1735,16 +1735,16 @@ Array [ "/UtopiaSpiedFunctionComponent(DropdownIndicator)/UtopiaSpiedFunctionComponent(DropdownIndicator)/Symbol(react.forward_ref)(render)/UtopiaSpiedExoticType(Symbol(react.context))", "/Symbol(react.forward_ref)(render)/UtopiaSpiedExoticType(Symbol(react.context))/Symbol(react.context)/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/UtopiaSpiedFunctionComponent(MenuProvider)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/UtopiaSpiedFunctionComponent(ContextMenu)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/Symbol(react.forward_ref)(EmotionCssPropInternal)", "//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(MenuProvider)/div", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedClass(StateManager)", @@ -1812,10 +1812,10 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/Symbol(react.memo)(Icon)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div:data-testid='plus-button-onMouseDown'", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)", - "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/div/div/ControlForProp/Symbol(react.memo)()", "/div/div/ControlForProp/Symbol(react.memo)()", @@ -1834,11 +1834,11 @@ Array [ "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/span", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedClass(Tooltip)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedFunctionComponent(Tooltip)", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", - "/Symbol(react.forward_ref)()/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)()/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))/div", @@ -1929,7 +1929,7 @@ Array [ "/TextSubsection/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/TextSubsection/div//Symbol(react.forward_ref)(Styled(div))", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/Symbol(react.memo)()", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", @@ -2041,10 +2041,10 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/Symbol(react.memo)(Icon)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div:data-testid='plus-button-onMouseDown'", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)", - "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/div/div/ControlForProp/Symbol(react.memo)()", "/div/div/ControlForProp/Symbol(react.memo)()", @@ -2063,11 +2063,11 @@ Array [ "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/span", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedClass(Tooltip)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedFunctionComponent(Tooltip)", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", - "/Symbol(react.forward_ref)()/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)()/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))/div", @@ -2132,10 +2132,10 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/Symbol(react.memo)(Icon)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div:data-testid='plus-button-onMouseDown'", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/div", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)", - "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/UtopiaSpiedFunctionComponent(PropertyLabelAndPlusButton)/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/div/div/ControlForProp/Symbol(react.memo)()", "/div/div/ControlForProp/Symbol(react.memo)()", @@ -2154,11 +2154,11 @@ Array [ "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/span", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedClass(Tooltip)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/UtopiaSpiedFunctionComponent(Tooltip)", "/UtopiaSpiedFunctionComponent(MenuProvider)/div/Symbol(react.forward_ref)()/div", - "/Symbol(react.forward_ref)()/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)()/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(Styled(div))/div", @@ -2262,16 +2262,16 @@ Array [ "////UtopiaSpiedExoticType(Symbol(react.provider))", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/UtopiaSpiedFunctionComponent()/UtopiaSpiedExoticType(Symbol(react.provider))", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/UtopiaSpiedFunctionComponent(MenuProvider)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/UtopiaSpiedFunctionComponent(ContextMenu)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/Symbol(react.forward_ref)(EmotionCssPropInternal)", "//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(MenuProvider)/div", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedClass(StateManager)", @@ -2398,7 +2398,7 @@ Array [ "/TextSubsection/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/TextSubsection/div//Symbol(react.forward_ref)(Styled(div))", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/Symbol(react.memo)()", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", @@ -2657,16 +2657,16 @@ Array [ "/UtopiaSpiedFunctionComponent(DropdownIndicator)/UtopiaSpiedFunctionComponent(DropdownIndicator)/Symbol(react.forward_ref)(render)/UtopiaSpiedExoticType(Symbol(react.context))", "/Symbol(react.forward_ref)(render)/UtopiaSpiedExoticType(Symbol(react.context))/Symbol(react.context)/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/UtopiaSpiedFunctionComponent(MenuProvider)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/UtopiaSpiedFunctionComponent(ContextMenu)", "/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/Symbol(react.forward_ref)(EmotionCssPropInternal)", "//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(MenuProvider)/div", - "/UtopiaSpiedFunctionComponent(MenuProvider)/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", - "/div/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", - "/UtopiaSpiedClass(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/UtopiaSpiedFunctionComponent(MenuProvider)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedClass(StateManager)", @@ -2793,7 +2793,7 @@ Array [ "/TextSubsection/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/TextSubsection/div//Symbol(react.forward_ref)(Styled(div))", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Symbol(react.forward_ref)())", - "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedClass(Tooltip)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(Tooltip)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/Symbol(react.memo)()", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(TextAlignControl)/UtopiaSpiedFunctionComponent(InspectorContextMenuWrapper)", diff --git a/editor/src/uuiui/tooltip.tsx b/editor/src/uuiui/tooltip.tsx index cd3e281da7f9..477c9f383391 100644 --- a/editor/src/uuiui/tooltip.tsx +++ b/editor/src/uuiui/tooltip.tsx @@ -17,63 +17,51 @@ export interface TooltipProps { textColor?: string } -function tooltipPropsEqual( - a: React.PropsWithChildren, - b: React.PropsWithChildren, -): boolean { - return ( - a == b || - (a.title === b.title && - a.placement === b.placement && - a.disabled === b.disabled && - a.children === b.children) - ) -} +export const Tooltip: React.FunctionComponent> = (props) => { + const backgroundColor = props.backgroundColor ?? colorTheme.neutralInvertedBackground.value + const textColor = props.textColor ?? colorTheme.neutralInvertedForeground.value -export class Tooltip extends React.Component> { - shouldComponentUpdate(nextProps: React.PropsWithChildren): boolean { - return !tooltipPropsEqual(this.props, nextProps) - } + const css = React.useMemo( + () => + ({ + fontWeight: 400, + fontSize: 11, + textAlign: 'center', + fontFamily: + "utopian-inter, -apple-system, BlinkMacSystemFont, Helvetica, 'Segoe UI', Roboto, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'", + backgroundColor: `${backgroundColor} !important`, + color: `${textColor} !important`, + '& .tippy-content': { + padding: '4px 8px !important', + }, + '&[data-placement^=top] .tippy-arrow::before': { + borderTopColor: `${backgroundColor} !important`, + }, + '&[data-placement^=right] .tippy-arrow::before': { + borderRightColor: `${backgroundColor} !important`, + }, + '&[data-placement^=bottom] .tippy-arrow::before': { + borderBottomColor: `${backgroundColor} !important`, + }, + '&[data-placement^=left] .tippy-arrow::before': { + borderLeftColor: `${backgroundColor} !important`, + }, + } as const), + [backgroundColor, textColor], + ) - render() { - const backgroundColor = this.props.backgroundColor ?? colorTheme.neutralInvertedBackground.value - const textColor = this.props.textColor ?? colorTheme.neutralInvertedForeground.value - return ( - - {this.props.children} - - ) - } + return ( + + {props.children} + + ) } From b1d8588c65ac576bc9a81f2b1d4ed60f9161ca6b Mon Sep 17 00:00:00 2001 From: Balint Gabor <127662+gbalint@users.noreply.github.com> Date: Tue, 17 Sep 2024 10:18:02 +0200 Subject: [PATCH 028/272] No dom query in grid element resize strategy (#6373) **Problem:** Another step to remove dom api dependency from grid strategies: the grid-resize-element strategy uses the new `getGlobalFramesOfGridCells` to detect the grid cell under the mouse. **Commit Details:** - Fixed `getGlobalFramesOfGridCells` problem: it calculated the local frame not the global frame.... - Fixed and improved `getGlobalFramesOfGridCells` test to include differend padding/row-padding/column-padding values - Memoized `getGlobalFramesOfGridCells`: this is a quite fast function so it wouldn't be important to memoize it, but in most cases we run it for the same grid cell (because we are doing an interaction in it), so it still makes sense to memoize. I just uses `memoize` with the default config (which allows memoization of 5 values) - Created a new `getGridCellUnderMouse` version called `getGridCellUnderMouseFromMetadata`, and call that from the strategy - I modified the strategy to use the canvas and not the window coordinate system. Unfortunately, `GridCustomStrategyState.targetCellData` uses the window coordinate system, and that is used in multiple strategies, so I postponed to change that too. I introduced a new type `TargetGridCellDataCanvas` (similar to `TargetGridCellData`), I plan to migrate to this new type everywhere. **TODO:** The strategy is still not the best. A downside of querying the grid cells under the mouse is that the strategy is broken when the mouse is not over the grid (even though the resize rectangle follows the mouse), see https://screenshot.click/16-30-s1avn-hgu83.mp4 Using the metadata it is possible to implement a much better strategy which can calculate where to resize to even when the mouse is not over the grid. That can come in a subsequent PR. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- .../strategies/grid-cell-bounds.ts | 38 +++++ .../strategies/grid-helpers.spec.browser2.tsx | 143 +++++++++--------- .../strategies/grid-helpers.ts | 37 ++--- .../grid-resize-element-strategy.ts | 48 +++--- editor/src/components/canvas/dom-lookup.ts | 18 +++ 5 files changed, 173 insertions(+), 111 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts index 02e7bf3f1d81..621ff9332207 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts @@ -10,6 +10,12 @@ import { } from '../../../../core/shared/math-utils' import { canvasPointToWindowPoint } from '../../dom-lookup' import * as EP from '../../../../core/shared/element-path' +import { + getGlobalFramesOfGridCells, + type GridCellGlobalFrames, + type TargetGridCellDataCanvas, +} from './grid-helpers' +import type { CanvasPoint } from '../../../../core/shared/math-utils' export type GridCellCoordinates = { row: number; column: number } @@ -27,6 +33,38 @@ export function gridCellTargetId( return gridCellTargetIdPrefix + `${EP.toString(gridElementPath)}-${row}-${column}` } +export function getGridCellUnderMouseFromMetadata( + grid: ElementInstanceMetadata, + canvasPoint: CanvasPoint, +): TargetGridCellDataCanvas | null { + const gridCellGlobalFrames = getGlobalFramesOfGridCells(grid) + + if (gridCellGlobalFrames == null) { + return null + } + + return getGridCellUnderPoint(gridCellGlobalFrames, canvasPoint) +} + +// TODO: we could optimize this with binary search, but huge grids are rare +function getGridCellUnderPoint( + gridCellGlobalFrames: GridCellGlobalFrames, + canvasPoint: CanvasPoint, +): TargetGridCellDataCanvas | null { + for (let i = 0; i < gridCellGlobalFrames.length; i++) { + for (let j = 0; j < gridCellGlobalFrames[i].length; j++) { + if (rectContainsPoint(gridCellGlobalFrames[i][j], canvasPoint)) { + return { + gridCellCoordinates: gridCellCoordinates(i + 1, j + 1), + cellCanvasRectangle: gridCellGlobalFrames[i][j], + } + } + } + } + return null +} + +// TODO: should be superseded by getGridCellUnderMouseFromMetadata export function getGridCellUnderMouse(mousePoint: WindowPoint) { return getGridCellAtPoint(mousePoint, false) } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx index 9712f1d1fb76..c7232d1373e2 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx @@ -1,7 +1,7 @@ import { matchInlineSnapshotBrowser } from '../../../../../test/karma-snapshots' import { runDOMWalker } from '../../../editor/actions/action-creators' import { makeTestProjectCodeWithSnippet, renderTestEditorWithCode } from '../../ui-jsx.test-utils' -import { getGlobalFramesOfGridCellsFromMetadata } from './grid-helpers' +import { getGlobalFramesOfGridCells } from './grid-helpers' describe('Grids', () => { it('can calculate global frames of grid cells', async () => { @@ -17,8 +17,9 @@ describe('Grids', () => { display: 'grid', gridTemplateColumns: '150px min-content 1fr 1fr', gridTemplateRows: 'min-content 1fr 1fr 1fr 1fr', - gridGap: 10, - padding: 10, + rowGap: 10, + columnGap: 20, + padding: 5, }} data-uid={'grid'} > @@ -110,7 +111,7 @@ describe('Grids', () => { // non-grids don't have cell measurements: expect( - getGlobalFramesOfGridCellsFromMetadata( + getGlobalFramesOfGridCells( editor.getEditorState().editor.jsxMetadata[ 'utopia-storyboard-uid/scene-aaa/app-entity:grid/child' ], @@ -119,7 +120,7 @@ describe('Grids', () => { // grids have cell measurements: matchInlineSnapshotBrowser( - getGlobalFramesOfGridCellsFromMetadata( + getGlobalFramesOfGridCells( editor.getEditorState().editor.jsxMetadata[ 'utopia-storyboard-uid/scene-aaa/app-entity:grid' ], @@ -129,130 +130,130 @@ describe('Grids', () => { Object { \"height\": 50, \"width\": 150, - \"x\": 10, - \"y\": 10, + \"x\": 132, + \"y\": 89, }, Object { \"height\": 50, \"width\": 80, - \"x\": 170, - \"y\": 10, + \"x\": 302, + \"y\": 89, }, Object { \"height\": 50, - \"width\": 119.5, - \"x\": 260, - \"y\": 10, + \"width\": 109.5, + \"x\": 402, + \"y\": 89, }, Object { \"height\": 50, - \"width\": 119.5, - \"x\": 389.5, - \"y\": 10, + \"width\": 109.5, + \"x\": 531.5, + \"y\": 89, }, ], Array [ Object { - \"height\": 83.25, + \"height\": 85.75, \"width\": 150, - \"x\": 10, - \"y\": 70, + \"x\": 132, + \"y\": 149, }, Object { - \"height\": 83.25, + \"height\": 85.75, \"width\": 80, - \"x\": 170, - \"y\": 70, + \"x\": 302, + \"y\": 149, }, Object { - \"height\": 83.25, - \"width\": 119.5, - \"x\": 260, - \"y\": 70, + \"height\": 85.75, + \"width\": 109.5, + \"x\": 402, + \"y\": 149, }, Object { - \"height\": 83.25, - \"width\": 119.5, - \"x\": 389.5, - \"y\": 70, + \"height\": 85.75, + \"width\": 109.5, + \"x\": 531.5, + \"y\": 149, }, ], Array [ Object { - \"height\": 83.25, + \"height\": 85.75, \"width\": 150, - \"x\": 10, - \"y\": 163.25, + \"x\": 132, + \"y\": 244.75, }, Object { - \"height\": 83.25, + \"height\": 85.75, \"width\": 80, - \"x\": 170, - \"y\": 163.25, + \"x\": 302, + \"y\": 244.75, }, Object { - \"height\": 83.25, - \"width\": 119.5, - \"x\": 260, - \"y\": 163.25, + \"height\": 85.75, + \"width\": 109.5, + \"x\": 402, + \"y\": 244.75, }, Object { - \"height\": 83.25, - \"width\": 119.5, - \"x\": 389.5, - \"y\": 163.25, + \"height\": 85.75, + \"width\": 109.5, + \"x\": 531.5, + \"y\": 244.75, }, ], Array [ Object { - \"height\": 83.25, + \"height\": 85.75, \"width\": 150, - \"x\": 10, - \"y\": 256.5, + \"x\": 132, + \"y\": 340.5, }, Object { - \"height\": 83.25, + \"height\": 85.75, \"width\": 80, - \"x\": 170, - \"y\": 256.5, + \"x\": 302, + \"y\": 340.5, }, Object { - \"height\": 83.25, - \"width\": 119.5, - \"x\": 260, - \"y\": 256.5, + \"height\": 85.75, + \"width\": 109.5, + \"x\": 402, + \"y\": 340.5, }, Object { - \"height\": 83.25, - \"width\": 119.5, - \"x\": 389.5, - \"y\": 256.5, + \"height\": 85.75, + \"width\": 109.5, + \"x\": 531.5, + \"y\": 340.5, }, ], Array [ Object { - \"height\": 83.25, + \"height\": 85.75, \"width\": 150, - \"x\": 10, - \"y\": 349.75, + \"x\": 132, + \"y\": 436.25, }, Object { - \"height\": 83.25, + \"height\": 85.75, \"width\": 80, - \"x\": 170, - \"y\": 349.75, + \"x\": 302, + \"y\": 436.25, }, Object { - \"height\": 83.25, - \"width\": 119.5, - \"x\": 260, - \"y\": 349.75, + \"height\": 85.75, + \"width\": 109.5, + \"x\": 402, + \"y\": 436.25, }, Object { - \"height\": 83.25, - \"width\": 119.5, - \"x\": 389.5, - \"y\": 349.75, + \"height\": 85.75, + \"width\": 109.5, + \"x\": 531.5, + \"y\": 436.25, }, ], ]`, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index caff66fee4bd..fcf31f4ad7d0 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -47,6 +47,7 @@ import { gridCellCoordinates, } from './grid-cell-bounds' import type { Sides } from 'utopia-api/core' +import { memoize } from '../../../../core/shared/memoize' export function runGridRearrangeMove( targetElement: ElementPath, @@ -350,6 +351,11 @@ export interface TargetGridCellData { cellWindowRectangle: WindowRectangle } +export interface TargetGridCellDataCanvas { + gridCellCoordinates: GridCellCoordinates + cellCanvasRectangle: CanvasRectangle +} + export function getTargetCell( previousTargetCell: GridCellCoordinates | null, duplicating: boolean, @@ -612,23 +618,18 @@ function getGridPositionIndex(props: { return (props.row - 1) * props.gridTemplateColumns + props.column - 1 } -export function getGlobalFramesOfGridCellsFromMetadata( +export type GridCellGlobalFrames = Array> + +function getGlobalFramesOfGridCellsInner( metadata: ElementInstanceMetadata, -): Array> | null { - return getGlobalFramesOfGridCells(metadata.specialSizeMeasurements) -} +): GridCellGlobalFrames | null { + const { globalFrame } = metadata + if (globalFrame == null || isInfinityRectangle(globalFrame)) { + return null + } + + const { containerGridProperties, padding, rowGap, columnGap } = metadata.specialSizeMeasurements -export function getGlobalFramesOfGridCells({ - containerGridProperties, - rowGap, - columnGap, - padding, -}: { - containerGridProperties: GridContainerProperties - rowGap: number | null - columnGap: number | null - padding: Sides -}): Array> | null { const columnWidths = gridTemplateToNumbers(containerGridProperties.gridTemplateColumns) const rowHeights = gridTemplateToNumbers(containerGridProperties.gridTemplateRows) @@ -638,9 +639,9 @@ export function getGlobalFramesOfGridCells({ } const cellRects: Array> = [] - let yOffset = padding.top ?? 0 + let yOffset = globalFrame.y + (padding.top ?? 0) rowHeights.forEach((height) => { - let xOffset = padding.left ?? 0 + let xOffset = globalFrame.x + (padding.left ?? 0) const rowRects: CanvasRectangle[] = [] columnWidths.forEach((width) => { const rect = canvasRectangle({ x: xOffset, y: yOffset, width: width, height: height }) @@ -654,6 +655,8 @@ export function getGlobalFramesOfGridCells({ return cellRects } +export const getGlobalFramesOfGridCells = memoize(getGlobalFramesOfGridCellsInner) + function gridTemplateToNumbers(gridTemplate: GridTemplate | null): Array | null { if (gridTemplate?.type !== 'DIMENSIONS') { return null diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts index 7f2c358e3d1b..dc4a0e73a030 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts @@ -6,7 +6,7 @@ import { assertNever } from '../../../../core/shared/utils' import { isCSSKeyword } from '../../../inspector/common/css-utils' import { isFixedHugFillModeApplied } from '../../../inspector/inspector-common' import { controlsForGridPlaceholders, GridResizeControls } from '../../controls/grid-controls' -import { canvasPointToWindowPoint } from '../../dom-lookup' +import { canvasRectangleToWindowRectangle } from '../../dom-lookup' import type { CanvasStrategyFactory } from '../canvas-strategies' import { onlyFitWhenDraggingThisControl } from '../canvas-strategies' import type { InteractionCanvasState } from '../canvas-strategy-types' @@ -16,8 +16,7 @@ import { strategyApplicationResult, } from '../canvas-strategy-types' import type { InteractionSession } from '../interaction-state' -import { getGridCellUnderMouse } from './grid-cell-bounds' -import type { TargetGridCellData } from './grid-helpers' +import { getGridCellUnderMouseFromMetadata } from './grid-cell-bounds' import { setGridPropsCommands } from './grid-helpers' export const gridResizeElementStrategy: CanvasStrategyFactory = ( @@ -78,26 +77,6 @@ export const gridResizeElementStrategy: CanvasStrategyFactory = ( return emptyStrategyApplicationResult } - const mouseWindowPoint = canvasPointToWindowPoint( - offsetPoint( - interactionSession.interactionData.dragStart, - interactionSession.interactionData.drag, - ), - canvasState.scale, - canvasState.canvasOffset, - ) - - let targetCell: TargetGridCellData | null = customState.grid.targetCellData - const cellUnderMouse = getGridCellUnderMouse(mouseWindowPoint) - if (cellUnderMouse != null) { - const { cellWindowRectangle, coordinates: gridCellCoordinates } = cellUnderMouse - targetCell = { cellWindowRectangle, gridCellCoordinates } - } - - if (targetCell == null) { - return emptyStrategyApplicationResult - } - const container = MetadataUtils.findElementByElementPath( canvasState.startingMetadata, EP.parentPath(selectedElement), @@ -105,6 +84,29 @@ export const gridResizeElementStrategy: CanvasStrategyFactory = ( if (container == null) { return emptyStrategyApplicationResult } + + const mouseCanvasPoint = offsetPoint( + interactionSession.interactionData.dragStart, + interactionSession.interactionData.drag, + ) + + const cellUnderMouse = getGridCellUnderMouseFromMetadata(container, mouseCanvasPoint) + const targetCell = + cellUnderMouse == null + ? customState.grid.targetCellData + : { + ...cellUnderMouse, + cellWindowRectangle: canvasRectangleToWindowRectangle( + cellUnderMouse.cellCanvasRectangle, + canvasState.scale, + canvasState.canvasOffset, + ), + } + + if (targetCell == null) { + return emptyStrategyApplicationResult + } + const gridTemplate = container.specialSizeMeasurements.containerGridProperties let gridProps: GridElementProperties = MetadataUtils.findElementByElementPath( diff --git a/editor/src/components/canvas/dom-lookup.ts b/editor/src/components/canvas/dom-lookup.ts index 7ed972ace357..94047c78525b 100644 --- a/editor/src/components/canvas/dom-lookup.ts +++ b/editor/src/components/canvas/dom-lookup.ts @@ -6,6 +6,7 @@ import type { CanvasRectangle, CanvasVector, WindowPoint, + WindowRectangle, } from '../../core/shared/math-utils' import { boundingRectangleArray, @@ -14,8 +15,10 @@ import { negate, offsetPoint, roundPointToNearestHalf, + scaleRect, scaleVector, windowPoint, + windowRectangle, } from '../../core/shared/math-utils' import type { ElementPath } from '../../core/shared/project-file-types' import * as EP from '../../core/shared/element-path' @@ -636,3 +639,18 @@ export function canvasPointToWindowPoint( throw new Error('calling screenToElementCoordinates() before being mounted') } } + +export function canvasRectangleToWindowRectangle( + canvasRect: CanvasRectangle, + canvasScale: number, + canvasOffset: CanvasVector, +): WindowRectangle { + const location = canvasPointToWindowPoint(canvasRect, canvasScale, canvasOffset) + const scaledRect = scaleRect(canvasRect, canvasScale) + return windowRectangle({ + x: location.x, + y: location.y, + width: scaledRect.width, + height: scaledRect.height, + }) +} From 1697de806e3e9a9459133f21ed0bbbf33eb79dbb Mon Sep 17 00:00:00 2001 From: Balazs Bajorics <2226774+balazsbajorics@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:34:22 +0200 Subject: [PATCH 029/272] Fix scrubbing performance of FrameUpdatingLayoutControl (#6375) **Problem:** When using the left label (such as **L**) to scrub a FrameUpdatingLayoutControl, the performance was bad. image Turns out the problem is simply that the control was never using the transient mode, for each scrub update it would fire a non-transient action, rerendering the entire canvas, **creating a new undo step!!!** **Fix:** Make the control aware of transient updates. **Commit Details:** - `executeFirstApplicableStrategy` takes an array of elementsToRerender, if it's a specific array of element paths, it automatically switches to dispatching Transient Actions - `NumberInput` now sets the transient flag for all onSubmit callbacks when scrubbed - `FrameUpdatingLayoutControl`'s onSubmitValue takes the transient parameter and feeds it to updateFrame - `updateFrame` calls `executeFirstApplicableStrategy` with the properly set `elementsToRerender` array **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [ ] I could navigate to various routes in Preview mode --- .../components/inspector/controls/control.ts | 5 + .../inspector-strategy.ts | 20 +++- .../frame-updating-layout-section.tsx | 106 +++++++++++------- editor/src/uuiui/inputs/number-input.tsx | 29 ++--- 4 files changed, 103 insertions(+), 57 deletions(-) diff --git a/editor/src/components/inspector/controls/control.ts b/editor/src/components/inspector/controls/control.ts index 7d02aca9defe..bd1104b68fb8 100644 --- a/editor/src/components/inspector/controls/control.ts +++ b/editor/src/components/inspector/controls/control.ts @@ -19,6 +19,11 @@ export type OnSubmitValueOrUnknownOrEmpty = ( transient?: boolean, ) => void +export type OnSubmitValueOrUnknownOrEmptyMaybeTransient = ( + value: UnknownOrEmptyInput, + transient: boolean, +) => void + export interface DEPRECATEDControlProps { id: string testId: string diff --git a/editor/src/components/inspector/inspector-strategies/inspector-strategy.ts b/editor/src/components/inspector/inspector-strategies/inspector-strategy.ts index cdf7d85255cd..38af9cf837a9 100644 --- a/editor/src/components/inspector/inspector-strategies/inspector-strategy.ts +++ b/editor/src/components/inspector/inspector-strategies/inspector-strategy.ts @@ -1,6 +1,7 @@ import type { CanvasCommand } from '../../canvas/commands/commands' import type { EditorDispatch } from '../../editor/action-types' -import { applyCommandsAction } from '../../editor/actions/action-creators' +import { applyCommandsAction, transientActions } from '../../editor/actions/action-creators' +import type { ElementsToRerender } from '../../editor/store/editor-state' interface CustomInspectorStrategyResultBase { commands: Array @@ -47,11 +48,26 @@ export function commandsForFirstApplicableStrategy( export function executeFirstApplicableStrategy( dispatch: EditorDispatch, + strategies: InspectorStrategy[], +): void { + return executeFirstApplicableStrategyForContinuousInteraction( + dispatch, + strategies, + 'rerender-all-elements', + ) +} +export function executeFirstApplicableStrategyForContinuousInteraction( + dispatch: EditorDispatch, strategies: InspectorStrategy[], + elementsToRerenderTransient: ElementsToRerender, ): void { const commands = commandsForFirstApplicableStrategy(strategies) if (commands != null) { - dispatch([applyCommandsAction(commands)]) + if (elementsToRerenderTransient !== 'rerender-all-elements') { + dispatch([transientActions([applyCommandsAction(commands)], elementsToRerenderTransient)]) + } else { + dispatch([applyCommandsAction(commands)]) + } } } diff --git a/editor/src/components/inspector/sections/layout-section/self-layout-subsection/frame-updating-layout-section.tsx b/editor/src/components/inspector/sections/layout-section/self-layout-subsection/frame-updating-layout-section.tsx index 33c5d446267d..0c729df8b904 100644 --- a/editor/src/components/inspector/sections/layout-section/self-layout-subsection/frame-updating-layout-section.tsx +++ b/editor/src/components/inspector/sections/layout-section/self-layout-subsection/frame-updating-layout-section.tsx @@ -46,7 +46,10 @@ import { type UnknownOrEmptyInput, } from '../../../common/css-utils' import { useInspectorLayoutInfo } from '../../../common/property-path-hooks' -import { executeFirstApplicableStrategy } from '../../../inspector-strategies/inspector-strategy' +import { + executeFirstApplicableStrategy, + executeFirstApplicableStrategyForContinuousInteraction, +} from '../../../inspector-strategies/inspector-strategy' import { UIGridRow } from '../../../widgets/ui-grid-row' import * as EP from '../../../../../core/shared/element-path' @@ -201,32 +204,43 @@ export const FrameUpdatingLayoutSection = React.memo(() => { ) const updateFrame = React.useCallback( - (frameUpdate: FrameUpdate) => { + (frameUpdate: FrameUpdate, transient: boolean) => { + const elementsToRerenderTransient = transient + ? selectedViewsRef.current + : 'rerender-all-elements' switch (frameUpdate.type) { case 'DELTA_FRAME_UPDATE': if ( frameUpdate.edgePosition === EdgePositionTop || frameUpdate.edgePosition === EdgePositionLeft ) { - executeFirstApplicableStrategy(dispatch, [ - moveInspectorStrategy( - metadataRef.current, - selectedViewsRef.current, - projectContentsRef.current, - frameUpdate.edgeMovement, - ), - ]) + executeFirstApplicableStrategyForContinuousInteraction( + dispatch, + [ + moveInspectorStrategy( + metadataRef.current, + selectedViewsRef.current, + projectContentsRef.current, + frameUpdate.edgeMovement, + ), + ], + elementsToRerenderTransient, + ) } else { - executeFirstApplicableStrategy(dispatch, [ - resizeInspectorStrategy( - metadataRef.current, - selectedViewsRef.current, - projectContentsRef.current, - originalGlobalFrame, - frameUpdate.edgePosition, - frameUpdate.edgeMovement, - ), - ]) + executeFirstApplicableStrategyForContinuousInteraction( + dispatch, + [ + resizeInspectorStrategy( + metadataRef.current, + selectedViewsRef.current, + projectContentsRef.current, + originalGlobalFrame, + frameUpdate.edgePosition, + frameUpdate.edgeMovement, + ), + ], + elementsToRerenderTransient, + ) } break case 'DIRECT_FRAME_UPDATE': @@ -235,27 +249,35 @@ export const FrameUpdatingLayoutSection = React.memo(() => { frameUpdate.edgePosition === EdgePositionLeft ) { const leftOrTop = frameUpdate.edgePosition === EdgePositionLeft ? 'left' : 'top' - executeFirstApplicableStrategy(dispatch, [ - directMoveInspectorStrategy( - metadataRef.current, - selectedViewsRef.current, - projectContentsRef.current, - leftOrTop, - frameUpdate.edgeValue, - ), - ]) + executeFirstApplicableStrategyForContinuousInteraction( + dispatch, + [ + directMoveInspectorStrategy( + metadataRef.current, + selectedViewsRef.current, + projectContentsRef.current, + leftOrTop, + frameUpdate.edgeValue, + ), + ], + elementsToRerenderTransient, + ) } else { const widthOrHeight = frameUpdate.edgePosition === EdgePositionRight ? 'width' : 'height' - executeFirstApplicableStrategy(dispatch, [ - directResizeInspectorStrategy( - metadataRef.current, - selectedViewsRef.current, - projectContentsRef.current, - widthOrHeight, - frameUpdate.edgeValue, - ), - ]) + executeFirstApplicableStrategyForContinuousInteraction( + dispatch, + [ + directResizeInspectorStrategy( + metadataRef.current, + selectedViewsRef.current, + projectContentsRef.current, + widthOrHeight, + frameUpdate.edgeValue, + ), + ], + elementsToRerenderTransient, + ) } break default: @@ -341,7 +363,7 @@ interface LayoutPinPropertyControlProps { label: string property: TLWH currentValues: Array - updateFrame: (frameUpdate: FrameUpdate) => void + updateFrame: (frameUpdate: FrameUpdate, transient: boolean) => void invalid?: boolean } @@ -378,7 +400,7 @@ const FrameUpdatingLayoutControl = React.memo((props: LayoutPinPropertyControlPr currentValuesRef.current = currentValues const onSubmitValue = React.useCallback( - (newValue: UnknownOrEmptyInput) => { + (newValue: UnknownOrEmptyInput, transient: boolean = false) => { const calculatedSingleCommonValue = getSingleCommonValue(currentValuesRef.current) if (isUnknownInputValue(newValue)) { // Ignore right now. @@ -390,14 +412,14 @@ const FrameUpdatingLayoutControl = React.memo((props: LayoutPinPropertyControlPr if (newValue.unit == null || newValue.unit === 'px') { const edgePosition = getTLWHEdgePosition(property) if (calculatedSingleCommonValue == null) { - updateFrame(directFrameUpdate(edgePosition, newValue.value)) + updateFrame(directFrameUpdate(edgePosition, newValue.value), transient) } else { const movement = getMovementFromValues( property, calculatedSingleCommonValue, newValue.value, ) - updateFrame(deltaFrameUpdate(edgePosition, movement)) + updateFrame(deltaFrameUpdate(edgePosition, movement), transient) } } else { console.error('Attempting to use a value with a unit, which is invalid.') diff --git a/editor/src/uuiui/inputs/number-input.tsx b/editor/src/uuiui/inputs/number-input.tsx index ba6d73773d6f..d0fcfc5ff9f3 100644 --- a/editor/src/uuiui/inputs/number-input.tsx +++ b/editor/src/uuiui/inputs/number-input.tsx @@ -32,6 +32,7 @@ import type { OnSubmitValue, OnSubmitValueOrEmpty, OnSubmitValueOrUnknownOrEmpty, + OnSubmitValueOrUnknownOrEmptyMaybeTransient, } from '../../components/inspector/controls/control' import type { Either } from '../../core/shared/either' import { isLeft, mapEither } from '../../core/shared/either' @@ -151,9 +152,9 @@ export interface AbstractNumberInputProps } export interface NumberInputProps extends AbstractNumberInputProps { - onSubmitValue?: OnSubmitValueOrUnknownOrEmpty - onTransientSubmitValue?: OnSubmitValueOrUnknownOrEmpty - onForcedSubmitValue?: OnSubmitValueOrUnknownOrEmpty + onSubmitValue?: OnSubmitValueOrUnknownOrEmptyMaybeTransient + onTransientSubmitValue?: OnSubmitValueOrUnknownOrEmptyMaybeTransient + onForcedSubmitValue?: OnSubmitValueOrUnknownOrEmptyMaybeTransient setGlobalCursor?: (cursor: CSSCursor | null) => void onMouseEnter?: MouseEventHandler onMouseLeave?: MouseEventHandler @@ -282,15 +283,15 @@ export const NumberInput = React.memo( const newValue = setCSSNumberValue(value, newNumericValue) if (transient) { if (onTransientSubmitValue != null) { - onTransientSubmitValue(newValue) + onTransientSubmitValue(newValue, transient) } else if (onSubmitValue != null) { - onSubmitValue(newValue) + onSubmitValue(newValue, transient) } } else { if (onForcedSubmitValue != null) { - onForcedSubmitValue(newValue) + onForcedSubmitValue(newValue, transient) } else if (onSubmitValue != null) { - onSubmitValue(newValue) + onSubmitValue(newValue, transient) } } repeatedValueRef.current = newValue @@ -339,15 +340,15 @@ export const NumberInput = React.memo( if (transient) { if (onTransientSubmitValue != null) { - onTransientSubmitValue(newValue) + onTransientSubmitValue(newValue, transient) } else if (onSubmitValue != null) { - onSubmitValue(newValue) + onSubmitValue(newValue, transient) } } else { if (onForcedSubmitValue != null) { - onForcedSubmitValue(newValue) + onForcedSubmitValue(newValue, transient) } else if (onSubmitValue != null) { - onSubmitValue(newValue) + onSubmitValue(newValue, transient) } } updateValue(newValue) @@ -484,7 +485,7 @@ export const NumberInput = React.memo( // todo make sure this isn't doubling up the value submit if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && onForcedSubmitValue != null) { if (value != null) { - onForcedSubmitValue(value) + onForcedSubmitValue(value, false) } } }, @@ -519,7 +520,7 @@ export const NumberInput = React.memo( if (valueChangedSinceFocus) { setValueChangedSinceFocus(false) if (onSubmitValue != null) { - onSubmitValue(newValue) + onSubmitValue(newValue, false) } } }, @@ -565,6 +566,7 @@ export const NumberInput = React.memo( repeatedValueRef.current != null ? repeatedValueRef.current : unknownInputValue(displayValue), + false, ) } @@ -611,6 +613,7 @@ export const NumberInput = React.memo( repeatedValueRef.current != null ? repeatedValueRef.current : unknownInputValue(displayValue), + false, ) } From 57d569c35e7eddae400e4f380db3412d110c85ea Mon Sep 17 00:00:00 2001 From: Balint Gabor <127662+gbalint@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:30:33 +0200 Subject: [PATCH 030/272] Less dom queries in grid strategies (#6377) Followup to https://github.com/concrete-utopia/utopia/pull/6373 I continued the work to - remove dom api queries from strategies - migrate from window points and rectangle to canvas ones. - unify the cell query functions, because we have more than 5 functions which basically do the same thing (return cell data under the a point) **Fix:** - Replaced all `TargetGridCellData` usage with the new `TargetGridCellDataCanvas`, which contains canvas and not window bounds (and renamed that back to `TargetGridCellData`) - Deleted a bunch of similar query functions which returned cell data under a certain point (`getTargetCell`, `getGridCellUnderMouse`, `getGridCellUnderMouseRecursive`, `getTargetGridCellUnderCursor`, etc), and replaced them all with `getGridCellUnderMouseFromMetadata ` - Updated grid-resize-element, grid-rearrange-move, grid-rearrange-move-duplicate, grid-draw-to-insert to use `getGridCellUnderMouseFromMetadata` - I had some 1-pixel differences in draw-to-insert tests... not sure why, maybe a rounding error in the canvas<->window conversions which I removed. I updated the tests, I think draw to insert works fine. **Next step:** - [ ] Continue deleting/converting grid query functions to metadata: `getGridCellBoundsFromCanvas`, `getGridCellAtPoint`, `getCellWindowRect` **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- .../draw-to-insert-strategy.spec.browser2.tsx | 8 +-- .../strategies/grid-cell-bounds.ts | 15 +---- .../grid-draw-to-insert-strategy.tsx | 45 +++----------- .../strategies/grid-helpers.ts | 58 +++++-------------- .../grid-rearrange-move-duplicate-strategy.ts | 1 - .../grid-rearrange-move-strategy.ts | 1 - ...grid-reparent-strategies.spec.browser2.tsx | 8 ++- .../strategies/grid-reparent-strategy.tsx | 54 +++++++---------- .../grid-resize-element-strategy.ts | 12 +--- 9 files changed, 59 insertions(+), 143 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-strategy.spec.browser2.tsx index b1d558488842..af5ab649508d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-strategy.spec.browser2.tsx @@ -324,9 +324,9 @@ export var storyboard = ( gridColumn: '2', gridRow: '1', height: '60px', - left: '83px', + left: '84px', position: 'absolute', - top: '150px', + top: '151px', width: '40px', }) }) @@ -371,9 +371,9 @@ export var storyboard = ( gridColumn: '1', gridRow: '1', height: '30px', - left: '125px', + left: '126px', position: 'absolute', - top: '75px', + top: '76px', width: '20px', }) }) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts index 621ff9332207..2439fb46efc6 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts @@ -13,7 +13,7 @@ import * as EP from '../../../../core/shared/element-path' import { getGlobalFramesOfGridCells, type GridCellGlobalFrames, - type TargetGridCellDataCanvas, + type TargetGridCellData, } from './grid-helpers' import type { CanvasPoint } from '../../../../core/shared/math-utils' @@ -36,7 +36,7 @@ export function gridCellTargetId( export function getGridCellUnderMouseFromMetadata( grid: ElementInstanceMetadata, canvasPoint: CanvasPoint, -): TargetGridCellDataCanvas | null { +): TargetGridCellData | null { const gridCellGlobalFrames = getGlobalFramesOfGridCells(grid) if (gridCellGlobalFrames == null) { @@ -50,7 +50,7 @@ export function getGridCellUnderMouseFromMetadata( function getGridCellUnderPoint( gridCellGlobalFrames: GridCellGlobalFrames, canvasPoint: CanvasPoint, -): TargetGridCellDataCanvas | null { +): TargetGridCellData | null { for (let i = 0; i < gridCellGlobalFrames.length; i++) { for (let j = 0; j < gridCellGlobalFrames[i].length; j++) { if (rectContainsPoint(gridCellGlobalFrames[i][j], canvasPoint)) { @@ -64,15 +64,6 @@ function getGridCellUnderPoint( return null } -// TODO: should be superseded by getGridCellUnderMouseFromMetadata -export function getGridCellUnderMouse(mousePoint: WindowPoint) { - return getGridCellAtPoint(mousePoint, false) -} - -export function getGridCellUnderMouseRecursive(mousePoint: WindowPoint) { - return getGridCellAtPoint(mousePoint, true) -} - function isGridCellTargetId(id: string): boolean { return id.startsWith(gridCellTargetIdPrefix) } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx index 7e4fac06a0b5..01c45b432ede 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx @@ -21,7 +21,7 @@ import { showGridControls } from '../../commands/show-grid-controls-command' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { wildcardPatch } from '../../commands/wildcard-patch-command' import { controlsForGridPlaceholders } from '../../controls/grid-controls' -import { canvasPointToWindowPoint, windowToCanvasCoordinates } from '../../dom-lookup' +import { canvasPointToWindowPoint } from '../../dom-lookup' import { getWrapperWithGeneratedUid, getWrappingCommands, @@ -43,9 +43,10 @@ import { getStyleAttributesForFrameInAbsolutePosition, updateInsertionSubjectWithAttributes, } from './draw-to-insert-metastrategy' -import { getTargetCell, setGridPropsCommands } from './grid-helpers' +import { setGridPropsCommands } from './grid-helpers' import { newReparentSubjects } from './reparent-helpers/reparent-strategy-helpers' import { getReparentTargetUnified } from './reparent-helpers/reparent-strategy-parent-lookup' +import { getGridCellUnderMouseFromMetadata } from './grid-cell-bounds' export const gridDrawToInsertText: CanvasStrategyFactory = ( canvasState: InteractionCanvasState, @@ -150,11 +151,10 @@ const gridDrawToInsertStrategyInner = controlsToRender: [controlsForGridPlaceholders(targetParent)], fitness: 5, apply: (strategyLifecycle) => { - const newTargetCell = getGridCellUnderCursor( - interactionData, - canvasState, - customStrategyState, - ) + const canvasPointToUse = + interactionData.type === 'DRAG' ? interactionData.dragStart : interactionData.point + + const newTargetCell = getGridCellUnderMouseFromMetadata(parent, canvasPointToUse) if (strategyLifecycle === 'mid-interaction' && interactionData.type === 'HOVER') { return strategyApplicationResult( @@ -182,13 +182,7 @@ const gridDrawToInsertStrategyInner = return emptyStrategyApplicationResult } - const { gridCellCoordinates, cellWindowRectangle } = newTargetCell - - const cellCanvasOrigin = windowToCanvasCoordinates( - canvasState.scale, - canvasState.canvasOffset, - cellWindowRectangle, - ).canvasPositionRounded + const { gridCellCoordinates, cellCanvasRectangle } = newTargetCell const defaultSize = interactionData.type === 'DRAG' && @@ -200,7 +194,7 @@ const gridDrawToInsertStrategyInner = const insertionCommand = getInsertionCommand( targetParent, insertionSubject, - getFrameForInsertion(interactionData, defaultSize, cellCanvasOrigin), + getFrameForInsertion(interactionData, defaultSize, cellCanvasRectangle), ) const gridTemplate = parent.specialSizeMeasurements.containerGridProperties @@ -329,24 +323,3 @@ function getInsertionCommand( return insertElementInsertionSubject('always', updatedInsertionSubject, insertionPath) } - -function getGridCellUnderCursor( - interactionData: DragInteractionData | HoverInteractionData, - canvasState: InteractionCanvasState, - customStrategyState: CustomStrategyState, -) { - const windowPointToUse = - interactionData.type === 'DRAG' ? interactionData.dragStart : interactionData.point - - const mouseWindowPoint = canvasPointToWindowPoint( - windowPointToUse, - canvasState.scale, - canvasState.canvasOffset, - ) - - return getTargetCell( - customStrategyState.grid.targetCellData?.gridCellCoordinates ?? null, - false, - mouseWindowPoint, - ) -} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index fcf31f4ad7d0..4030c029d901 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -26,7 +26,6 @@ import { scaleVector, windowPoint, windowVector, - type WindowPoint, } from '../../../../core/shared/math-utils' import * as PP from '../../../../core/shared/property-path' import { absolute } from '../../../../utils/utils' @@ -42,11 +41,9 @@ import type { DragInteractionData } from '../interaction-state' import type { GridCellCoordinates } from './grid-cell-bounds' import { getCellWindowRect, - getGridCellUnderMouse, - getGridCellUnderMouseRecursive, + getGridCellUnderMouseFromMetadata, gridCellCoordinates, } from './grid-cell-bounds' -import type { Sides } from 'utopia-api/core' import { memoize } from '../../../../core/shared/memoize' export function runGridRearrangeMove( @@ -57,7 +54,6 @@ export function runGridRearrangeMove( canvasScale: number, canvasOffset: CanvasVector, customState: GridCustomStrategyState, - duplicating: boolean, ): { commands: CanvasCommand[] targetCell: TargetGridCellData | null @@ -75,18 +71,23 @@ export function runGridRearrangeMove( } } - const mouseWindowPoint = canvasPointToWindowPoint( - offsetPoint(interactionData.dragStart, interactionData.drag), - canvasScale, - canvasOffset, - ) + const parentGridPath = EP.parentPath(selectedElement) + const grid = MetadataUtils.findElementByElementPath(jsxMetadata, parentGridPath) + + if (grid == null) { + return { + commands: [], + targetCell: null, + originalRootCell: null, + draggingFromCell: null, + targetRootCell: null, + } + } + + const mousePos = offsetPoint(interactionData.dragStart, interactionData.drag) const targetCellData = - getTargetCell( - customState.targetCellData?.gridCellCoordinates ?? null, - duplicating, - mouseWindowPoint, - ) ?? customState.targetCellData + getGridCellUnderMouseFromMetadata(grid, mousePos) ?? customState.targetCellData if (targetCellData == null) { return { @@ -347,37 +348,10 @@ export function setGridPropsCommands( } export interface TargetGridCellData { - gridCellCoordinates: GridCellCoordinates - cellWindowRectangle: WindowRectangle -} - -export interface TargetGridCellDataCanvas { gridCellCoordinates: GridCellCoordinates cellCanvasRectangle: CanvasRectangle } -export function getTargetCell( - previousTargetCell: GridCellCoordinates | null, - duplicating: boolean, - mouseWindowPoint: WindowPoint, -): TargetGridCellData | null { - let cell = previousTargetCell ?? null - const cellUnderMouse = duplicating - ? getGridCellUnderMouseRecursive(mouseWindowPoint) - : getGridCellUnderMouse(mouseWindowPoint) - if (cellUnderMouse == null) { - return null - } - cell = cellUnderMouse.coordinates - if (cell.row < 1 || cell.column < 1) { - return null - } - return { - gridCellCoordinates: cell, - cellWindowRectangle: cellUnderMouse.cellWindowRectangle, - } -} - function getElementGridProperties( element: ElementInstanceMetadata, cellUnderMouse: { row: number; column: number }, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts index ec44a5d3d40d..24b363140066 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts @@ -86,7 +86,6 @@ export const gridRearrangeMoveDuplicateStrategy: CanvasStrategyFactory = ( canvasState.scale, canvasState.canvasOffset, customState.grid, - true, ) if (moveCommands.length === 0) { return emptyStrategyApplicationResult diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts index 0e108b5dfb1a..1a1f9c02182f 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts @@ -183,7 +183,6 @@ function getCommandsAndPatchForGridRearrange( canvasState.scale, canvasState.canvasOffset, customState.grid, - false, ) return { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategies.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategies.spec.browser2.tsx index 1456ab0423f2..8b65e186af9c 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategies.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategies.spec.browser2.tsx @@ -627,7 +627,7 @@ describe('grid reparent strategies', () => { await selectComponentsForTest(editor, [EP.fromString('sb/grid/dragme')]) - await dragOut(editor, 'grid', EP.fromString('sb/grid/dragme'), { x: 2200, y: 2500 }) + await dragOut(editor, 'grid', EP.fromString('sb/grid/dragme'), { x: 2200, y: 2200 }) expect(getPrintedUiJsCode(editor.getEditorState())).toEqual( formatTestProjectCode( @@ -804,7 +804,11 @@ async function dragOut( const sourceGridCell = renderResult.renderedDOM.getByTestId(GridCellTestId(cell)) const sourceRect = sourceGridCell.getBoundingClientRect() - await mouseClickAtPoint(sourceGridCell, sourceRect, { modifiers: cmdModifier }) + await mouseClickAtPoint( + sourceGridCell, + { x: sourceRect.x + 5, y: sourceRect.y + 5 }, + { modifiers: cmdModifier }, + ) await mouseDragFromPointToPoint(sourceGridCell, sourceRect, endPoint, { modifiers: cmdModifier, }) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx index 24bb761a39f2..4249b4b699fa 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx @@ -23,13 +23,11 @@ import { controlsForGridPlaceholders } from '../../controls/grid-controls' import { ParentBounds } from '../../controls/parent-bounds' import { ParentOutlines } from '../../controls/parent-outlines' import { ZeroSizedElementControls } from '../../controls/zero-sized-element-controls' -import { canvasPointToWindowPoint } from '../../dom-lookup' import type { CanvasStrategyFactory } from '../canvas-strategies' import type { CanvasStrategy, ControlWithProps, CustomStrategyState, - GridCustomStrategyState, InteractionCanvasState, } from '../canvas-strategy-types' import { @@ -41,14 +39,13 @@ import { import type { DragInteractionData, InteractionSession, UpdatedPathMap } from '../interaction-state' import { honoursPropsPosition, shouldKeepMovingDraggedGroupChildren } from './absolute-utils' import { replaceFragmentLikePathsWithTheirChildrenRecursive } from './fragment-like-helpers' -import type { TargetGridCellData } from './grid-helpers' -import { getTargetCell, setGridPropsCommands } from './grid-helpers' +import { setGridPropsCommands } from './grid-helpers' import { ifAllowedToReparent, isAllowedToReparent } from './reparent-helpers/reparent-helpers' import { removeAbsolutePositioningProps } from './reparent-helpers/reparent-property-changes' import type { ReparentTarget } from './reparent-helpers/reparent-strategy-helpers' import { getReparentOutcome, pathToReparent } from './reparent-utils' import { flattenSelection } from './shared-move-strategies-helpers' -import type { GridCellCoordinates } from './grid-cell-bounds' +import { getGridCellUnderMouseFromMetadata, type GridCellCoordinates } from './grid-cell-bounds' import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' export function gridReparentStrategy( @@ -142,27 +139,6 @@ export function controlsForGridReparent(reparentTarget: ReparentTarget): Control ] } -function getTargetGridCellUnderCursor( - interactionData: DragInteractionData, - canvasScale: number, - canvasOffset: CanvasVector, - customState: GridCustomStrategyState, -): TargetGridCellData | null { - const mouseWindowPoint = canvasPointToWindowPoint( - offsetPoint(interactionData.dragStart, interactionData.drag ?? canvasVector({ x: 0, y: 0 })), - canvasScale, - canvasOffset, - ) - - const targetCellUnderMouse = getTargetCell( - customState.targetCellData?.gridCellCoordinates ?? null, - false, - mouseWindowPoint, - ) - - return targetCellUnderMouse -} - export function applyGridReparent( canvasState: InteractionCanvasState, interactionData: DragInteractionData, @@ -172,7 +148,7 @@ export function applyGridReparent( gridFrame: CanvasRectangle, ) { return () => { - if (interactionData.drag == null) { + if (interactionData.drag == null || selectedElements.length === 0) { return emptyStrategyApplicationResult } @@ -184,7 +160,16 @@ export function applyGridReparent( selectedElements, newParent.intendedParentPath, () => { - if (interactionData.drag == null) { + if (interactionData.drag == null || selectedElements.length === 0) { + return emptyStrategyApplicationResult + } + + const grid = MetadataUtils.findElementByElementPath( + canvasState.startingMetadata, + newParent.intendedParentPath, + ) + + if (grid == null) { return emptyStrategyApplicationResult } @@ -201,13 +186,14 @@ export function applyGridReparent( return emptyStrategyApplicationResult } + const mousePos = offsetPoint( + interactionData.dragStart, + interactionData.drag ?? canvasVector({ x: 0, y: 0 }), + ) + const targetCellData = - getTargetGridCellUnderCursor( - interactionData, - canvasState.scale, - canvasState.canvasOffset, - customStrategyState.grid, - ) ?? customStrategyState.grid.targetCellData + getGridCellUnderMouseFromMetadata(grid, mousePos) ?? + customStrategyState.grid.targetCellData if (targetCellData == null) { return emptyStrategyApplicationResult diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts index dc4a0e73a030..64730c52ff48 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts @@ -91,17 +91,7 @@ export const gridResizeElementStrategy: CanvasStrategyFactory = ( ) const cellUnderMouse = getGridCellUnderMouseFromMetadata(container, mouseCanvasPoint) - const targetCell = - cellUnderMouse == null - ? customState.grid.targetCellData - : { - ...cellUnderMouse, - cellWindowRectangle: canvasRectangleToWindowRectangle( - cellUnderMouse.cellCanvasRectangle, - canvasState.scale, - canvasState.canvasOffset, - ), - } + const targetCell = cellUnderMouse == null ? customState.grid.targetCellData : cellUnderMouse if (targetCell == null) { return emptyStrategyApplicationResult From b75611c6ac26cf7816f7d87eb5e4ec2794df0dab Mon Sep 17 00:00:00 2001 From: Balazs Bajorics <2226774+balazsbajorics@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:17:32 +0200 Subject: [PATCH 031/272] DomWalkerObservers know about ElementsToRerenderGLOBAL (#6383) **Problem:** The dom-walker observers (now used for triggering the dom-sampler) fire for continuous interactions that don't have `editor.canvas.interactionSession`, such as scrubbing in the inspector. **Fix:** The mutation callback now checks if `ElementsToRerenderGLOBAL.current` is in selective mode, and then it will behave similarly to when there is an active interactionSession. **Commit Details:** - Renamed `selectCanvasInteractionHappening ` to `isCanvasInteractionHappening` - `isCanvasInteractionHappening` is aware of ElementsToRerenderGLOBAL.current --- editor/src/components/canvas/dom-walker.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/editor/src/components/canvas/dom-walker.ts b/editor/src/components/canvas/dom-walker.ts index 0051199c8df8..475ff3c1295c 100644 --- a/editor/src/components/canvas/dom-walker.ts +++ b/editor/src/components/canvas/dom-walker.ts @@ -72,6 +72,7 @@ import { getFlexAlignment, getFlexJustifyContent, MaxContent } from '../inspecto import type { EditorDispatch } from '../editor/action-types' import { runDOMWalker } from '../editor/actions/action-creators' import { CanvasContainerOuterId } from './canvas-component-entry' +import { ElementsToRerenderGLOBAL } from './ui-jsx-canvas' export const ResizeObserver = window.ResizeObserver ?? ResizeObserverSyntheticDefault.default ?? ResizeObserverSyntheticDefault @@ -306,9 +307,9 @@ export function resubscribeObservers(domWalkerMutableState: { } } -function selectCanvasInteractionHappening(store: EditorStorePatched): boolean { +function isCanvasInteractionHappening(store: EditorStorePatched): boolean { const interactionSessionActive = store.editor.canvas.interactionSession != null - return interactionSessionActive + return interactionSessionActive || ElementsToRerenderGLOBAL.current !== 'rerender-all-elements' } export function initDomWalkerObservers( @@ -329,7 +330,7 @@ export function initDomWalkerObservers( // adequately assess the performance impact of doing so, and ideally find a way to only do so when the observed // change was not triggered by a user interaction const resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => { - const canvasInteractionHappening = selectCanvasInteractionHappening(editorStore.getState()) + const canvasInteractionHappening = isCanvasInteractionHappening(editorStore.getState()) const selectedViews = editorStore.getState().editor.selectedViews if (canvasInteractionHappening) { // Warning this only adds the selected views instead of the observed element @@ -352,7 +353,7 @@ export function initDomWalkerObservers( }) const mutationObserver = new window.MutationObserver((mutations: MutationRecord[]) => { - const canvasInteractionHappening = selectCanvasInteractionHappening(editorStore.getState()) + const canvasInteractionHappening = isCanvasInteractionHappening(editorStore.getState()) const selectedViews = editorStore.getState().editor.selectedViews if (canvasInteractionHappening) { From 8ab360fd6767b47872ced83d2454b28a6623612f Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:29:32 +0200 Subject: [PATCH 032/272] Preserve repeats when resizing grids (#6380) **Problem:** When resizing a grid, if the template contains `repeat` functions they will get denormalized to the calculated values, which is confusing/wrong/etc. **Fix:** The goal is to: 1. preserve `repeat` keywords after resizes 2. if resizing a repeated col/row, update the repeated _value_ 3. resize _all_ rows/cols generated by the same repeat if resizing any of them In order to achieve this, this PR does a bunch of things: 1. It scraps the old grid template parsing in favor of `csstree` AST parsing, preserving `repeats` 2. It adds a new grid dimension type, `GridCSSRepeat` which contains the values that will be repeated (and how many times) 3. It expands the repeats when displaying the rows/cols and for counting them 4. It reworks the resize strategy so that it updates as per the goals 5. It updates the grid controls so that repeated cols/rows are highlighted when resizing any of them https://github.com/user-attachments/assets/7c4fe075-22db-4628-abba-0feb966f6d43 Fixes #6379 --- .../resize-grid-strategy.spec.browser2.tsx | 4 +- .../strategies/resize-grid-strategy.ts | 107 ++++++++- .../canvas/controls/grid-controls.tsx | 142 ++++++++++-- .../store/store-deep-equality-instances.ts | 42 +++- .../inspector/common/css-tree-utils.ts | 50 ----- .../inspector/common/css-utils.spec.ts | 58 ----- .../components/inspector/common/css-utils.ts | 205 +++++++++++------- .../src/components/inspector/flex-section.tsx | 60 +++-- 8 files changed, 429 insertions(+), 239 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.spec.browser2.tsx index 67593bcedcee..c829dc823ae4 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.spec.browser2.tsx @@ -255,7 +255,7 @@ export var storyboard = ( width: 600, height: 600, gridTemplateColumns: '2.4fr 1fr 1fr', - gridTemplateRows: '99px 129px 90px 0px', + gridTemplateRows: '99px 129px 90px', height: 'max-content', }} > @@ -370,7 +370,7 @@ export var storyboard = ( gap: 10, width: 600, height: 600, - gridTemplateColumns: '1fr 2fr 1fr', + gridTemplateColumns: 'repeat(3, 2fr)', gridTemplateRows: '99px 109px 90px', height: 'max-content', }} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts index 57f261d4e10f..1489e1b20d2b 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts @@ -23,13 +23,17 @@ import { import type { InteractionSession } from '../interaction-state' import type { GridDimension } from '../../../../components/inspector/common/css-utils' import { + cssNumber, + gridCSSNumber, + gridCSSRepeat, isGridCSSNumber, - printArrayGridDimension, + isGridCSSRepeat, + printArrayGridDimensions, } from '../../../../components/inspector/common/css-utils' -import { modify, toFirst } from '../../../../core/shared/optics/optic-utilities' +import { toFirst } from '../../../../core/shared/optics/optic-utilities' import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' import type { Either } from '../../../../core/shared/either' -import { foldEither, isRight } from '../../../../core/shared/either' +import { foldEither, isLeft, isRight } from '../../../../core/shared/either' import { roundToNearestWhole } from '../../../../core/shared/math-utils' import type { GridAutoOrTemplateBase } from '../../../../core/shared/element-template' @@ -112,11 +116,29 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( return emptyStrategyApplicationResult } + // Expanded representation of the original values, where repeated elements are serialized. + // Each element also contains the indexes information to be used later on to build the resized + // template string. + const expandedOriginalValues = originalValues.dimensions.reduce((acc, cur, index) => { + if (isGridCSSRepeat(cur)) { + const repeatGroup = cur.value.map((dim, repeatedIndex) => + expandedGridDimension(dim, index, repeatedIndex), + ) + let expanded: ExpandedGridDimension[] = [] + for (let i = 0; i < cur.times; i++) { + expanded.push(...repeatGroup) + } + return [...acc, ...expanded] + } else { + return [...acc, expandedGridDimension(cur, index)] + } + }, [] as ExpandedGridDimension[]) + const mergedValues: GridAutoOrTemplateBase = { type: calculatedValues.type, dimensions: calculatedValues.dimensions.map((dim, index) => { - if (index < originalValues.dimensions.length) { - return originalValues.dimensions[index] + if (index < expandedOriginalValues.length) { + return expandedOriginalValues[index] } return dim }), @@ -134,22 +156,38 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( const calculatedValue = toFirst(valueOptic, calculatedValues.dimensions) const mergedValue = toFirst(valueOptic, mergedValues.dimensions) + if (isLeft(mergedValue)) { + return emptyStrategyApplicationResult + } const mergedUnit = toFirst(unitOptic, mergedValues.dimensions) - const isFractional = isRight(mergedUnit) && mergedUnit.value === 'fr' + if (isLeft(mergedUnit)) { + return emptyStrategyApplicationResult + } + + const isFractional = mergedUnit.value === 'fr' const precision = modifiers.cmd ? 'coarse' : 'precise' + const areaName = mergedValues.dimensions[control.columnOrRow]?.areaName ?? null - const newSetting = modify( - valueOptic, - (current) => + const newValue = gridCSSNumber( + cssNumber( newResizedValue( - current, + mergedValue.value, getNewDragValue(dragAmount, isFractional, calculatedValue, mergedValue), precision, isFractional, ), - mergedValues.dimensions, + mergedUnit.value, + ), + areaName, ) - const propertyValueAsString = printArrayGridDimension(newSetting) + + const newDimensions = buildResizedDimensions({ + newValue: newValue, + originalValues: originalValues.dimensions, + target: expandedOriginalValues[control.columnOrRow], + }) + + const propertyValueAsString = printArrayGridDimensions(newDimensions) const commands = [ setProperty( @@ -169,6 +207,51 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( } } +type DimensionIndexes = { + originalIndex: number // the index of this element in the original values + repeatedIndex: number // the index of this element, if it's generated via a repeat, inside the repeated values array definition +} + +function expandedGridDimension( + dim: GridDimension, + originalIndex: number, + repeatedIndex: number = 0, +): ExpandedGridDimension { + return { + ...dim, + indexes: { + originalIndex: originalIndex, + repeatedIndex: repeatedIndex, + }, + } +} + +type ExpandedGridDimension = GridDimension & { + indexes: DimensionIndexes +} + +function buildResizedDimensions(params: { + newValue: GridDimension + originalValues: GridDimension[] + target: ExpandedGridDimension +}) { + return params.originalValues.map((dim, index) => { + if (index !== params.target.indexes.originalIndex) { + return dim + } else if (isGridCSSRepeat(dim)) { + const repeatedIndex = params.target.indexes.repeatedIndex ?? 0 + const repeatGroup = [ + ...dim.value.slice(0, repeatedIndex), + params.newValue, + ...dim.value.slice(repeatedIndex + 1), + ] + return gridCSSRepeat(dim.times, repeatGroup) + } else { + return params.newValue + } + }) +} + function getNewDragValue( dragAmount: number, isFractional: boolean, diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 688df97ef115..5992931ef155 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -7,7 +7,10 @@ import type { CSSProperties } from 'react' import React from 'react' import type { Sides } from 'utopia-api/core' import type { ElementPath } from 'utopia-shared/src/types' -import type { GridDimension } from '../../../components/inspector/common/css-utils' +import type { + GridDimension, + GridDiscreteDimension, +} from '../../../components/inspector/common/css-utils' import { isCSSKeyword, printGridAutoOrTemplateBase, @@ -17,6 +20,7 @@ import { MetadataUtils } from '../../../core/model/element-metadata-utils' import { mapDropNulls, stripNulls } from '../../../core/shared/array-utils' import { defaultEither } from '../../../core/shared/either' import * as EP from '../../../core/shared/element-path' +import type { GridAutoOrTemplateDimensions } from '../../../core/shared/element-template' import { isGridAutoOrTemplateDimensions, type GridAutoOrTemplateBase, @@ -97,7 +101,9 @@ function getCellsCount(template: GridAutoOrTemplateBase | null): number { switch (template.type) { case 'DIMENSIONS': - return template.dimensions.length + return template.dimensions.reduce((acc, cur) => { + return acc + (cur.type === 'REPEAT' ? cur.times : 1) + }, 0) case 'FALLBACK': return 0 default: @@ -129,7 +135,7 @@ function gridCSSNumberToLabel(gridCSSNumber: GridDimension): string { function getLabelForAxis( fromDOM: GridDimension, index: number, - fromProps: GridAutoOrTemplateBase | null, + fromProps: GridAutoOrTemplateDimensions | null, ): string { const fromPropsAtIndex = toFirst(getFromPropsOptic(index), fromProps) return gridCSSNumberToLabel(defaultEither(fromDOM, fromPropsAtIndex)) @@ -143,11 +149,15 @@ export interface GridResizingControlProps { dimensionIndex: number axis: Axis containingFrame: CanvasRectangle - fromPropsAxisValues: GridAutoOrTemplateBase | null + fromPropsAxisValues: GridAutoOrTemplateDimensions | null padding: number | null + resizing: 'resize-target' | 'resize-generated' | 'not-resizing' + setResizingIndex: (v: number | null) => void } export const GridResizingControl = React.memo((props: GridResizingControlProps) => { + const { setResizingIndex } = props + const canvasOffset = useEditorState( Substores.canvasOffset, (store) => store.editor.canvas.roundedCanvasOffset, @@ -161,12 +171,10 @@ export const GridResizingControl = React.memo((props: GridResizingControlProps) const dispatch = useDispatch() const colorTheme = useColorTheme() - const [resizing, setResizing] = React.useState(false) - const mouseDownHandler = React.useCallback( (event: React.MouseEvent): void => { function mouseUpHandler() { - setResizing(false) + setResizingIndex(null) window.removeEventListener('mouseup', mouseUpHandler) } window.addEventListener('mouseup', mouseUpHandler) @@ -176,7 +184,7 @@ export const GridResizingControl = React.memo((props: GridResizingControlProps) canvasOffset, windowPoint({ x: event.nativeEvent.x, y: event.nativeEvent.y }), ) - setResizing(true) + setResizingIndex(props.dimensionIndex) dispatch([ CanvasActions.createInteractionSession( @@ -191,7 +199,7 @@ export const GridResizingControl = React.memo((props: GridResizingControlProps) event.stopPropagation() event.preventDefault() }, - [canvasOffset, dispatch, props.axis, props.dimensionIndex, scale], + [canvasOffset, dispatch, props.axis, props.dimensionIndex, scale, setResizingIndex], ) const { maybeClearHighlightsOnHoverEnd } = useMaybeHighlightElement() @@ -221,8 +229,8 @@ export const GridResizingControl = React.memo((props: GridResizingControlProps) display: 'flex', alignItems: props.axis === 'column' ? 'flex-start' : 'center', justifyContent: props.axis === 'column' ? 'center' : 'flex-start', - height: props.axis === 'column' && resizing ? shadowSize : '100%', - width: props.axis === 'row' && resizing ? shadowSize : '100%', + height: props.axis === 'column' && props.resizing !== 'not-resizing' ? shadowSize : '100%', + width: props.axis === 'row' && props.resizing !== 'not-resizing' ? shadowSize : '100%', position: 'relative', }} > @@ -245,7 +253,7 @@ export const GridResizingControl = React.memo((props: GridResizingControlProps) pointerEvents: 'initial', }} css={{ - opacity: resizing ? 1 : 0.5, + opacity: props.resizing !== 'not-resizing' ? 1 : 0.5, ':hover': { opacity: 1, }, @@ -260,7 +268,7 @@ export const GridResizingControl = React.memo((props: GridResizingControlProps) )}
{when( - resizing, + props.resizing !== 'not-resizing',
, @@ -309,6 +328,85 @@ export const GridResizing = React.memo((props: GridResizingProps) => { (store) => store.editor.canvas.scale, 'GridResizing canvasScale', ) + + const fromProps = React.useMemo((): GridAutoOrTemplateDimensions | null => { + if (props.fromPropsAxisValues?.type !== 'DIMENSIONS') { + return null + } + return { + type: 'DIMENSIONS', + dimensions: props.fromPropsAxisValues.dimensions.reduce( + (acc, cur): GridDiscreteDimension[] => { + if (cur.type === 'REPEAT') { + let expanded: GridDiscreteDimension[] = [] + for (let i = 0; i < cur.times; i++) { + expanded.push(...cur.value.filter((v) => v.type !== 'REPEAT')) + } + return acc.concat(...expanded) + } else { + return acc.concat(cur) + } + }, + [] as GridDiscreteDimension[], + ), + } + }, [props.fromPropsAxisValues]) + + const [resizingIndex, setResizingIndex] = React.useState(null) + + // These are the indexes of the elements that will resize too alongside the one at the index of + // `resizingIndex`. + const coresizingIndexes: number[] = React.useMemo(() => { + if (props.fromPropsAxisValues?.type !== 'DIMENSIONS' || resizingIndex == null) { + return [] + } + + // Build an array of coresizing indexes per element. + let coresizeIndexes: number[][][] = [] // This looks scary but it's not! It's just a list of indexes, containing a list of the indexes *per group element*. + // For example, 1fr repeat(3, 10px 20px) 1fr, will be represented as: + /** + * [ + * [ [0] ] + * [ [1, 3] [2, 4] ] + * [ [5] ] + * ] + */ + let elementCount = 0 // basically the expanded index + for (const dim of props.fromPropsAxisValues.dimensions) { + if (dim.type === 'REPEAT') { + let groupIndexes: number[][] = [] + // for each value push the coresize indexes as many times as the repeats counter + for (let valueIndex = 0; valueIndex < dim.value.length; valueIndex++) { + let repeatedValueIndexes: number[] = [] + for (let repeatIndex = 0; repeatIndex < dim.times; repeatIndex++) { + repeatedValueIndexes.push(elementCount + valueIndex + repeatIndex * dim.value.length) + } + groupIndexes.push(repeatedValueIndexes) + } + coresizeIndexes.push(groupIndexes) + elementCount += dim.value.length * dim.times // advance the counter as many times as the repeated values *combined* + } else { + coresizeIndexes.push([[elementCount]]) + elementCount++ + } + } + + // Now, expand the indexes calculated above so they "flatten out" to match the generated values + let expandedCoresizeIndexes: number[][] = [] + props.fromPropsAxisValues.dimensions.forEach((dim, dimIndex) => { + if (dim.type === 'REPEAT') { + for (let repeatIndex = 0; repeatIndex < dim.times * dim.value.length; repeatIndex++) { + const indexes = coresizeIndexes[dimIndex][repeatIndex % dim.value.length] + expandedCoresizeIndexes.push(indexes) + } + } else { + expandedCoresizeIndexes.push(coresizeIndexes[dimIndex][0]) + } + }) + + return expandedCoresizeIndexes[resizingIndex] ?? [] + }, [props.fromPropsAxisValues, resizingIndex]) + if (props.axisValues == null) { return null } @@ -347,9 +445,17 @@ export const GridResizing = React.memo((props: GridResizingProps) => { key={`grid-resizing-control-${dimensionIndex}`} dimensionIndex={dimensionIndex} dimension={dimension} - fromPropsAxisValues={props.fromPropsAxisValues} + fromPropsAxisValues={fromProps} axis={props.axis} containingFrame={props.containingFrame} + resizing={ + resizingIndex === dimensionIndex + ? 'resize-target' + : coresizingIndexes.includes(dimensionIndex) + ? 'resize-generated' + : 'not-resizing' + } + setResizingIndex={setResizingIndex} padding={ props.padding == null ? 0 diff --git a/editor/src/components/editor/store/store-deep-equality-instances.ts b/editor/src/components/editor/store/store-deep-equality-instances.ts index a360d4d1eeca..16385bd42779 100644 --- a/editor/src/components/editor/store/store-deep-equality-instances.ts +++ b/editor/src/components/editor/store/store-deep-equality-instances.ts @@ -265,7 +265,6 @@ import { combine9EqualityCalls, unionDeepEquality, combine11EqualityCalls, - combine16EqualityCalls, combine15EqualityCalls, } from '../../../utils/deep-equality' import { @@ -567,15 +566,15 @@ import type { GridCSSNumber, GridDimension, GridAutoFlow, + GridCSSRepeat, } from '../../inspector/common/css-utils' import { cssNumber, fontSettings, gridCSSKeyword, gridCSSNumber, + gridCSSRepeat, isCSSKeyword, - isGridCSSKeyword, - isGridCSSNumber, } from '../../inspector/common/css-utils' import type { ElementPaste, ProjectListing } from '../action-types' import { projectListing } from '../action-types' @@ -1993,15 +1992,40 @@ export const GridCSSKeywordKeepDeepEquality: KeepDeepEqualityCall = combine1EqualityCall( (dimension) => dimension, - unionDeepEquality( - GridCSSNumberKeepDeepEquality, - GridCSSKeywordKeepDeepEquality, - isGridCSSNumber, - isGridCSSKeyword, - ), + (oldValue: GridDimension, newValue: GridDimension): KeepDeepEqualityResult => { + switch (oldValue.type) { + case 'KEYWORD': + if (newValue.type === oldValue.type) { + return GridCSSKeywordKeepDeepEquality(oldValue, newValue) + } + break + case 'NUMBER': + if (newValue.type === oldValue.type) { + return GridCSSNumberKeepDeepEquality(oldValue, newValue) + } + break + case 'REPEAT': + if (newValue.type === oldValue.type) { + return GridCSSRepeatKeepDeepEquality(oldValue, newValue) + } + break + default: + assertNever(oldValue) + } + return keepDeepEqualityResult(newValue, false) + }, (dimension) => dimension, ) +export const GridCSSRepeatKeepDeepEquality: KeepDeepEqualityCall = + combine2EqualityCalls( + (p) => p.times, + NumberKeepDeepEquality, + (p) => p.value, + arrayDeepEquality(GridDimensionKeepDeepEquality), + gridCSSRepeat, + ) + export const GridAutoOrTemplateDimensionsKeepDeepEquality: KeepDeepEqualityCall = combine1EqualityCall( (value) => value.dimensions, diff --git a/editor/src/components/inspector/common/css-tree-utils.ts b/editor/src/components/inspector/common/css-tree-utils.ts index 46f7ea72ce25..4fd6d4de0ef3 100644 --- a/editor/src/components/inspector/common/css-tree-utils.ts +++ b/editor/src/components/inspector/common/css-tree-utils.ts @@ -16,53 +16,3 @@ export function cssTreeNodeValue(children: csstree.List): csstr children: children, } } - -export function expandCssTreeNodeValue(node: csstree.CssNode): csstree.Value { - return cssTreeNodeValue(expandNode(node)) -} - -function expandNode(node: csstree.CssNode): csstree.List { - if (node.type === 'Function' && node.name === 'repeat') { - // specific expansion for repeat functions - return expandRepeatFunction(node) - } else if (node.type === 'Value') { - // recursively expand children of Value nodes - const children = node.children.toArray() - const expanded = children.flatMap((child) => expandNode(child).toArray()) - return cssTreeNodeList(expanded) - } else { - // fallback to just the verbatim node - return cssTreeNodeList([node]) - } -} - -function expandRepeatFunction(fnNode: csstree.FunctionNode): csstree.List { - // The node should have 3+ children, because it should be [Number + Operator (,) + Value(s)] - // TODO this should be extended to support non-numeric, keyword repeaters - const children = fnNode.children.toArray() - if (children.length < 3) { - // just return the original children if the format is not supported - return fnNode.children - } - - // 1. parse the repeat number - const repeatNumber = children[0] - if (repeatNumber.type !== 'Number') { - return fnNode.children - } - const times = parseInt(repeatNumber.value) - - // 2. grab ALL the values to repeat (rightside of the comma), wrap them in a new Value node, - // and expand them so they support nested repeats - const valuesToRepeat = children.slice(2) - const nodeToRepeat = cssTreeNodeValue(cssTreeNodeList(valuesToRepeat)) - const expandedValues = expandNode(nodeToRepeat) - - // 3. append the expanded values N times, where N is the number of repeats parsed earlier - let result = new csstree.List() - for (let i = 0; i < times; i++) { - expandedValues.forEach((v) => result.appendData(v)) - } - - return result -} diff --git a/editor/src/components/inspector/common/css-utils.spec.ts b/editor/src/components/inspector/common/css-utils.spec.ts index 139eb037d072..243f75f26ec2 100644 --- a/editor/src/components/inspector/common/css-utils.spec.ts +++ b/editor/src/components/inspector/common/css-utils.spec.ts @@ -31,7 +31,6 @@ import { cssNumber, cssPixelLength, cssPixelLengthZero, - CSSSolidColor, cssTransformRotate, cssTransformRotateX, cssTransformRotateY, @@ -48,13 +47,11 @@ import { cssTransformTranslateY, cssTransformTranslateZ, cssUnitlessLength, - CSSUnknownArrayItem, defaultBGSize, defaultCSSGradientStops, defaultCSSRadialGradientSize, defaultCSSRadialOrConicGradientCenter, disabledFunctionName, - expandRepeatFunctions, parseBackgroundColor, parseBackgroundImage, parseBorderRadius, @@ -72,7 +69,6 @@ import { RegExpLibrary, toggleSimple, toggleStylePropPath, - tokenizeGridTemplate, } from './css-utils' describe('toggleStyleProp', () => { @@ -1809,57 +1805,3 @@ describe('printBackgroundSize', () => { `) }) }) - -describe('tokenizeGridTemplate', () => { - it('tokenizes the grid template strings (no units)', async () => { - expect(tokenizeGridTemplate('123 456 78 9')).toEqual(['123', '456', '78', '9']) - }) - it('tokenizes the grid template strings (with units)', async () => { - expect(tokenizeGridTemplate('123 456px 78 9rem')).toEqual(['123', '456px', '78', '9rem']) - }) - it('tokenizes the grid template strings (with some area names)', async () => { - expect(tokenizeGridTemplate('[foo] 123 456px 78 9rem')).toEqual([ - '[foo] 123', - '456px', - '78', - '9rem', - ]) - expect(tokenizeGridTemplate('123 [foo]456px 78 [bar] 9rem')).toEqual([ - '123', - '[foo] 456px', - '78', - '[bar] 9rem', - ]) - }) - it('tokenizes the grid template strings (with all area names)', async () => { - expect(tokenizeGridTemplate('[foo] 123 [bar]456px [baz] 78 [QUX]9rem')).toEqual([ - '[foo] 123', - '[bar] 456px', - '[baz] 78', - '[QUX] 9rem', - ]) - }) -}) - -describe('expandRepeatFunctions', () => { - it('expands repeat', async () => { - expect(expandRepeatFunctions('repeat(4, 1fr)')).toEqual('1fr 1fr 1fr 1fr') - }) - it('expands repeat with multiple units', () => { - expect(expandRepeatFunctions('repeat(2, 1fr 2fr 3fr)')).toEqual('1fr 2fr 3fr 1fr 2fr 3fr') - }) - it('expands repeat with spacing', () => { - expect(expandRepeatFunctions('repeat( 4 , 1fr )')).toEqual('1fr 1fr 1fr 1fr') - }) - it('expands repeat with decimals', () => { - expect(expandRepeatFunctions('repeat(4, 1.5fr)')).toEqual('1.5fr 1.5fr 1.5fr 1.5fr') - }) - it('expands nested', () => { - expect(expandRepeatFunctions('repeat(2, repeat(3, 1fr))')).toEqual('1fr 1fr 1fr 1fr 1fr 1fr') - - // Note: crazytown, I'm not even sure this is valid CSS *but still* - expect(expandRepeatFunctions('repeat(2, repeat(2, 1fr repeat(3, 2fr 4em)))')).toEqual( - '1fr 2fr 4em 2fr 4em 2fr 4em 1fr 2fr 4em 2fr 4em 2fr 4em 1fr 2fr 4em 2fr 4em 2fr 4em 1fr 2fr 4em 2fr 4em 2fr 4em', - ) - }) -}) diff --git a/editor/src/components/inspector/common/css-utils.ts b/editor/src/components/inspector/common/css-utils.ts index 2b361ff8d03e..5bee0ef90a05 100644 --- a/editor/src/components/inspector/common/css-utils.ts +++ b/editor/src/components/inspector/common/css-utils.ts @@ -21,7 +21,6 @@ import { isLeft, isRight, left, - leftMapEither, mapEither, right, traverseEither, @@ -46,7 +45,6 @@ import { jsExpressionValue, gridPositionValue, gridRange, - gridAutoOrTemplateDimensions, } from '../../../core/shared/element-template' import type { ModifiableAttribute } from '../../../core/shared/jsx-attributes' import { @@ -83,11 +81,7 @@ import { } from '../../../printer-parsers/css/css-parser-margin' import { parseFlex, printFlexAsAttributeValue } from '../../../printer-parsers/css/css-parser-flex' import { memoize } from '../../../core/shared/memoize' -import { parseCSSArray } from '../../../printer-parsers/css/css-parser-utils' -import type { ParseError } from '../../../utils/value-parser-utils' -import { descriptionParseError } from '../../../utils/value-parser-utils' import * as csstree from 'css-tree' -import { expandCssTreeNodeValue, parseCssTreeNodeValue } from './css-tree-utils' import type { IcnProps } from '../../../uuiui' var combineRegExp = function (regexpList: Array, flags?: string) { @@ -601,6 +595,13 @@ export type GridCSSKeyword = BaseGridDimension & { value: CSSKeyword } +export type GridCSSRepeat = { + type: 'REPEAT' + times: number + value: Array + areaName: null +} + export function isGridCSSKeyword(dim: GridDimension): dim is GridCSSKeyword { return dim.type === 'KEYWORD' } @@ -616,10 +617,23 @@ export function gridCSSKeyword( } } +export function gridCSSRepeat(times: number, value: GridDimension[]): GridCSSRepeat { + return { + type: 'REPEAT', + times: times, + value: value, + areaName: null, + } +} + export function isGridCSSNumber(dim: GridDimension): dim is GridCSSNumber { return dim.type === 'NUMBER' } +export function isGridCSSRepeat(dim: GridDimension): dim is GridCSSRepeat { + return dim.type === 'REPEAT' +} + export function gridCSSNumber(value: CSSNumber, areaName: string | null): GridCSSNumber { return { type: 'NUMBER', @@ -628,13 +642,23 @@ export function gridCSSNumber(value: CSSNumber, areaName: string | null): GridCS } } -export type GridDimension = GridCSSNumber | GridCSSKeyword +export type GridDiscreteDimension = GridCSSNumber | GridCSSKeyword +export type GridDimension = GridDiscreteDimension | GridCSSRepeat export function printGridCSSNumber(dim: GridDimension): string { - if (isGridCSSNumber(dim)) { - return `${dim.value.value}${dim.value.unit ?? ''}` + switch (dim.type) { + case 'KEYWORD': + return dim.value.value + case 'NUMBER': + return `${dim.value.value}${dim.value.unit ?? ''}` + case 'REPEAT': + if (dim.value.length === 0) { + return '' + } + return printGridCSSNumber(dim.value[0]) + default: + assertNever(dim) } - return dim.value.value } export function cssNumber(value: number, unit: CSSNumberUnit | null = null): CSSNumber { @@ -797,23 +821,29 @@ export function printCSSNumber( } } -export function printArrayGridDimension(array: Array): string { - return array - .map((dimension) => { - if (isGridCSSKeyword(dimension)) { - return dimension.value.value - } +export function printGridDimension(dimension: GridDimension): string { + switch (dimension.type) { + case 'KEYWORD': + return dimension.value.value + case 'NUMBER': const printed = printCSSNumber(dimension.value, null) const areaName = dimension.areaName != null ? `[${dimension.areaName}] ` : '' return `${areaName}${printed}` - }) - .join(' ') + case 'REPEAT': + return `repeat(${dimension.times}, ${printArrayGridDimensions(dimension.value)})` + default: + assertNever(dimension) + } +} + +export function printArrayGridDimensions(array: Array): string { + return array.map(printGridDimension).join(' ') } export function printGridAutoOrTemplateBase(input: GridAutoOrTemplateBase): string { switch (input.type) { case 'DIMENSIONS': - return printArrayGridDimension(input.dimensions) + return printArrayGridDimensions(input.dimensions) case 'FALLBACK': return input.value default: @@ -926,8 +956,8 @@ export function parseToCSSGridDimension(input: unknown): Either { return { ...value, - areaName: areaName, - } + areaName: value.type === 'REPEAT' ? null : areaName, + } as GridDimension }, parseCSSGrid(inputToParse)) } @@ -1046,68 +1076,89 @@ export function parseGridRange( } } -export function expandRepeatFunctions(str: string): string { - const node = parseCssTreeNodeValue(str) - const expanded = expandCssTreeNodeValue(node) - return csstree.generate(expanded) -} - -const reGridAreaNameBrackets = /^\[.+\]$/ - -function normalizeGridTemplate(template: string): string { - type normalizeFn = (s: string) => string - - const normalizePasses: normalizeFn[] = [ - // 1. expand repeat functions - expandRepeatFunctions, - // 2. normalize area names spacing - (s) => s.replace(/\]/g, '] ').replace(/\[/g, ' ['), - ] - - return normalizePasses.reduce((working, normalize) => normalize(working), template).trim() -} - -export function tokenizeGridTemplate(template: string): string[] { - let tokens: string[] = [] - let parts = normalizeGridTemplate(template).split(/\s+/) - while (parts.length > 0) { - const part = parts.shift()?.trim() - if (part == null) { - break - } - if (part.match(reGridAreaNameBrackets) != null && parts.length > 0) { - const withAreaName = `${part} ${parts.shift()}` - tokens.push(withAreaName) - } else { - tokens.push(part) - } - } - return tokens -} - export function parseGridAutoOrTemplateBase( input: unknown, ): Either { - function numberOrKeywordParse(inputToParse: unknown): Either { - const result = parseToCSSGridDimension(inputToParse) - return leftMapEither(descriptionParseError, result) - } if (typeof input === 'string') { - const parsedCSSArray = parseCSSArray([numberOrKeywordParse])(tokenizeGridTemplate(input)) - return bimapEither( - (error) => { - if (error.type === 'DESCRIPTION_PARSE_ERROR') { - return error.description - } else { - return error.toString() + const parsed = csstree.parse(input, { context: 'value' }) + if (parsed.type === 'Value') { + let nextAreaName: string | null = null + function getAreaName() { + const currentAreaName = nextAreaName != null ? `${nextAreaName}` : null + nextAreaName = null + return currentAreaName + } + + function parseChildren( + children: csstree.List, + ): Either { + let dimensions: GridDimension[] = [] + for (const child of children) { + switch (child.type) { + case 'Dimension': { + const parsedDimension = parseCSSNumber(`${child.value}${child.unit}`, 'AnyValid') + if (isRight(parsedDimension)) { + dimensions.push(gridCSSNumber(parsedDimension.value, getAreaName())) + } else { + return left('Invalid grid CSS dimension.') + } + break + } + case 'Identifier': { + if (isValidGridDimensionKeyword(child.name)) { + dimensions.push(gridCSSKeyword(cssKeyword(child.name), getAreaName())) + } else { + return left('Invalid grid CSS keyword.') + } + break + } + case 'Function': { + if (child.name.toLowerCase() === 'repeat') { + const repeatChildren = child.children.toArray() + const times = parseInt( + repeatChildren.find((c) => c.type === 'Number')?.value ?? '0', + ) + const values = new csstree.List().fromArray( + repeatChildren.filter( + (c) => + c.type === 'Dimension' || + c.type === 'Identifier' || + // We want to support area names too, because they are valid CSS + c.type === 'Brackets', + ), + ) + const parsedDimensions = parseChildren(values) + if (isRight(parsedDimensions)) { + dimensions.push(gridCSSRepeat(times, parsedDimensions.value)) + } else { + return left('Invalid grid CSS repeat values.') + } + } + break + } + case 'Brackets': { + // The next child will get this area name + nextAreaName = + child.children.toArray().find((c) => c.type === 'Identifier')?.name ?? null + break + } + default: + return left(`invalid grid child type ${child.type}`) + } } - }, - gridAutoOrTemplateDimensions, - parsedCSSArray, - ) - } else { - return left('Unknown input.') + return right(dimensions) + } + + const dimensions = parseChildren(parsed.children) + if (isRight(dimensions)) { + return right({ type: 'DIMENSIONS', dimensions: dimensions.value }) + } + + console.warn(`Invalid grid template, falling back: ${dimensions.value}.`) + return right({ type: 'FALLBACK', value: input }) + } } + return left('Invalid grid template input.') } export function parseDisplay(input: unknown): Either { diff --git a/editor/src/components/inspector/flex-section.tsx b/editor/src/components/inspector/flex-section.tsx index f158e65eebe1..87242505e12f 100644 --- a/editor/src/components/inspector/flex-section.tsx +++ b/editor/src/components/inspector/flex-section.tsx @@ -35,6 +35,7 @@ import type { CSSKeyword, CSSNumber, GridAutoFlow, + GridDiscreteDimension, UnknownOrEmptyInput, ValidGridDimensionKeyword, } from './common/css-utils' @@ -151,12 +152,13 @@ export const FlexSection = React.memo(() => { 'FlexSection grid', ) - const columns = React.useMemo(() => { + const columns = React.useMemo((): GridDiscreteDimension[] => { const autoCols: GridDimension[] = grid?.specialSizeMeasurements.containerGridProperties.gridAutoColumns?.type === 'DIMENSIONS' ? grid.specialSizeMeasurements.containerGridProperties.gridAutoColumns.dimensions : [] - return mergeGridTemplateValues({ + + const merged = mergeGridTemplateValues({ autoValues: autoCols, ...getGridTemplateAxisValues({ calculated: @@ -166,14 +168,28 @@ export const FlexSection = React.memo(() => { null, }), }) + + const reduced = merged.reduce((acc, cur) => { + if (cur.type === 'REPEAT') { + let expanded: GridDiscreteDimension[] = [] + for (let i = 0; i < cur.times; i++) { + expanded.push(...cur.value.filter((v) => v.type !== 'REPEAT')) + } + return acc.concat(...expanded) + } + return acc.concat(cur) + }, [] as GridDiscreteDimension[]) + + return reduced }, [grid]) - const rows = React.useMemo(() => { + const rows = React.useMemo((): GridDiscreteDimension[] => { const autoRows: GridDimension[] = grid?.specialSizeMeasurements.containerGridProperties.gridAutoRows?.type === 'DIMENSIONS' ? grid.specialSizeMeasurements.containerGridProperties.gridAutoRows.dimensions : [] - return mergeGridTemplateValues({ + + const merged = mergeGridTemplateValues({ autoValues: autoRows, ...getGridTemplateAxisValues({ calculated: grid?.specialSizeMeasurements.containerGridProperties.gridTemplateRows ?? null, @@ -181,6 +197,15 @@ export const FlexSection = React.memo(() => { grid?.specialSizeMeasurements.containerGridPropertiesFromProps.gridTemplateRows ?? null, }), }) + + const reduced = merged.reduce((acc, cur) => { + if (cur.type === 'REPEAT') { + return acc.concat(...cur.value.filter((v) => v.type !== 'REPEAT')) + } + return acc.concat(cur) + }, [] as GridDiscreteDimension[]) + + return reduced }, [grid]) return ( @@ -246,7 +271,7 @@ const TemplateDimensionControl = React.memo( title, }: { grid: ElementInstanceMetadata - values: GridDimension[] + values: GridDiscreteDimension[] axis: 'column' | 'row' title: string }) => { @@ -498,7 +523,7 @@ function AxisDimensionControl({ onUpdate, opener, }: { - value: GridDimension + value: GridDiscreteDimension index: number items: DropdownMenuItem[] axis: 'column' | 'row' @@ -594,9 +619,14 @@ function renameAreaInTemplateAtIndex( axis: 'column' | 'row', index: number, newAreaName: string | null, -) { - function renameDimension(dimension: GridDimension, idx: number) { - return idx === index ? { ...dimension, areaName: newAreaName } : dimension +): GridContainerProperties { + function renameDimension(dimension: GridDimension, idx: number): GridDimension { + return idx === index + ? ({ + ...dimension, + areaName: dimension.type === 'REPEAT' ? null : newAreaName, + } as GridDimension) + : dimension } const gridTemplateRows = @@ -622,14 +652,18 @@ function renameAreaInTemplateAtIndex( } } -function gridNumbersToTemplateString(values: GridDimension[]) { +function gridNumbersToTemplateString(values: GridDiscreteDimension[]) { return values .map((v) => { function getValue(): string { - if (isGridCSSKeyword(v)) { - return v.value.value + switch (v.type) { + case 'KEYWORD': + return v.value.value + case 'NUMBER': + return `${v.value.value}${v.value.unit != null ? `${v.value.unit}` : 'px'}` + default: + assertNever(v) } - return `${v.value.value}${v.value.unit != null ? `${v.value.unit}` : 'px'}` } const areaName = v.areaName != null ? `[${v.areaName}] ` : '' const value = getValue() From 5b1cd242260eaa78246ca465aea7bcaa6a0ce876 Mon Sep 17 00:00:00 2001 From: Balint Gabor <127662+gbalint@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:12:20 +0200 Subject: [PATCH 033/272] More grid refactor (#6384) **Problem:** Replace more dom query based logic from grid strategies, and nuke grid specific X behavior. **Commit Details:** (< vv pls delete this section if's not relevant) - Remove `getGridCellAtPoint` and replace its usage with `getGridCellUnderMouseFromMetadata` - Rewrite `getGridCellBoundsFromCanvas` to use metadata and canvas coordinates. - Nuke grid specific X behavior and all its helpers: let's just remove the grid cell positioning props when converting to absolute. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- .../strategies/grid-cell-bounds.ts | 94 ++------- .../grid-rearrange-keyboard-strategy.ts | 6 +- .../editor/shortcuts.spec.browser2.tsx | 188 +----------------- .../components/inspector/inspector-common.ts | 145 ++------------ 4 files changed, 42 insertions(+), 391 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts index 2439fb46efc6..e70b9aef07f4 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts @@ -1,14 +1,13 @@ import type { ElementPath } from 'utopia-shared/src/types' import type { ElementInstanceMetadata } from '../../../../core/shared/element-template' -import type { CanvasVector, WindowPoint, WindowRectangle } from '../../../../core/shared/math-utils' +import type { WindowPoint, WindowRectangle } from '../../../../core/shared/math-utils' import { + canvasPoint, isInfinityRectangle, offsetPoint, rectContainsPoint, - windowPoint, windowRectangle, } from '../../../../core/shared/math-utils' -import { canvasPointToWindowPoint } from '../../dom-lookup' import * as EP from '../../../../core/shared/element-path' import { getGlobalFramesOfGridCells, @@ -35,7 +34,7 @@ export function gridCellTargetId( export function getGridCellUnderMouseFromMetadata( grid: ElementInstanceMetadata, - canvasPoint: CanvasPoint, + point: CanvasPoint, ): TargetGridCellData | null { const gridCellGlobalFrames = getGlobalFramesOfGridCells(grid) @@ -43,17 +42,17 @@ export function getGridCellUnderMouseFromMetadata( return null } - return getGridCellUnderPoint(gridCellGlobalFrames, canvasPoint) + return getGridCellUnderPoint(gridCellGlobalFrames, point) } // TODO: we could optimize this with binary search, but huge grids are rare function getGridCellUnderPoint( gridCellGlobalFrames: GridCellGlobalFrames, - canvasPoint: CanvasPoint, + point: CanvasPoint, ): TargetGridCellData | null { for (let i = 0; i < gridCellGlobalFrames.length; i++) { for (let j = 0; j < gridCellGlobalFrames[i].length; j++) { - if (rectContainsPoint(gridCellGlobalFrames[i][j], canvasPoint)) { + if (rectContainsPoint(gridCellGlobalFrames[i][j], point)) { return { gridCellCoordinates: gridCellCoordinates(i + 1, j + 1), cellCanvasRectangle: gridCellGlobalFrames[i][j], @@ -64,97 +63,34 @@ function getGridCellUnderPoint( return null } -function isGridCellTargetId(id: string): boolean { - return id.startsWith(gridCellTargetIdPrefix) -} - -export function getGridCellAtPoint( - point: WindowPoint, - duplicating: boolean, -): { id: string; coordinates: GridCellCoordinates; cellWindowRectangle: WindowRectangle } | null { - function maybeRecursivelyFindCellAtPoint( - elements: Element[], - ): { element: Element; cellWindowRectangle: WindowRectangle } | null { - // If this used during duplication, the canvas controls will be in the way and we need to traverse the children too. - for (const element of elements) { - if (isGridCellTargetId(element.id)) { - const domRect = element.getBoundingClientRect() - const windowRect = windowRectangle(domRect) - if (rectContainsPoint(windowRect, point)) { - return { element: element, cellWindowRectangle: windowRect } - } - } - - if (duplicating) { - const child = maybeRecursivelyFindCellAtPoint(Array.from(element.children)) - if (child != null) { - return child - } - } - } - - return null - } - - const cellUnderMouse = maybeRecursivelyFindCellAtPoint( - document.elementsFromPoint(point.x, point.y), - ) - if (cellUnderMouse == null) { - return null - } - - const { element, cellWindowRectangle } = cellUnderMouse - const row = element.getAttribute('data-grid-row') - const column = element.getAttribute('data-grid-column') - - return { - id: element.id, - cellWindowRectangle: cellWindowRectangle, - coordinates: gridCellCoordinates( - row == null ? 0 : parseInt(row), - column == null ? 0 : parseInt(column), - ), - } -} - -const GRID_BOUNDS_TOLERANCE = 5 // px - export function getGridCellBoundsFromCanvas( cell: ElementInstanceMetadata, - canvasScale: number, - canvasOffset: CanvasVector, + grid: ElementInstanceMetadata, ) { const cellFrame = cell.globalFrame if (cellFrame == null || isInfinityRectangle(cellFrame)) { return null } - const canvasFrameWidth = cellFrame.width * canvasScale - const canvasFrameHeight = cellFrame.height * canvasScale - - const cellOriginPoint = offsetPoint( - canvasPointToWindowPoint(cellFrame, canvasScale, canvasOffset), - windowPoint({ x: GRID_BOUNDS_TOLERANCE, y: GRID_BOUNDS_TOLERANCE }), - ) - const cellOrigin = getGridCellAtPoint(cellOriginPoint, true) + const cellOrigin = getGridCellUnderMouseFromMetadata(grid, cellFrame) if (cellOrigin == null) { return null } const cellEndPoint = offsetPoint( - cellOriginPoint, - windowPoint({ - x: canvasFrameWidth - GRID_BOUNDS_TOLERANCE, - y: canvasFrameHeight - GRID_BOUNDS_TOLERANCE, + cellFrame, + canvasPoint({ + x: cellFrame.width, + y: cellFrame.height, }), ) - const cellEnd = getGridCellAtPoint(cellEndPoint, true) + const cellEnd = getGridCellUnderMouseFromMetadata(grid, cellEndPoint) if (cellEnd == null) { return null } - const cellOriginCoords = cellOrigin.coordinates - const cellEndCoords = cellEnd.coordinates + const cellOriginCoords = cellOrigin.gridCellCoordinates + const cellEndCoords = cellEnd.gridCellCoordinates const cellWidth = cellEndCoords.column - cellOriginCoords.column + 1 const cellHeight = cellEndCoords.row - cellOriginCoords.row + 1 diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts index 3807c3d9b71d..ec4a6e55511f 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts @@ -54,11 +54,7 @@ export function gridRearrangeResizeKeyboardStrategy( } const gridTemplate = grid.specialSizeMeasurements.containerGridProperties - const initialCellBounds = getGridCellBoundsFromCanvas( - cell, - canvasState.scale, - canvasState.canvasOffset, - ) + const initialCellBounds = getGridCellBoundsFromCanvas(cell, grid) if (initialCellBounds == null) { return null } diff --git a/editor/src/components/editor/shortcuts.spec.browser2.tsx b/editor/src/components/editor/shortcuts.spec.browser2.tsx index 0e1342631ae7..f80afae9f7d1 100644 --- a/editor/src/components/editor/shortcuts.spec.browser2.tsx +++ b/editor/src/components/editor/shortcuts.spec.browser2.tsx @@ -301,11 +301,6 @@ export var storyboard = ( data-testid='child' style={{ backgroundColor: '#0162ff', - position: 'absolute', - left: 13, - top: 19, - width: 74, - height: 59, gridColumn: 3, gridRow: 3, }} @@ -319,194 +314,33 @@ export var storyboard = ( ) await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/child')]) - await pressKey('x') + await pressKey('x') // convert it to absolute { const { position, gridRow, gridColumn, width, height } = editor.renderedDOM.getByTestId('child').style expect({ position, gridRow, gridColumn, width, height }).toEqual({ - gridColumn: '3', - gridRow: '3', - height: '', - position: '', - width: '', - }) - } - - await pressKey('x') // convert it back to absolute - - { - const { position, gridRow, gridColumn, width, height, top, left } = - editor.renderedDOM.getByTestId('child').style - expect({ position, gridRow, gridColumn, width, height, top, left }).toEqual({ - gridColumn: '3', - gridRow: '3', - height: '90.5px', - left: '0px', + gridColumn: '', + gridRow: '', + height: '91px', position: 'absolute', - top: '0px', width: '104px', }) } - }) - it('can place element spanning multiple grid cells into the grid and take it out', async () => { - const editor = await renderTestEditorWithCode( - `import { Scene, Storyboard } from 'utopia-api' - -export var storyboard = ( - - -
-
-
- - -) -`, - 'await-first-dom-report', - ) - - await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/child')]) - await pressKey('x') - - { - const { position, gridRow, gridColumn, width, height } = - editor.renderedDOM.getByTestId('child').style - expect({ position, gridRow, gridColumn, width, height }).toEqual({ - gridColumn: '2 / 5', - gridRow: '2 / 4', - height: '', - position: '', - width: '', - }) - } - - await pressKey('x') // convert it back to absolute + await pressKey('x') // convert it back to flow with size kept (but no gridColumn/Row or other grid specific prop is set yet) { const { position, gridRow, gridColumn, width, height, top, left } = editor.renderedDOM.getByTestId('child').style expect({ position, gridRow, gridColumn, width, height, top, left }).toEqual({ - gridColumn: '2', - gridRow: '2', - height: '183px', - left: '0px', - position: 'absolute', - top: '0px', - width: '315.5px', - }) - } - }) - - it('can place element with no grid positioning props set', async () => { - const editor = await renderTestEditorWithCode( - `import { Scene, Storyboard } from 'utopia-api' - -export var storyboard = ( - - -
-
-
- - -) -`, - 'await-first-dom-report', - ) - - await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/child')]) - await pressKey('x') - - { - const { position, gridRow, gridColumn, width, height } = - editor.renderedDOM.getByTestId('child').style - expect({ position, gridRow, gridColumn, width, height }).toEqual({ - gridColumn: '2 / 4', - gridRow: '2 / 4', - height: '', + gridColumn: '', + gridRow: '', + height: '91px', + left: '', position: '', - width: '', + top: '', + width: '104px', }) } }) diff --git a/editor/src/components/inspector/inspector-common.ts b/editor/src/components/inspector/inspector-common.ts index 69c4c92638b6..8718b4106c3f 100644 --- a/editor/src/components/inspector/inspector-common.ts +++ b/editor/src/components/inspector/inspector-common.ts @@ -34,12 +34,7 @@ import { optionalMap } from '../../core/shared/optional-utils' import type { CSSProperties } from 'react' import type { CanvasCommand } from '../canvas/commands/commands' import { deleteProperties } from '../canvas/commands/delete-properties-command' -import { - propertyToDelete, - propertyToSet, - setProperty, - updateBulkProperties, -} from '../canvas/commands/set-property-command' +import { setProperty } from '../canvas/commands/set-property-command' import { addContainLayoutIfNeeded } from '../canvas/commands/add-contain-layout-if-needed-command' import { setCssLengthProperty, @@ -617,6 +612,19 @@ export const nukeAllAbsolutePositioningPropsCommands = ( ] } +export const nukeGridCellPositioningPropsCommands = (path: ElementPath): Array => { + return [ + deleteProperties('always', path, [ + PP.create('style', 'gridColumn'), + PP.create('style', 'gridColumnStart'), + PP.create('style', 'gridColumnEnd'), + PP.create('style', 'gridRow'), + PP.create('style', 'gridRowStart'), + PP.create('style', 'gridRowEnd'), + ]), + ] +} + export type FixedHugFill = | { type: 'fixed'; value: CSSNumber } | { type: 'fill'; value: CSSNumber } @@ -1235,16 +1243,6 @@ export function toggleAbsolutePositioningCommands( return maybeGroupConversionCommands } - const maybeGridElementConversionCommands = gridChildAbsolutePositionConversionCommands( - jsxMetadata, - elementPathTree, - elementPath, - canvasContext, - ) - if (maybeGridElementConversionCommands != null) { - return maybeGridElementConversionCommands - } - const element = MetadataUtils.findElementByElementPath(jsxMetadata, elementPath) if (element == null) { return [] @@ -1327,6 +1325,7 @@ export function getConvertIndividualElementToAbsoluteCommands( // First round the frame so that we don't end up with half pixel values const roundedFrame = roundRectangleToNearestWhole(frame) return [ + ...nukeGridCellPositioningPropsCommands(target), ...sizeToDimensionsFromFrame(jsxMetadata, elementPathTree, target, roundedFrame), ...addPositionAbsoluteTopLeft(target, roundedFrame, parentFlexDirection), ] @@ -1417,117 +1416,3 @@ export function getConstraintsIncludingImplicitForElement( export function isHuggingParent(element: ElementInstanceMetadata, property: 'width' | 'height') { return element.specialSizeMeasurements.computedHugProperty[property] != null } - -interface ContainedGridPositioning { - type: 'contained' - gridRow: number - gridColumn: number -} - -interface SpanningGridPositioning { - type: 'span' - gridRowStart: number - gridRowEnd: number - gridColumnStart: number - gridColumnEnd: number -} - -type DetectedGridPositioning = ContainedGridPositioning | SpanningGridPositioning - -function getGridElementBounds( - cell: ElementInstanceMetadata, - canvasContext: { scale: number; offset: CanvasVector }, -): DetectedGridPositioning | null { - const initialCellBounds = getGridCellBoundsFromCanvas( - cell, - canvasContext.scale, - canvasContext.offset, - ) - - if (initialCellBounds == null) { - return null - } - - if (initialCellBounds.height > 1 || initialCellBounds.width > 1) { - return { - type: 'span', - gridRowStart: initialCellBounds.row, - gridRowEnd: initialCellBounds.row + initialCellBounds.height, - gridColumnStart: initialCellBounds.column, - gridColumnEnd: initialCellBounds.column + initialCellBounds.width, - } - } - - return { - type: 'contained', - gridRow: initialCellBounds.row, - gridColumn: initialCellBounds.column, - } -} - -function gridChildAbsolutePositionConversionCommands( - jsxMetadata: ElementInstanceMetadataMap, - elementPathTree: ElementPathTrees, - elementPath: ElementPath, - canvasContext: { scale: number; offset: CanvasVector }, -): CanvasCommand[] | null { - if (!MetadataUtils.isGridCell(jsxMetadata, elementPath)) { - return null - } - - const instance = MetadataUtils.findElementByElementPath(jsxMetadata, elementPath) - if (instance == null) { - return null - } - - const cellBounds = getGridElementBounds(instance, canvasContext) - if (cellBounds == null) { - return null - } - - if (MetadataUtils.isPositionAbsolute(instance)) { - const gridPositioningProps = - cellBounds.type === 'contained' - ? [ - { prop: PP.create('style', 'gridRow'), value: cellBounds.gridRow }, - { prop: PP.create('style', 'gridColumn'), value: cellBounds.gridColumn }, - ] - : cellBounds.type === 'span' - ? [ - { prop: PP.create('style', 'gridRowStart'), value: cellBounds.gridRowStart }, - { prop: PP.create('style', 'gridRowEnd'), value: cellBounds.gridRowEnd }, - { prop: PP.create('style', 'gridColumnStart'), value: cellBounds.gridColumnStart }, - { prop: PP.create('style', 'gridColumnEnd'), value: cellBounds.gridColumnEnd }, - ] - : assertNever(cellBounds) - - return [ - ...nukeAllAbsolutePositioningPropsCommands(elementPath), - updateBulkProperties('always', elementPath, [ - propertyToDelete(PP.create('style', 'width')), - propertyToDelete(PP.create('style', 'height')), - ...gridElementProps.map(propertyToDelete), - ...gridPositioningProps.map(({ prop, value }) => propertyToSet(prop, value)), - ]), - ] - } - - const { row, column } = - cellBounds.type === 'contained' - ? { row: cellBounds.gridRow, column: cellBounds.gridColumn } - : cellBounds.type === 'span' - ? { row: cellBounds.gridRowStart, column: cellBounds.gridColumnStart } - : assertNever(cellBounds) - - return [ - ...sizeToVisualDimensions(jsxMetadata, elementPathTree, elementPath), - updateBulkProperties('always', elementPath, [ - ...gridElementProps.map(propertyToDelete), - propertyToSet(PP.create('style', 'gridRow'), row), - propertyToSet(PP.create('style', 'gridColumn'), column), - propertyToSet(PP.create('style', 'position'), 'absolute'), - propertyToSet(PP.create('style', 'top'), 0), - propertyToSet(PP.create('style', 'left'), 0), - ]), - ] -} From db198f6e84eff194e3310d65d47576bc55645f25 Mon Sep 17 00:00:00 2001 From: Balint Gabor <127662+gbalint@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:48:54 +0200 Subject: [PATCH 034/272] Remove dom queries from grid rearrange move strategies (#6386) **Problem:** Followup to https://github.com/concrete-utopia/utopia/pull/6384 Rewrite `runGridRearrangeMove` and remove dom queries and calculation in window rectangles. **Commit Details:** - `runGridRearrangeRemove` called `getCellWindowRect`, remove that function and replace it with a new one working from the result of `getGlobalFramesOfGridCells`. - I removed plenty of canvas<->window conversions and could remove canvasScale and canvasOffset parameters too. - Some test results were changed by ~1 pixel, I believe this is a result of the removed back and forth conversions between canvas and window. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- .../strategies/grid-cell-bounds.ts | 11 --- .../strategies/grid-helpers.ts | 85 +++++++------------ .../grid-rearrange-move-duplicate-strategy.ts | 2 - ...-rearrange-move-strategy.spec.browser2.tsx | 16 ++-- .../grid-rearrange-move-strategy.ts | 2 - 5 files changed, 37 insertions(+), 79 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts index e70b9aef07f4..1c7827d5d01a 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts @@ -111,14 +111,3 @@ export function getGridPlaceholderDomElementFromCoordinates(params: { `[data-grid-row="${params.row}"]` + `[data-grid-column="${params.column}"]`, ) } - -export function getCellWindowRect(coords: GridCellCoordinates): WindowRectangle | null { - const element = getGridPlaceholderDomElementFromCoordinates(coords) - if (element == null) { - return null - } - - const domRect = element!.getBoundingClientRect() - const windowRect = windowRectangle(domRect) - return windowRect -} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index 4030c029d901..5b0aa20bad71 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -13,19 +13,14 @@ import { type GridElementProperties, type GridPosition, } from '../../../../core/shared/element-template' -import type { - CanvasRectangle, - CanvasVector, - WindowRectangle, -} from '../../../../core/shared/math-utils' +import type { CanvasRectangle, CanvasVector } from '../../../../core/shared/math-utils' import { canvasPoint, canvasRectangle, + canvasVector, isInfinityRectangle, offsetPoint, - scaleVector, windowPoint, - windowVector, } from '../../../../core/shared/math-utils' import * as PP from '../../../../core/shared/property-path' import { absolute } from '../../../../utils/utils' @@ -35,15 +30,10 @@ import { deleteProperties } from '../../commands/delete-properties-command' import { reorderElement } from '../../commands/reorder-element-command' import { setCssLengthProperty } from '../../commands/set-css-length-command' import { setProperty } from '../../commands/set-property-command' -import { canvasPointToWindowPoint } from '../../dom-lookup' -import type { GridCustomStrategyState, InteractionCanvasState } from '../canvas-strategy-types' +import type { GridCustomStrategyState } from '../canvas-strategy-types' import type { DragInteractionData } from '../interaction-state' import type { GridCellCoordinates } from './grid-cell-bounds' -import { - getCellWindowRect, - getGridCellUnderMouseFromMetadata, - gridCellCoordinates, -} from './grid-cell-bounds' +import { getGridCellUnderMouseFromMetadata, gridCellCoordinates } from './grid-cell-bounds' import { memoize } from '../../../../core/shared/memoize' export function runGridRearrangeMove( @@ -51,8 +41,6 @@ export function runGridRearrangeMove( selectedElement: ElementPath, jsxMetadata: ElementInstanceMetadataMap, interactionData: DragInteractionData, - canvasScale: number, - canvasOffset: CanvasVector, customState: GridCustomStrategyState, ): { commands: CanvasCommand[] @@ -209,15 +197,14 @@ export function runGridRearrangeMove( switch (moveType) { case 'rearrange': { const targetRootCell = gridCellCoordinates(row.start, column.start) - const windowRect = getCellWindowRect(targetRootCell) + const canvasRect = getGlobalFrameOfGridCell(containerMetadata, targetRootCell) const absoluteMoveCommands = - windowRect == null + canvasRect == null ? [] : gridChildAbsoluteMoveCommands( MetadataUtils.findElementByElementPath(jsxMetadata, targetElement), - windowRect, + canvasRect, interactionData, - { scale: canvasScale, canvasOffset: canvasOffset }, ) return { commands: [ @@ -427,9 +414,8 @@ function asMaybeNamedAreaOrValue( function gridChildAbsoluteMoveCommands( targetMetadata: ElementInstanceMetadata | null, - targetCellWindowRect: WindowRectangle, + targetCellRect: CanvasRectangle, dragInteractionData: DragInteractionData, - canvasContext: Pick, ): CanvasCommand[] { if ( targetMetadata == null || @@ -440,45 +426,20 @@ function gridChildAbsoluteMoveCommands( return [] } - const targetFrameWindow = canvasPointToWindowPoint( - canvasPoint({ - x: targetMetadata.globalFrame.x, - y: targetMetadata.globalFrame.y, - }), - canvasContext.scale, - canvasContext.canvasOffset, - ) - - const dragStartWindow = canvasPointToWindowPoint( - canvasPoint({ - x: dragInteractionData.originalDragStart.x, - y: dragInteractionData.originalDragStart.y, - }), - canvasContext.scale, - canvasContext.canvasOffset, - ) - const offsetInTarget = windowPoint({ - x: dragStartWindow.x - targetFrameWindow.x, - y: dragStartWindow.y - targetFrameWindow.y, + x: dragInteractionData.originalDragStart.x - targetMetadata.globalFrame.x, + y: dragInteractionData.originalDragStart.y - targetMetadata.globalFrame.y, }) - const dragWindowOffset = canvasPointToWindowPoint( - offsetPoint( - dragInteractionData.originalDragStart, - dragInteractionData.drag ?? canvasPoint({ x: 0, y: 0 }), - ), - canvasContext.scale, - canvasContext.canvasOffset, + const dragOffset = offsetPoint( + dragInteractionData.originalDragStart, + dragInteractionData.drag ?? canvasPoint({ x: 0, y: 0 }), ) - const offset = scaleVector( - windowVector({ - x: dragWindowOffset.x - targetCellWindowRect.x - offsetInTarget.x, - y: dragWindowOffset.y - targetCellWindowRect.y - offsetInTarget.y, - }), - 1 / canvasContext.scale, - ) + const offset = canvasVector({ + x: dragOffset.x - targetCellRect.x - offsetInTarget.x, + y: dragOffset.y - targetCellRect.y - offsetInTarget.y, + }) return [ deleteProperties('always', targetMetadata.elementPath, [ @@ -631,6 +592,18 @@ function getGlobalFramesOfGridCellsInner( export const getGlobalFramesOfGridCells = memoize(getGlobalFramesOfGridCellsInner) +export function getGlobalFrameOfGridCell( + grid: ElementInstanceMetadata, + coords: GridCellCoordinates, +): CanvasRectangle | null { + const gridCellGlobalFrames = getGlobalFramesOfGridCells(grid) + if (gridCellGlobalFrames == null) { + return null + } + + return gridCellGlobalFrames[coords.row - 1][coords.column - 1] ?? null +} + function gridTemplateToNumbers(gridTemplate: GridTemplate | null): Array | null { if (gridTemplate?.type !== 'DIMENSIONS') { return null diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts index 24b363140066..8418611cdc88 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts @@ -83,8 +83,6 @@ export const gridRearrangeMoveDuplicateStrategy: CanvasStrategyFactory = ( selectedElement, canvasState.startingMetadata, interactionSession.interactionData, - canvasState.scale, - canvasState.canvasOffset, customState.grid, ) if (moveCommands.length === 0) { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx index c942f983fa55..584a9eed36a3 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.spec.browser2.tsx @@ -287,8 +287,8 @@ export var storyboard = ( expect({ top, left, gridColumn, gridRow }).toEqual({ gridColumn: '1', gridRow: '1', - left: '36px', - top: '40px', + left: '37px', + top: '41px', }) } }) @@ -329,8 +329,8 @@ export var storyboard = ( expect({ top, left, gridColumn, gridRow }).toEqual({ gridColumn: '1', gridRow: '1', - left: '136.5px', - top: '140.5px', + left: '137px', + top: '141px', }) } }) @@ -369,8 +369,8 @@ export var storyboard = ( expect({ top, left, gridColumn, gridRow }).toEqual({ gridColumn: '2', gridRow: '2', - left: '25.5px', - top: '36px', + left: '26.5px', + top: '37px', }) } }) @@ -452,8 +452,8 @@ export var storyboard = ( expect({ top, left, gridColumn, gridRow }).toEqual({ gridColumn: '1', gridRow: '1', - left: '60.5px', - top: '61px', + left: '61.5px', + top: '62px', }) } }) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts index 1a1f9c02182f..41a8396967b6 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts @@ -180,8 +180,6 @@ function getCommandsAndPatchForGridRearrange( selectedElement, canvasState.startingMetadata, interactionData, - canvasState.scale, - canvasState.canvasOffset, customState.grid, ) From 96795b03477f987ed5f86e3b8af4c89d7dab57e0 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:26:55 +0200 Subject: [PATCH 035/272] Grids: presetve repeat from inspector changes (#6388) **Problem:** As a followup to #6380 , we should preserve `repeat` functions & co. when altering the grid template from the inspector inputs too. **Fix:** 1. Factored out the logic to alter a table from the resize strategy to helper functions in `grid-helpers.ts` 2. Adjusted the logic to support removing elements too 3. Refactored the callbacks in the inspector section to use the new helpers Fixes #6387 --- .../strategies/grid-helpers.ts | 180 ++++++++++++++++- .../strategies/resize-grid-strategy.ts | 78 +------- .../canvas/controls/grid-controls.tsx | 48 +---- .../components/inspector/common/css-utils.ts | 12 +- .../inspector/flex-section.spec.browser2.tsx | 75 ++++++- .../src/components/inspector/flex-section.tsx | 184 ++++++++++-------- 6 files changed, 379 insertions(+), 198 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index 5b0aa20bad71..a1651088f729 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -24,7 +24,13 @@ import { } from '../../../../core/shared/math-utils' import * as PP from '../../../../core/shared/property-path' import { absolute } from '../../../../utils/utils' -import { cssNumber, isCSSKeyword } from '../../../inspector/common/css-utils' +import type { GridDimension } from '../../../inspector/common/css-utils' +import { + cssNumber, + gridCSSRepeat, + isCSSKeyword, + isGridCSSRepeat, +} from '../../../inspector/common/css-utils' import type { CanvasCommand } from '../../commands/commands' import { deleteProperties } from '../../commands/delete-properties-command' import { reorderElement } from '../../commands/reorder-element-command' @@ -35,6 +41,8 @@ import type { DragInteractionData } from '../interaction-state' import type { GridCellCoordinates } from './grid-cell-bounds' import { getGridCellUnderMouseFromMetadata, gridCellCoordinates } from './grid-cell-bounds' import { memoize } from '../../../../core/shared/memoize' +import { mapDropNulls } from '../../../../core/shared/array-utils' +import { assertNever } from '../../../../core/shared/utils' export function runGridRearrangeMove( targetElement: ElementPath, @@ -620,3 +628,173 @@ function gridTemplateToNumbers(gridTemplate: GridTemplate | null): Array return result } + +type DimensionIndexes = { + originalIndex: number // the index of this element in the original values + repeatedIndex: number // the index of this element, if it's generated via a repeat, inside the repeated values array definition +} + +export type ExpandedGridDimension = GridDimension & { + indexes: DimensionIndexes +} + +function expandedGridDimension( + dim: GridDimension, + originalIndex: number, + repeatedIndex: number = 0, +): ExpandedGridDimension { + return { + ...dim, + indexes: { + originalIndex: originalIndex, + repeatedIndex: repeatedIndex, + }, + } +} + +export function expandGridDimensions(template: GridDimension[]): ExpandedGridDimension[] { + // Expanded representation of the original values, where repeated elements are serialized. + // Each element also contains the indexes information to be used later on to build the resized + // template string. + return template.reduce((acc, cur, index) => { + if (isGridCSSRepeat(cur)) { + const repeatGroup = cur.value.map((dim, repeatedIndex) => + expandedGridDimension(dim, index, repeatedIndex), + ) + let expanded: ExpandedGridDimension[] = [] + for (let i = 0; i < cur.times; i++) { + expanded.push(...repeatGroup) + } + return [...acc, ...expanded] + } else { + return [...acc, expandedGridDimension(cur, index)] + } + }, [] as ExpandedGridDimension[]) +} + +function alterGridTemplateDimensions(params: { + originalValues: GridDimension[] + target: ExpandedGridDimension + patch: AlterGridTemplateDimensionPatch +}): GridDimension[] { + return mapDropNulls((dim, index) => { + if (index !== params.target.indexes.originalIndex) { + return dim + } else if (isGridCSSRepeat(dim)) { + const repeatedIndex = params.target.indexes.repeatedIndex ?? 0 + const before = dim.value.slice(0, repeatedIndex) + const after = dim.value.slice(repeatedIndex + 1) + switch (params.patch.type) { + case 'REMOVE': + if (before.length + after.length === 0) { + return null + } + return gridCSSRepeat(dim.times, [...before, ...after]) + case 'REPLACE': + return gridCSSRepeat(dim.times, [...before, params.patch.newValue, ...after]) + default: + assertNever(params.patch) + } + } else { + switch (params.patch.type) { + case 'REPLACE': + return params.patch.newValue + case 'REMOVE': + return null + default: + assertNever(params.patch) + } + } + }, params.originalValues) +} + +export type ReplaceGridDimensionPatch = { + type: 'REPLACE' + newValue: GridDimension +} + +export type RemoveGridDimensionPatch = { + type: 'REMOVE' +} + +export type AlterGridTemplateDimensionPatch = ReplaceGridDimensionPatch | RemoveGridDimensionPatch + +export function replaceGridTemplateDimensionAtIndex( + template: GridDimension[], + expanded: ExpandedGridDimension[], + index: number, + newValue: GridDimension, +): GridDimension[] { + return alterGridTemplateDimensions({ + originalValues: template, + target: expanded[index], + patch: { + type: 'REPLACE', + newValue: newValue, + }, + }) +} + +export function removeGridTemplateDimensionAtIndex( + template: GridDimension[], + expanded: ExpandedGridDimension[], + index: number, +): GridDimension[] { + return alterGridTemplateDimensions({ + originalValues: template, + target: expanded[index], + patch: { + type: 'REMOVE', + }, + }) +} + +// Return an array of related indexes to a given index inside a grid's template dimensions. +export function getGridRelatedIndexes(params: { + template: GridDimension[] + index: number +}): number[] { + let relatedIndexes: number[][][] = [] // This looks scary but it's not! It's just a list of indexes, containing a list of the indexes *per group element*. + // For example, 1fr repeat(3, 10px 20px) 1fr, will be represented as: + /** + * [ + * [ [0] ] + * [ [1, 3] [2, 4] ] + * [ [5] ] + * ] + */ + let elementCount = 0 // basically the expanded index + for (const dim of params.template) { + if (dim.type === 'REPEAT') { + let groupIndexes: number[][] = [] + // for each value push the related indexes as many times as the repeats counter + for (let valueIndex = 0; valueIndex < dim.value.length; valueIndex++) { + let repeatedValueIndexes: number[] = [] + for (let repeatIndex = 0; repeatIndex < dim.times; repeatIndex++) { + repeatedValueIndexes.push(elementCount + valueIndex + repeatIndex * dim.value.length) + } + groupIndexes.push(repeatedValueIndexes) + } + relatedIndexes.push(groupIndexes) + elementCount += dim.value.length * dim.times // advance the counter as many times as the repeated values *combined* + } else { + relatedIndexes.push([[elementCount]]) + elementCount++ + } + } + + // Now, expand the indexes calculated above so they "flatten out" to match the generated values + let expandedRelatedIndexes: number[][] = [] + params.template.forEach((dim, dimIndex) => { + if (dim.type === 'REPEAT') { + for (let repeatIndex = 0; repeatIndex < dim.times * dim.value.length; repeatIndex++) { + const indexes = relatedIndexes[dimIndex][repeatIndex % dim.value.length] + expandedRelatedIndexes.push(indexes) + } + } else { + expandedRelatedIndexes.push(relatedIndexes[dimIndex][0]) + } + }) + + return expandedRelatedIndexes[params.index] ?? [] +} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts index 1489e1b20d2b..b99bbaf32607 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts @@ -25,9 +25,7 @@ import type { GridDimension } from '../../../../components/inspector/common/css- import { cssNumber, gridCSSNumber, - gridCSSRepeat, isGridCSSNumber, - isGridCSSRepeat, printArrayGridDimensions, } from '../../../../components/inspector/common/css-utils' import { toFirst } from '../../../../core/shared/optics/optic-utilities' @@ -36,6 +34,7 @@ import type { Either } from '../../../../core/shared/either' import { foldEither, isLeft, isRight } from '../../../../core/shared/either' import { roundToNearestWhole } from '../../../../core/shared/math-utils' import type { GridAutoOrTemplateBase } from '../../../../core/shared/element-template' +import { expandGridDimensions, replaceGridTemplateDimensionAtIndex } from './grid-helpers' export const resizeGridStrategy: CanvasStrategyFactory = ( canvasState: InteractionCanvasState, @@ -116,24 +115,7 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( return emptyStrategyApplicationResult } - // Expanded representation of the original values, where repeated elements are serialized. - // Each element also contains the indexes information to be used later on to build the resized - // template string. - const expandedOriginalValues = originalValues.dimensions.reduce((acc, cur, index) => { - if (isGridCSSRepeat(cur)) { - const repeatGroup = cur.value.map((dim, repeatedIndex) => - expandedGridDimension(dim, index, repeatedIndex), - ) - let expanded: ExpandedGridDimension[] = [] - for (let i = 0; i < cur.times; i++) { - expanded.push(...repeatGroup) - } - return [...acc, ...expanded] - } else { - return [...acc, expandedGridDimension(cur, index)] - } - }, [] as ExpandedGridDimension[]) - + const expandedOriginalValues = expandGridDimensions(originalValues.dimensions) const mergedValues: GridAutoOrTemplateBase = { type: calculatedValues.type, dimensions: calculatedValues.dimensions.map((dim, index) => { @@ -181,11 +163,12 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( areaName, ) - const newDimensions = buildResizedDimensions({ - newValue: newValue, - originalValues: originalValues.dimensions, - target: expandedOriginalValues[control.columnOrRow], - }) + const newDimensions = replaceGridTemplateDimensionAtIndex( + originalValues.dimensions, + expandedOriginalValues, + control.columnOrRow, + newValue, + ) const propertyValueAsString = printArrayGridDimensions(newDimensions) @@ -207,51 +190,6 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( } } -type DimensionIndexes = { - originalIndex: number // the index of this element in the original values - repeatedIndex: number // the index of this element, if it's generated via a repeat, inside the repeated values array definition -} - -function expandedGridDimension( - dim: GridDimension, - originalIndex: number, - repeatedIndex: number = 0, -): ExpandedGridDimension { - return { - ...dim, - indexes: { - originalIndex: originalIndex, - repeatedIndex: repeatedIndex, - }, - } -} - -type ExpandedGridDimension = GridDimension & { - indexes: DimensionIndexes -} - -function buildResizedDimensions(params: { - newValue: GridDimension - originalValues: GridDimension[] - target: ExpandedGridDimension -}) { - return params.originalValues.map((dim, index) => { - if (index !== params.target.indexes.originalIndex) { - return dim - } else if (isGridCSSRepeat(dim)) { - const repeatedIndex = params.target.indexes.repeatedIndex ?? 0 - const repeatGroup = [ - ...dim.value.slice(0, repeatedIndex), - params.newValue, - ...dim.value.slice(repeatedIndex + 1), - ] - return gridCSSRepeat(dim.times, repeatGroup) - } else { - return params.newValue - } - }) -} - function getNewDragValue( dragAmount: number, isFractional: boolean, diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 5992931ef155..3d64376a27f6 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -89,6 +89,7 @@ import { getGridPlaceholderDomElementFromCoordinates, gridCellTargetId, } from '../canvas-strategies/strategies/grid-cell-bounds' +import { getGridRelatedIndexes } from '../canvas-strategies/strategies/grid-helpers' const CELL_ANIMATION_DURATION = 0.15 // seconds @@ -360,51 +361,10 @@ export const GridResizing = React.memo((props: GridResizingProps) => { if (props.fromPropsAxisValues?.type !== 'DIMENSIONS' || resizingIndex == null) { return [] } - - // Build an array of coresizing indexes per element. - let coresizeIndexes: number[][][] = [] // This looks scary but it's not! It's just a list of indexes, containing a list of the indexes *per group element*. - // For example, 1fr repeat(3, 10px 20px) 1fr, will be represented as: - /** - * [ - * [ [0] ] - * [ [1, 3] [2, 4] ] - * [ [5] ] - * ] - */ - let elementCount = 0 // basically the expanded index - for (const dim of props.fromPropsAxisValues.dimensions) { - if (dim.type === 'REPEAT') { - let groupIndexes: number[][] = [] - // for each value push the coresize indexes as many times as the repeats counter - for (let valueIndex = 0; valueIndex < dim.value.length; valueIndex++) { - let repeatedValueIndexes: number[] = [] - for (let repeatIndex = 0; repeatIndex < dim.times; repeatIndex++) { - repeatedValueIndexes.push(elementCount + valueIndex + repeatIndex * dim.value.length) - } - groupIndexes.push(repeatedValueIndexes) - } - coresizeIndexes.push(groupIndexes) - elementCount += dim.value.length * dim.times // advance the counter as many times as the repeated values *combined* - } else { - coresizeIndexes.push([[elementCount]]) - elementCount++ - } - } - - // Now, expand the indexes calculated above so they "flatten out" to match the generated values - let expandedCoresizeIndexes: number[][] = [] - props.fromPropsAxisValues.dimensions.forEach((dim, dimIndex) => { - if (dim.type === 'REPEAT') { - for (let repeatIndex = 0; repeatIndex < dim.times * dim.value.length; repeatIndex++) { - const indexes = coresizeIndexes[dimIndex][repeatIndex % dim.value.length] - expandedCoresizeIndexes.push(indexes) - } - } else { - expandedCoresizeIndexes.push(coresizeIndexes[dimIndex][0]) - } + return getGridRelatedIndexes({ + template: props.fromPropsAxisValues.dimensions, + index: resizingIndex, }) - - return expandedCoresizeIndexes[resizingIndex] ?? [] }, [props.fromPropsAxisValues, resizingIndex]) if (props.axisValues == null) { diff --git a/editor/src/components/inspector/common/css-utils.ts b/editor/src/components/inspector/common/css-utils.ts index 5bee0ef90a05..1140f4dd6c4d 100644 --- a/editor/src/components/inspector/common/css-utils.ts +++ b/editor/src/components/inspector/common/css-utils.ts @@ -823,14 +823,18 @@ export function printCSSNumber( export function printGridDimension(dimension: GridDimension): string { switch (dimension.type) { - case 'KEYWORD': - return dimension.value.value - case 'NUMBER': + case 'KEYWORD': { + const areaName = dimension.areaName != null ? `[${dimension.areaName}] ` : '' + return `${areaName}${dimension.value.value}` + } + case 'NUMBER': { const printed = printCSSNumber(dimension.value, null) const areaName = dimension.areaName != null ? `[${dimension.areaName}] ` : '' return `${areaName}${printed}` - case 'REPEAT': + } + case 'REPEAT': { return `repeat(${dimension.times}, ${printArrayGridDimensions(dimension.value)})` + } default: assertNever(dimension) } diff --git a/editor/src/components/inspector/flex-section.spec.browser2.tsx b/editor/src/components/inspector/flex-section.spec.browser2.tsx index 61e646a27eca..f8ad05c41e96 100644 --- a/editor/src/components/inspector/flex-section.spec.browser2.tsx +++ b/editor/src/components/inspector/flex-section.spec.browser2.tsx @@ -60,10 +60,24 @@ describe('flex section', () => { ) await selectComponentsForTest(renderResult, [EP.fromString('sb/grid')]) const control = await screen.findByTestId('grid-dimension-column-0') - await typeIntoField(control, '100') + await typeIntoField(control, '100px') const grid = await renderResult.renderedDOM.findByTestId('grid') expect(grid.style.gridTemplateColumns).toEqual('100px auto auto') }) + it('updates a repeated value', async () => { + const renderResult = await renderTestEditorWithCode( + gridProjectWithRepeat, + 'await-first-dom-report', + ) + await selectComponentsForTest(renderResult, [EP.fromString('sb/grid')]) + await typeIntoField(await screen.findByTestId('grid-dimension-column-2'), '42') + + const grid = await renderResult.renderedDOM.findByTestId('grid') + expect(grid.style.gridTemplateColumns).toEqual('[area1] 1fr repeat(2, 10px 42px) 2fr') + + await typeIntoField(await screen.findByTestId('grid-dimension-column-1'), '.5fr') + expect(grid.style.gridTemplateColumns).toEqual('[area1] 1fr repeat(2, 0.5fr 42px) 2fr') + }) }) }) @@ -190,3 +204,62 @@ export var storyboard = ( ) ` + +const gridProjectWithRepeat = ` +import * as React from 'react' +import { Storyboard } from 'utopia-api' + +export var storyboard = ( + +
+
+
+
+ a test +
+
+ +) +` diff --git a/editor/src/components/inspector/flex-section.tsx b/editor/src/components/inspector/flex-section.tsx index 87242505e12f..6172d7d3d9cb 100644 --- a/editor/src/components/inspector/flex-section.tsx +++ b/editor/src/components/inspector/flex-section.tsx @@ -35,6 +35,7 @@ import type { CSSKeyword, CSSNumber, GridAutoFlow, + GridCSSKeyword, GridDiscreteDimension, UnknownOrEmptyInput, ValidGridDimensionKeyword, @@ -51,7 +52,9 @@ import { isEmptyInputValue, isGridCSSKeyword, isGridCSSNumber, + isGridCSSRepeat, isValidGridDimensionKeyword, + printArrayGridDimensions, type GridDimension, } from './common/css-utils' import { applyCommandsAction, transientActions } from '../editor/actions/action-creators' @@ -73,7 +76,12 @@ import { type ElementInstanceMetadata, type GridElementProperties, } from '../../core/shared/element-template' -import { setGridPropsCommands } from '../canvas/canvas-strategies/strategies/grid-helpers' +import { + expandGridDimensions, + removeGridTemplateDimensionAtIndex, + replaceGridTemplateDimensionAtIndex, + setGridPropsCommands, +} from '../canvas/canvas-strategies/strategies/grid-helpers' import { type CanvasCommand } from '../canvas/commands/commands' import type { DropdownMenuItem } from '../../uuiui/radix-components' import { @@ -169,18 +177,7 @@ export const FlexSection = React.memo(() => { }), }) - const reduced = merged.reduce((acc, cur) => { - if (cur.type === 'REPEAT') { - let expanded: GridDiscreteDimension[] = [] - for (let i = 0; i < cur.times; i++) { - expanded.push(...cur.value.filter((v) => v.type !== 'REPEAT')) - } - return acc.concat(...expanded) - } - return acc.concat(cur) - }, [] as GridDiscreteDimension[]) - - return reduced + return merged.filter((v) => v.type !== 'REPEAT') }, [grid]) const rows = React.useMemo((): GridDiscreteDimension[] => { @@ -198,14 +195,7 @@ export const FlexSection = React.memo(() => { }), }) - const reduced = merged.reduce((acc, cur) => { - if (cur.type === 'REPEAT') { - return acc.concat(...cur.value.filter((v) => v.type !== 'REPEAT')) - } - return acc.concat(cur) - }, [] as GridDiscreteDimension[]) - - return reduced + return merged.filter((v) => v.type !== 'REPEAT') }, [grid]) return ( @@ -279,22 +269,60 @@ const TemplateDimensionControl = React.memo( const metadataRef = useRefEditorState((store) => store.editor.jsxMetadata) + const template = React.useMemo(() => { + const fromProps = + axis === 'column' + ? grid.specialSizeMeasurements.containerGridPropertiesFromProps.gridTemplateColumns + : grid.specialSizeMeasurements.containerGridPropertiesFromProps.gridTemplateRows + if (fromProps?.type === 'DIMENSIONS' && fromProps.dimensions.length === 0) { + return { type: 'DIMENSIONS', dimensions: values } + } + return fromProps + }, [grid, axis, values]) + + const expandedTemplate = React.useMemo(() => { + if (template?.type !== 'DIMENSIONS') { + return [] + } + return expandGridDimensions(template.dimensions) + }, [template]) + const onUpdate = React.useCallback( (index: number) => (value: UnknownOrEmptyInput>) => { - const newValues = [...values] - const gridValueAtIndex = values[index] - if (isCSSNumber(value)) { - const maybeUnit = isGridCSSNumber(gridValueAtIndex) ? gridValueAtIndex.value.unit : null - newValues[index] = gridCSSNumber( - cssNumber(value.value, value.unit ?? maybeUnit), - gridValueAtIndex.areaName, - ) - } else if (isCSSKeyword(value)) { - newValues[index] = gridCSSKeyword(value, gridValueAtIndex.areaName) - } else if (isEmptyInputValue(value)) { - newValues[index] = gridCSSKeyword(cssKeyword('auto'), gridValueAtIndex.areaName) + if (template?.type !== 'DIMENSIONS') { + return + } + + function getNewValue() { + const gridValueAtIndex = values[index] + if (isCSSNumber(value)) { + const maybeUnit = isGridCSSNumber(gridValueAtIndex) + ? gridValueAtIndex.value.unit + : null + return gridCSSNumber( + cssNumber(value.value, value.unit ?? maybeUnit), + gridValueAtIndex.areaName, + ) + } else if (isCSSKeyword(value)) { + return gridCSSKeyword(value, gridValueAtIndex.areaName) + } else if (isEmptyInputValue(value)) { + return gridCSSKeyword(cssKeyword('auto'), gridValueAtIndex.areaName) + } else { + return null + } } + const newValue = getNewValue() + if (newValue == null) { + return + } + + const newDimensions = replaceGridTemplateDimensionAtIndex( + template.dimensions, + expandedTemplate, + index, + newValue, + ) dispatch([ applyCommandsAction([ @@ -302,24 +330,32 @@ const TemplateDimensionControl = React.memo( 'always', grid.elementPath, PP.create('style', axis === 'column' ? 'gridTemplateColumns' : 'gridTemplateRows'), - gridNumbersToTemplateString(newValues), + printArrayGridDimensions(newDimensions), ), ]), ]) }, - [grid, values, dispatch, axis], + [grid, values, dispatch, axis, template, expandedTemplate], ) const onRemove = React.useCallback( (index: number) => () => { - const newValues = values.filter((_, idx) => idx !== index) + if (template?.type !== 'DIMENSIONS') { + return + } + + const newValues = removeGridTemplateDimensionAtIndex( + template.dimensions, + expandedTemplate, + index, + ) let commands: CanvasCommand[] = [ setProperty( 'always', grid.elementPath, PP.create('style', axis === 'column' ? 'gridTemplateColumns' : 'gridTemplateRows'), - gridNumbersToTemplateString(newValues), + printArrayGridDimensions(newValues), ), ] @@ -373,25 +409,33 @@ const TemplateDimensionControl = React.memo( dispatch([applyCommandsAction(commands)]) }, - [grid, values, dispatch, axis, metadataRef], + [grid, dispatch, axis, metadataRef, template, expandedTemplate], ) - const onAdd = React.useCallback(() => { - const newValues = values.concat(gridCSSNumber(cssNumber(1, 'fr'), null)) + const onAppend = React.useCallback(() => { + if (template?.type !== 'DIMENSIONS') { + return + } + + const newValues = [...template.dimensions, gridCSSNumber(cssNumber(1, 'fr'), null)] + dispatch([ applyCommandsAction([ setProperty( 'always', grid.elementPath, PP.create('style', axis === 'column' ? 'gridTemplateColumns' : 'gridTemplateRows'), - gridNumbersToTemplateString(newValues), + printArrayGridDimensions(newValues), ), ]), ]) - }, [dispatch, grid, axis, values]) + }, [dispatch, grid, axis, template]) const onRename = React.useCallback( (index: number) => () => { + if (template?.type !== 'DIMENSIONS') { + return + } const container = grid.specialSizeMeasurements.containerGridProperties const dimensions = axis === 'column' ? container.gridTemplateColumns : container.gridTemplateRows @@ -408,22 +452,19 @@ const TemplateDimensionControl = React.memo( const newAreaName: string | null = rawNewAreaName.length === 0 ? null : sanitizeAreaName(rawNewAreaName) - const newValues = values.map((value, idx) => { - if (idx !== index) { - return value - } - return { - ...value, - areaName: newAreaName, - } - }) + const newValues = replaceGridTemplateDimensionAtIndex( + template.dimensions, + expandedTemplate, + index, + { ...values[index], areaName: newAreaName }, + ) let commands: CanvasCommand[] = [ setProperty( 'always', grid.elementPath, PP.create('style', axis === 'column' ? 'gridTemplateColumns' : 'gridTemplateRows'), - gridNumbersToTemplateString(newValues), + printArrayGridDimensions(newValues), ), ] @@ -448,7 +489,7 @@ const TemplateDimensionControl = React.memo( dispatch([applyCommandsAction(commands)]) }, - [grid, axis, values, dispatch, metadataRef], + [grid, axis, values, dispatch, metadataRef, template, expandedTemplate], ) const dropdownMenuItems = React.useCallback( @@ -495,7 +536,7 @@ const TemplateDimensionControl = React.memo(
{title}
- +
{values.map((value, index) => ( @@ -652,26 +693,6 @@ function renameAreaInTemplateAtIndex( } } -function gridNumbersToTemplateString(values: GridDiscreteDimension[]) { - return values - .map((v) => { - function getValue(): string { - switch (v.type) { - case 'KEYWORD': - return v.value.value - case 'NUMBER': - return `${v.value.value}${v.value.unit != null ? `${v.value.unit}` : 'px'}` - default: - assertNever(v) - } - } - const areaName = v.areaName != null ? `[${v.areaName}] ` : '' - const value = getValue() - return `${areaName}${value}` - }) - .join(' ') -} - function getGridTemplateAxisValues(template: { calculated: GridAutoOrTemplateBase | null fromProps: GridAutoOrTemplateBase | null @@ -1065,13 +1086,17 @@ export function mergeGridTemplateValues({ fromProps: GridDimension[] autoValues: GridDimension[] }): GridDimension[] { + const expanded = fromProps.flatMap((v) => { + return isGridCSSRepeat(v) ? Array(v.times).fill(v.value).flat() : v + }) + function getExplicitValue(dimension: GridDimension, index: number): GridDimension { - if (fromProps.length === 0) { + if (expanded.length === 0) { return gridCSSKeyword(cssKeyword('auto'), dimension.areaName) - } else if (fromProps[index] == null) { + } else if (expanded[index] == null) { return dimension } else { - return fromProps[index] + return expanded[index] } } @@ -1082,7 +1107,10 @@ export function mergeGridTemplateValues({ const autoValue = autoValues.at(autoValueIndex) if (isGridCSSKeyword(explicitValue) && explicitValue.value.value === 'auto') { - return autoValue ?? explicitValue + return { + ...(autoValue ?? explicitValue), + areaName: explicitValue.areaName ?? autoValue?.areaName ?? null, + } as GridCSSKeyword } return explicitValue From 0a8440c28a42dfa32fa9e0ac7afeb796a920405e Mon Sep 17 00:00:00 2001 From: Sean Parsons <217400+seanparsons@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:34:08 +0100 Subject: [PATCH 036/272] performance(editor) Dedupe `validPaths`. (#6376) - Added `addAll` utility function for sets. - `runDomSampler` now includes a test environment only check that there are no duplicate entries in `validPaths`. - `getValidElementPathsFromElement` now uses a `Set` instead of any array for storing the paths as it builds up the result. --- editor/src/components/canvas/canvas-utils.ts | 57 ++++++++++++------- editor/src/components/canvas/dom-sampler.tsx | 10 ++++ .../src/components/canvas/ui-jsx-canvas.tsx | 2 +- editor/src/core/shared/set-utils.ts | 6 ++ 4 files changed, 52 insertions(+), 23 deletions(-) diff --git a/editor/src/components/canvas/canvas-utils.ts b/editor/src/components/canvas/canvas-utils.ts index 0b384a89ae13..de3d1b6857ea 100644 --- a/editor/src/components/canvas/canvas-utils.ts +++ b/editor/src/components/canvas/canvas-utils.ts @@ -168,6 +168,7 @@ import { getComponentDescriptorForTarget } from '../../core/property-controls/pr import type { PropertyControlsInfo } from '../custom-code/code-file' import { mapDropNulls } from '../../core/shared/array-utils' import { isFeatureEnabled } from '../../utils/feature-switches' +import { addAll } from '../../core/shared/set-utils' function dragDeltaScaleForProp(prop: LayoutTargetableProp): number { switch (prop) { @@ -1782,7 +1783,10 @@ function getValidElementPathsFromElement( ? EP.appendNewElementPath(parentPath, uid) : EP.appendToPath(parentPath, uid) : parentPath - let paths = includeElementInPath ? [path] : [] + let paths: Set = new Set() + if (includeElementInPath) { + paths.add(path) + } if (isJSXElementLike(element)) { const isRemixScene = isRemixSceneElement(element, filePath, projectContents) if (isRemixScene) { @@ -1800,8 +1804,9 @@ function getValidElementPathsFromElement( return } - paths.push( - ...getValidElementPathsFromElement( + addAll( + paths, + getValidElementPathsFromElement( focusedElementPath, topLevelElement, parentPathInner, @@ -1834,7 +1839,7 @@ function getValidElementPathsFromElement( } } - return paths + return Array.from(paths) } } @@ -1866,7 +1871,7 @@ function getValidElementPathsFromElement( resolve, getRemixValidPathsGenerationContext, ) - paths.push(...result) + addAll(paths, result) } matchingAutofocusedPathParts.forEach((autofocusedPathPart) => { const result = getValidElementPaths( @@ -1879,13 +1884,14 @@ function getValidElementPathsFromElement( resolve, getRemixValidPathsGenerationContext, ) - paths.push(...result) + addAll(paths, result) }) // finally, add children elements fastForEach(element.children, (c) => - paths.push( - ...getValidElementPathsFromElement( + addAll( + paths, + getValidElementPathsFromElement( focusedElementPath, c, path, @@ -1907,8 +1913,9 @@ function getValidElementPathsFromElement( if (p.type === 'JSX_ATTRIBUTES_ENTRY') { const prop = p.value if (prop.type === 'JSX_ELEMENT') { - paths.push( - ...getValidElementPathsFromElement( + addAll( + paths, + getValidElementPathsFromElement( focusedElementPath, prop, path, @@ -1928,17 +1935,18 @@ function getValidElementPathsFromElement( }) } - return paths + return Array.from(paths) } else if ( (isJSXTextBlock(element) && isFeatureEnabled('Condensed Navigator Entries')) || isJSIdentifier(element) || isJSPropertyAccess(element) || isJSElementAccess(element) ) { - return paths + return Array.from(paths) } else if (isJSXMapExpression(element)) { - paths.push( - ...getValidElementPathsFromElement( + addAll( + paths, + getValidElementPathsFromElement( focusedElementPath, element.valueToMap, path, @@ -1952,7 +1960,10 @@ function getValidElementPathsFromElement( resolve, getRemixValidPathsGenerationContext, ), - ...getValidElementPathsFromElement( + ) + addAll( + paths, + getValidElementPathsFromElement( focusedElementPath, element.mapFunction, path, @@ -1967,7 +1978,7 @@ function getValidElementPathsFromElement( getRemixValidPathsGenerationContext, ), ) - return paths + return Array.from(paths) } else if (isJSExpressionOtherJavaScript(element)) { // FIXME: From investigation of https://github.com/concrete-utopia/utopia/issues/1137 // The paths this will generate will only be correct if the elements from `elementsWithin` @@ -1988,8 +1999,9 @@ function getValidElementPathsFromElement( // We explicitly prevent auto-focusing generated elements here, because to support it would // require using the elementPathTree to determine how many children of a scene were actually // generated, creating a chicken and egg situation. - paths.push( - ...getValidElementPathsFromElement( + addAll( + paths, + getValidElementPathsFromElement( focusedElementPath, e, path, @@ -2005,11 +2017,12 @@ function getValidElementPathsFromElement( ), ), ) - return paths + return Array.from(paths) } else if (isJSXConditionalExpression(element)) { fastForEach([element.whenTrue, element.whenFalse], (e) => { - paths.push( - ...getValidElementPathsFromElement( + addAll( + paths, + getValidElementPathsFromElement( focusedElementPath, e, path, @@ -2025,7 +2038,7 @@ function getValidElementPathsFromElement( ), ) }) - return paths + return Array.from(paths) } else { return [] } diff --git a/editor/src/components/canvas/dom-sampler.tsx b/editor/src/components/canvas/dom-sampler.tsx index 7aefefa59b25..3bb9f3994f25 100644 --- a/editor/src/components/canvas/dom-sampler.tsx +++ b/editor/src/components/canvas/dom-sampler.tsx @@ -42,6 +42,7 @@ import { getAttributesComingFromStyleSheets, } from './dom-walker' import type { UiJsxCanvasContextData } from './ui-jsx-canvas' +import { IS_TEST_ENVIRONMENT } from '../../common/env-vars' export function runDomSampler(options: { elementsToFocusOn: ElementsToRerender @@ -67,6 +68,15 @@ export function runDomSampler(options: { } const validPaths = getValidPathsFromCanvasContainer(canvasRootContainer) + // Only perform this validation while in a test environment. + if (IS_TEST_ENVIRONMENT) { + const uniqueValidPaths = new Set(validPaths.map(EP.toString)) + if (uniqueValidPaths.size !== validPaths.length) { + throw new Error( + `Duplicate paths in validPaths: ${JSON.stringify(validPaths.map(EP.toString), null, 2)}`, + ) + } + } const spyPaths = Object.keys(options.spyCollector.current.spyValues.metadata) if (spyPaths.length === 0 && validPaths.length > 0) { diff --git a/editor/src/components/canvas/ui-jsx-canvas.tsx b/editor/src/components/canvas/ui-jsx-canvas.tsx index 19413a4462d6..03b2215fd10e 100644 --- a/editor/src/components/canvas/ui-jsx-canvas.tsx +++ b/editor/src/components/canvas/ui-jsx-canvas.tsx @@ -833,7 +833,7 @@ function useGetStoryboardRoot( getRemixValidPathsGenerationContext, ) const storyboardRootElementPath = useKeepReferenceEqualityIfPossible( - validPaths[0] ?? EP.emptyElementPath, + validPaths.at(0) ?? EP.emptyElementPath, ) const rootValidPathsArray = validPaths.map(EP.makeLastPartOfPathStatic) diff --git a/editor/src/core/shared/set-utils.ts b/editor/src/core/shared/set-utils.ts index 012c40b814f8..d4c7404c3d73 100644 --- a/editor/src/core/shared/set-utils.ts +++ b/editor/src/core/shared/set-utils.ts @@ -45,3 +45,9 @@ export function getSingleValueOnly(set: Set): T { } throw new Error(`Set had ${set.size} when it was expected to have just 1.`) } + +export function addAll(set: Set, values: Array): void { + for (const value of values) { + set.add(value) + } +} From b2cf41f731d7d5dec821a4c6f41716beead2ee58 Mon Sep 17 00:00:00 2001 From: Sean Parsons <217400+seanparsons@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:34:38 +0100 Subject: [PATCH 037/272] performance(editor) Eliminate duplicate dom lookups (#6389) - `collectMetadataForPaths` now caches the results of calls to `collectMetadataForElementPath` as there are two locations that make calls to it. --- editor/src/components/canvas/dom-sampler.tsx | 22 +++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/editor/src/components/canvas/dom-sampler.tsx b/editor/src/components/canvas/dom-sampler.tsx index 3bb9f3994f25..7b1dca594dce 100644 --- a/editor/src/components/canvas/dom-sampler.tsx +++ b/editor/src/components/canvas/dom-sampler.tsx @@ -166,6 +166,8 @@ function collectMetadataForPaths({ ) }) + let domMetadataCollected: { [key: string]: DomElementMetadata | null } = {} + if (checkExistingMetadata === 'check-existing') { // delete all metadata which should be collected now and those which are not in the dom anymore Object.keys(metadataToUpdate_MUTATE).forEach((p) => { @@ -185,19 +187,23 @@ function collectMetadataForPaths({ if (domMetadata == null) { delete metadataToUpdate_MUTATE[p] } + domMetadataCollected[p] = domMetadata }) } dynamicPathsToCollect.forEach((pathString) => { const path = EP.fromString(pathString) - const domMetadata = collectMetadataForElementPath( - path, - validPaths, - selectedViews, - scale, - containerRect, - elementCanvasRectangleCache, - ) + const domMetadata = + pathString in domMetadataCollected + ? domMetadataCollected[pathString] + : collectMetadataForElementPath( + path, + validPaths, + selectedViews, + scale, + containerRect, + elementCanvasRectangleCache, + ) const spyMetadata = spyCollector.current.spyValues.metadata[EP.toString(path)] if (spyMetadata == null) { From 1e9b84e57c2af7b7b78eb35d122a0973c4f408ca Mon Sep 17 00:00:00 2001 From: Balint Gabor <127662+gbalint@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:40:38 +0200 Subject: [PATCH 038/272] Grid controls use metadata (#6390) **Problem:** Followup to https://github.com/concrete-utopia/utopia/pull/6386 Removed dom queries from grid and grid gap controls, and converted all calculations to the canvas coordinate system. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Preview mode --- .../strategies/grid-cell-bounds.ts | 11 --- .../strategies/grid-helpers.ts | 6 +- .../canvas/controls/grid-controls.tsx | 98 +++++-------------- .../controls/select-mode/grid-gap-control.tsx | 13 +-- .../select-mode/subdued-grid-gap-controls.tsx | 34 ++----- editor/src/components/canvas/gap-utils.ts | 96 +++++++++--------- 6 files changed, 86 insertions(+), 172 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts index 1c7827d5d01a..f90d461ddae0 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-cell-bounds.ts @@ -1,12 +1,10 @@ import type { ElementPath } from 'utopia-shared/src/types' import type { ElementInstanceMetadata } from '../../../../core/shared/element-template' -import type { WindowPoint, WindowRectangle } from '../../../../core/shared/math-utils' import { canvasPoint, isInfinityRectangle, offsetPoint, rectContainsPoint, - windowRectangle, } from '../../../../core/shared/math-utils' import * as EP from '../../../../core/shared/element-path' import { @@ -102,12 +100,3 @@ export function getGridCellBoundsFromCanvas( height: cellHeight, } } - -export function getGridPlaceholderDomElementFromCoordinates(params: { - row: number - column: number -}): HTMLElement | null { - return document.querySelector( - `[data-grid-row="${params.row}"]` + `[data-grid-column="${params.column}"]`, - ) -} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index a1651088f729..50f1ae451df4 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -13,7 +13,7 @@ import { type GridElementProperties, type GridPosition, } from '../../../../core/shared/element-template' -import type { CanvasRectangle, CanvasVector } from '../../../../core/shared/math-utils' +import type { CanvasRectangle } from '../../../../core/shared/math-utils' import { canvasPoint, canvasRectangle, @@ -434,7 +434,7 @@ function gridChildAbsoluteMoveCommands( return [] } - const offsetInTarget = windowPoint({ + const offsetInTarget = canvasPoint({ x: dragInteractionData.originalDragStart.x - targetMetadata.globalFrame.x, y: dragInteractionData.originalDragStart.y - targetMetadata.globalFrame.y, }) @@ -609,7 +609,7 @@ export function getGlobalFrameOfGridCell( return null } - return gridCellGlobalFrames[coords.row - 1][coords.column - 1] ?? null + return gridCellGlobalFrames[coords.row - 1]?.[coords.column - 1] ?? null } function gridTemplateToNumbers(gridTemplate: GridTemplate | null): Array | null { diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 3d64376a27f6..3936bf6dc5a0 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -20,7 +20,10 @@ import { MetadataUtils } from '../../../core/model/element-metadata-utils' import { mapDropNulls, stripNulls } from '../../../core/shared/array-utils' import { defaultEither } from '../../../core/shared/either' import * as EP from '../../../core/shared/element-path' -import type { GridAutoOrTemplateDimensions } from '../../../core/shared/element-template' +import type { + ElementInstanceMetadata, + GridAutoOrTemplateDimensions, +} from '../../../core/shared/element-template' import { isGridAutoOrTemplateDimensions, type GridAutoOrTemplateBase, @@ -28,7 +31,6 @@ import { import type { CanvasPoint, CanvasRectangle } from '../../../core/shared/math-utils' import { canvasPoint, - canvasRectangle, isFiniteRectangle, isInfinityRectangle, nullIfInfinity, @@ -85,11 +87,11 @@ import { CanvasOffsetWrapper } from './canvas-offset-wrapper' import { CanvasLabel } from './select-mode/controls-common' import { useMaybeHighlightElement } from './select-mode/select-mode-hooks' import type { GridCellCoordinates } from '../canvas-strategies/strategies/grid-cell-bounds' +import { gridCellTargetId } from '../canvas-strategies/strategies/grid-cell-bounds' import { - getGridPlaceholderDomElementFromCoordinates, - gridCellTargetId, -} from '../canvas-strategies/strategies/grid-cell-bounds' -import { getGridRelatedIndexes } from '../canvas-strategies/strategies/grid-helpers' + getGlobalFrameOfGridCell, + getGridRelatedIndexes, +} from '../canvas-strategies/strategies/grid-helpers' const CELL_ANIMATION_DURATION = 0.15 // seconds @@ -452,6 +454,7 @@ export type GridData = { rows: number columns: number cells: number + metadata: ElementInstanceMetadata } export function useGridData(elementPaths: ElementPath[]): GridData[] { const grids = useEditorState( @@ -495,6 +498,7 @@ export function useGridData(elementPaths: ElementPath[]): GridData[] { return { elementPath: targetGridContainer.elementPath, + metadata: targetGridContainer, frame: targetGridContainer.globalFrame, gridTemplateColumns: gridTemplateColumns, gridTemplateRows: gridTemplateRows, @@ -912,8 +916,6 @@ export const GridControls = controlForStrategyMemoized(({ tar position: 'relative', pointerEvents: 'initial', }} - data-grid-row={countedRow} - data-grid-column={countedColumn} > {when( features.Grid.dotgrid, @@ -1052,61 +1054,31 @@ const AbsoluteDistanceIndicators = React.memo( (props: { targetRootCell: GridCellCoordinates | null }) => { const colorTheme = useColorTheme() - const cellFrame = useEditorState( + const gridMetadata = useEditorState( Substores.metadata, (store) => { if (store.editor.selectedViews.length !== 1) { return null } - const meta = MetadataUtils.findElementByElementPath( + return MetadataUtils.findElementByElementPath( store.editor.jsxMetadata, store.editor.selectedViews[0], ) - if (!MetadataUtils.isPositionAbsolute(meta)) { - return null - } - - return nullIfInfinity(meta?.globalFrame) }, 'AbsoluteDistanceIndicators cellFrame', ) - const canvasScale = useEditorState( - Substores.canvasOffset, - (store) => store.editor.canvas.scale, - 'AbsoluteDistanceIndicators canvasScale', - ) - const canvasOffset = useEditorState( - Substores.canvasOffset, - (store) => store.editor.canvas.roundedCanvasOffset, - 'AbsoluteDistanceIndicators canvasOffset', - ) + const cellFrame = !MetadataUtils.isPositionAbsolute(gridMetadata) + ? null + : nullIfInfinity(gridMetadata?.globalFrame) const targetCellBoundingBox = React.useMemo(() => { - if (props.targetRootCell == null) { + if (gridMetadata == null || props.targetRootCell == null) { return null } - const element = getGridPlaceholderDomElementFromCoordinates(props.targetRootCell) - const boundingBox = element?.getBoundingClientRect() - if (boundingBox == null) { - return null - } - - const canvasOrigin = windowToCanvasCoordinates( - canvasScale, - canvasOffset, - windowPoint({ x: boundingBox.left, y: boundingBox.top }), - ).canvasPositionRounded - const canvasRect = canvasRectangle({ - x: canvasOrigin.x, - y: canvasOrigin.y, - width: boundingBox.width * canvasScale, - height: boundingBox.height * canvasScale, - }) - - return canvasRect - }, [props.targetRootCell, canvasScale, canvasOffset]) + return getGlobalFrameOfGridCell(gridMetadata, props.targetRootCell) + }, [props.targetRootCell, gridMetadata]) const distanceTop = targetCellBoundingBox == null || cellFrame == null ? 0 : cellFrame.y - targetCellBoundingBox.y @@ -1397,16 +1369,10 @@ function useCellAnimation(params: { const animate = useCanvasAnimation(selectedViews) - const canvasScale = useEditorState( - Substores.canvasOffset, - (store) => store.editor.canvas.scale, - 'useSnapAnimation canvasScale', - ) - - const canvasOffset = useEditorState( - Substores.canvasOffset, - (store) => store.editor.canvas.roundedCanvasOffset, - 'useSnapAnimation canvasOffset', + const gridMetadata = useEditorState( + Substores.metadata, + (store) => MetadataUtils.findElementByElementPath(store.editor.jsxMetadata, gridPath), + 'useCellAnimation gridMetadata', ) const moveFromPoint = React.useMemo(() => { @@ -1414,22 +1380,12 @@ function useCellAnimation(params: { }, [lastSnapPoint, shadowFrame]) const snapPoint = React.useMemo(() => { - if (gridPath == null || targetRootCell == null) { + if (gridMetadata == null || targetRootCell == null) { return null } - const element = document.getElementById( - gridCellTargetId(gridPath, targetRootCell.row, targetRootCell.column), - ) - if (element == null) { - return null - } - - const rect = element.getBoundingClientRect() - const point = windowPoint({ x: rect.x, y: rect.y }) - - return windowToCanvasCoordinates(canvasScale, canvasOffset, point).canvasPositionRounded - }, [canvasScale, canvasOffset, gridPath, targetRootCell]) + return getGlobalFrameOfGridCell(gridMetadata, targetRootCell) + }, [gridMetadata, targetRootCell]) React.useEffect(() => { if (disabled) { @@ -1762,10 +1718,6 @@ function gridKeyFromPath(path: ElementPath): string { return `grid-${EP.toString(path)}` } -export function getGridPlaceholderDomElement(elementPath: ElementPath): HTMLElement | null { - return document.getElementById(gridKeyFromPath(elementPath)) -} - const gridPlaceholderBorder = (color: string) => `2px solid ${color}` export function controlsForGridPlaceholders(gridPath: ElementPath): ControlWithProps { diff --git a/editor/src/components/canvas/controls/select-mode/grid-gap-control.tsx b/editor/src/components/canvas/controls/select-mode/grid-gap-control.tsx index ccf0049b9037..5cf6af9f6779 100644 --- a/editor/src/components/canvas/controls/select-mode/grid-gap-control.tsx +++ b/editor/src/components/canvas/controls/select-mode/grid-gap-control.tsx @@ -154,15 +154,10 @@ export const GridGapControl = controlForStrategyMemoized((p const gridRowColumnInfo = useGridData([selectedElement]) - const controlBounds = gridGapControlBoundsFromMetadata( - selectedElement, - gridRowColumnInfo[0], - { - row: fallbackEmptyValue(gridGapRow), - column: fallbackEmptyValue(gridGapColumn), - }, - scale, - ) + const controlBounds = gridGapControlBoundsFromMetadata(gridRowColumnInfo[0], { + row: fallbackEmptyValue(gridGapRow), + column: fallbackEmptyValue(gridGapColumn), + }) return ( diff --git a/editor/src/components/canvas/controls/select-mode/subdued-grid-gap-controls.tsx b/editor/src/components/canvas/controls/select-mode/subdued-grid-gap-controls.tsx index 61f436cda21b..3ea911a32c89 100644 --- a/editor/src/components/canvas/controls/select-mode/subdued-grid-gap-controls.tsx +++ b/editor/src/components/canvas/controls/select-mode/subdued-grid-gap-controls.tsx @@ -23,11 +23,7 @@ export const SubduedGridGapControl = React.memo((pro (store) => store.editor.selectedViews, 'SubduedGridGapControl selectedViews', ) - const scale = useEditorState( - Substores.canvas, - (store) => store.editor.canvas.scale, - 'GridGapControl scale', - ) + const metadata = useRefEditorState((store) => store.editor.jsxMetadata) const selectedElement = targets.at(0) @@ -46,17 +42,12 @@ export const SubduedGridGapControl = React.memo((pro const gridGapRow = gridGap.row const gridGapColumn = gridGap.column - const controlBounds = gridGapControlBoundsFromMetadata( - selectedElement, - selectedGrid, - { - row: fallbackEmptyValue(gridGapRow), - column: fallbackEmptyValue(gridGapColumn), - }, - scale, - ) + const controlBounds = gridGapControlBoundsFromMetadata(selectedGrid, { + row: fallbackEmptyValue(gridGapRow), + column: fallbackEmptyValue(gridGapColumn), + }) return controlBounds.gaps.filter((gap) => gap.axis === axis || axis === 'both') - }, [axis, metadata, scale, selectedElement, selectedGrid]) + }, [axis, metadata, selectedElement, selectedGrid]) if (filteredGaps.length === 0 || selectedElement == null) { return null @@ -108,15 +99,10 @@ function GridGapControl({ return } - const controlBounds = gridGapControlBoundsFromMetadata( - selectedElement, - selectedGrid, - { - row: fallbackEmptyValue(gridGap.row), - column: fallbackEmptyValue(gridGap.column), - }, - scale, - ) + const controlBounds = gridGapControlBoundsFromMetadata(selectedGrid, { + row: fallbackEmptyValue(gridGap.row), + column: fallbackEmptyValue(gridGap.column), + }) const bound = controlBounds.gaps.find((updatedGap) => updatedGap.gapId === gap.gapId) if (bound == null) { diff --git a/editor/src/components/canvas/gap-utils.ts b/editor/src/components/canvas/gap-utils.ts index c30454a2afeb..cddd81efd7a6 100644 --- a/editor/src/components/canvas/gap-utils.ts +++ b/editor/src/components/canvas/gap-utils.ts @@ -32,10 +32,8 @@ import * as EP from '../../core/shared/element-path' import { treatElementAsFragmentLike } from './canvas-strategies/strategies/fragment-like-helpers' import type { AllElementProps } from '../editor/store/editor-state' import type { GridData } from './controls/grid-controls' -import { - getGridPlaceholderDomElement, - getNullableAutoOrTemplateBaseString, -} from './controls/grid-controls' +import { getNullableAutoOrTemplateBaseString } from './controls/grid-controls' +import { getGlobalFramesOfGridCells } from './canvas-strategies/strategies/grid-helpers' export interface PathWithBounds { bounds: CanvasRectangle @@ -179,10 +177,8 @@ export function gapControlBoundsFromMetadata( } export function gridGapControlBoundsFromMetadata( - parentPath: ElementPath, gridRowColumnInfo: GridData, gapValues: { row: CSSNumber; column: CSSNumber }, - scale: number, ): { gaps: Array<{ bounds: CanvasRectangle @@ -206,48 +202,56 @@ export function gridGapControlBoundsFromMetadata( gridTemplateRows: '1fr', gridTemplateColumns: '1fr', } - const parentGrid = getGridPlaceholderDomElement(parentPath) - if (parentGrid == null) { + const grid = gridRowColumnInfo.metadata + + if (grid == null) { + return emptyResult + } + + const parentGridBounds = grid.globalFrame + + if (parentGridBounds == null || isInfinityRectangle(parentGridBounds)) { return emptyResult } - const parentGridBounds = parentGrid?.getBoundingClientRect() + const gridRows = gridRowColumnInfo.rows const gridColumns = gridRowColumnInfo.columns const gridTemplateRows = getNullableAutoOrTemplateBaseString(gridRowColumnInfo.gridTemplateRows) const gridTemplateColumns = getNullableAutoOrTemplateBaseString( gridRowColumnInfo.gridTemplateColumns, ) - const childrenArray = Array.from(parentGrid?.children ?? []) - if (childrenArray.length !== gridRows * gridColumns) { + + const gridCellBounds = getGlobalFramesOfGridCells(grid) + + if (gridCellBounds == null) { return emptyResult } - const cell = matrixGetter(childrenArray, gridColumns) - // the actual rectangle that surrounds the cell placeholders - const cellBounds = canvasRectangle({ - x: cell(0, 0).getBoundingClientRect().x - parentGridBounds.x, - y: cell(0, 0).getBoundingClientRect().y - parentGridBounds.y, + const allCellsBound = canvasRectangle({ + x: gridCellBounds[0][0].x - parentGridBounds.x, + y: gridCellBounds[0][0].y - parentGridBounds.y, width: - cell(0, gridColumns - 1).getBoundingClientRect().right - cell(0, 0).getBoundingClientRect().x, + gridCellBounds[0][gridColumns - 1].x + + gridCellBounds[0][gridColumns - 1].width - + gridCellBounds[0][0].x, height: - cell(gridRows - 1, 0).getBoundingClientRect().bottom - cell(0, 0).getBoundingClientRect().y, + gridCellBounds[gridRows - 1][0].y + + gridCellBounds[gridRows - 1][0].height - + gridCellBounds[0][0].y, }) // row gaps array const rowGaps = createArrayWithLength(gridRows - 1, (i) => { // cell i represents the gap between child [i * gridColumns] and child [(i+1) * gridColumns] - const firstChildBounds = cell(i, 0).getBoundingClientRect() - const secondChildBounds = cell(i + 1, 0).getBoundingClientRect() + const firstChildBounds = gridCellBounds[i][0] + const secondChildBounds = gridCellBounds[i + 1][0] return { - gapId: `${EP.toString(parentPath)}-row-gap-${i}`, - bounds: adjustToScale( - canvasRectangle({ - x: cellBounds.x, - y: firstChildBounds.bottom - parentGridBounds.y, - width: cellBounds.width, - height: secondChildBounds.top - firstChildBounds.bottom, - }), - scale, - ), + gapId: `${EP.toString(grid.elementPath)}-row-gap-${i}`, + bounds: canvasRectangle({ + x: allCellsBound.x, + y: firstChildBounds.y + firstChildBounds.height - parentGridBounds.y, + width: allCellsBound.width, + height: secondChildBounds.y - firstChildBounds.y - firstChildBounds.height, + }), gap: gapValues.row, axis: 'row' as Axis, } @@ -256,19 +260,16 @@ export function gridGapControlBoundsFromMetadata( // column gaps array const columnGaps = createArrayWithLength(gridColumns - 1, (i) => { // cell i represents the gap between child [i] and child [i + 1] - const firstChildBounds = cell(0, i).getBoundingClientRect() - const secondChildBounds = cell(0, i + 1).getBoundingClientRect() + const firstChildBounds = gridCellBounds[0][i] + const secondChildBounds = gridCellBounds[0][i + 1] return { - gapId: `${EP.toString(parentPath)}-column-gap-${i}`, - bounds: adjustToScale( - canvasRectangle({ - x: firstChildBounds.right - parentGridBounds.x, - y: cellBounds.y, - width: secondChildBounds.left - firstChildBounds.right, - height: cellBounds.height, - }), - scale, - ), + gapId: `${EP.toString(grid.elementPath)}-column-gap-${i}`, + bounds: canvasRectangle({ + x: firstChildBounds.x + firstChildBounds.width - parentGridBounds.x, + y: allCellsBound.y, + width: secondChildBounds.x - firstChildBounds.x - firstChildBounds.width, + height: allCellsBound.height, + }), gap: gapValues.column, axis: 'column' as Axis, } @@ -280,20 +281,11 @@ export function gridGapControlBoundsFromMetadata( columns: gridColumns, gridTemplateRows: gridTemplateRows ?? '', gridTemplateColumns: gridTemplateColumns ?? '', - cellBounds: cellBounds, + cellBounds: allCellsBound, gapValues: gapValues, } } -function adjustToScale(rectangle: CanvasRectangle, scale: number): CanvasRectangle { - return canvasRectangle({ - x: rectangle.x / scale, - y: rectangle.y / scale, - width: rectangle.width / scale, - height: rectangle.height / scale, - }) -} - export interface GridGapData { row: CSSNumberWithRenderedValue column: CSSNumberWithRenderedValue From 6cb11b211e99a28c744b38acaa93e3be37d87418 Mon Sep 17 00:00:00 2001 From: Sean Parsons <217400+seanparsons@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:48:17 +0100 Subject: [PATCH 039/272] performance(editor) Switch Event Handlers (#6385) - Switched lots of event handlers from `onClick` to `onMouseDown`, along with updating the name of props if those use that naming. --- .../components/canvas/design-panel-root.tsx | 42 +++++++++---------- ...spector-end-to-end-tests.spec.browser2.tsx | 8 ++-- .../components/inspector/section-header.tsx | 2 +- .../component-section/component-section.tsx | 4 +- .../header-section/target-selector.tsx | 4 +- .../layout-section/list-source-cartouche.tsx | 13 +++--- .../components/navigator/left-pane/index.tsx | 34 +++++++-------- .../navigator-condensed-entry.tsx | 12 +++--- .../navigator-item-clickable-wrapper.tsx | 14 +++---- .../navigator-item-components.tsx | 37 ++++++++-------- .../navigator-item/navigator-item.tsx | 29 +++++++------ ...nent-picker-context-menu.spec.browser2.tsx | 9 ++-- .../navigator/navigator.spec.browser2.tsx | 9 ++-- 13 files changed, 112 insertions(+), 105 deletions(-) diff --git a/editor/src/components/canvas/design-panel-root.tsx b/editor/src/components/canvas/design-panel-root.tsx index 5852f12f0e23..82de4a3df8d6 100644 --- a/editor/src/components/canvas/design-panel-root.tsx +++ b/editor/src/components/canvas/design-panel-root.tsx @@ -136,7 +136,7 @@ export const RightPane = React.memo((props) => { ) const dispatch = useDispatch() - const onClickTab = React.useCallback( + const onMouseDownTab = React.useCallback( (menuTab: RightMenuTab) => { const actions: Array = [EditorActions.setRightMenuTab(menuTab)] if (isCommentMode(editorModeRef.current) && menuTab !== RightMenuTab.Comments) { @@ -147,25 +147,25 @@ export const RightPane = React.memo((props) => { [dispatch, editorModeRef], ) - const onClickInsertTab = React.useCallback(() => { - onClickTab(RightMenuTab.Insert) - }, [onClickTab]) + const onMouseDownInsertTab = React.useCallback(() => { + onMouseDownTab(RightMenuTab.Insert) + }, [onMouseDownTab]) - const onClickCommentsTab = React.useCallback(() => { - onClickTab(RightMenuTab.Comments) - }, [onClickTab]) + const onMouseDownCommentsTab = React.useCallback(() => { + onMouseDownTab(RightMenuTab.Comments) + }, [onMouseDownTab]) - const onClickInspectorTab = React.useCallback(() => { - onClickTab(RightMenuTab.Inspector) - }, [onClickTab]) + const onMouseDownInspectorTab = React.useCallback(() => { + onMouseDownTab(RightMenuTab.Inspector) + }, [onMouseDownTab]) - const onClickSettingsTab = React.useCallback(() => { - onClickTab(RightMenuTab.Settings) - }, [onClickTab]) + const onMouseDownSettingsTab = React.useCallback(() => { + onMouseDownTab(RightMenuTab.Settings) + }, [onMouseDownTab]) - const onClickRollYourOwnTab = React.useCallback(() => { - onClickTab(RightMenuTab.RollYourOwn) - }, [onClickTab]) + const onMouseDownRollYourOwnTab = React.useCallback(() => { + onMouseDownTab(RightMenuTab.RollYourOwn) + }, [onMouseDownTab]) const canComment = useCanComment() @@ -206,7 +206,7 @@ export const RightPane = React.memo((props) => { {when( allowedToEdit, @@ -216,7 +216,7 @@ export const RightPane = React.memo((props) => { , )} , @@ -227,20 +227,20 @@ export const RightPane = React.memo((props) => { testId='comments-tab' label={'Comments'} selected={selectedTab === RightMenuTab.Comments} - onClick={onClickCommentsTab} + onMouseDown={onMouseDownCommentsTab} />, )} {when( isFeatureEnabled('Roll Your Own'), , )} diff --git a/editor/src/components/inspector/common/inspector-end-to-end-tests.spec.browser2.tsx b/editor/src/components/inspector/common/inspector-end-to-end-tests.spec.browser2.tsx index 088a593c27be..2fabb7121bba 100644 --- a/editor/src/components/inspector/common/inspector-end-to-end-tests.spec.browser2.tsx +++ b/editor/src/components/inspector/common/inspector-end-to-end-tests.spec.browser2.tsx @@ -1459,12 +1459,12 @@ describe('inspector tests with real metadata', () => { await act(async () => { await screen.findByTestId('section-header-Advanced') - fireEvent.click(screen.getByTestId('section-header-Advanced')) + fireEvent.mouseDown(screen.getByTestId('section-header-Advanced')) }) await act(async () => { await screen.findByTestId('target-selector-style') - fireEvent.click(screen.getByTestId('target-selector')) + fireEvent.mouseDown(screen.getByTestId('target-selector')) }) await act(async () => { await screen.findByTestId('target-list-item-css') @@ -1566,12 +1566,12 @@ describe('inspector tests with real metadata', () => { await act(async () => { await screen.findByTestId('section-header-Advanced') - fireEvent.click(screen.getByTestId('section-header-Advanced')) + fireEvent.mouseDown(screen.getByTestId('section-header-Advanced')) }) await act(async () => { await screen.findByTestId('target-selector-style') - fireEvent.click(screen.getByTestId('target-selector')) + fireEvent.mouseDown(screen.getByTestId('target-selector')) }) await act(async () => { await screen.findByTestId('target-list-item-css') diff --git a/editor/src/components/inspector/section-header.tsx b/editor/src/components/inspector/section-header.tsx index 1887359b8cd5..77719edac898 100644 --- a/editor/src/components/inspector/section-header.tsx +++ b/editor/src/components/inspector/section-header.tsx @@ -19,7 +19,7 @@ export function InspectorSectionHeader({ padding: 8, cursor: 'pointer', }} - onClick={toggle} + onMouseDown={toggle} data-testid={`section-header-${title}`} >
{ return (
Component )} - + { Target - + - + { - if (openOn === 'single-click') { - openPopup() - } - }, [openOn, openPopup]) + const onClick = React.useCallback( + (e: React.MouseEvent) => { + if (openOn === 'single-click') { + openPopup() + } + }, + [openOn, openPopup], + ) const onDoubleClick = React.useCallback(() => { if (openOn === 'double-click') { diff --git a/editor/src/components/navigator/left-pane/index.tsx b/editor/src/components/navigator/left-pane/index.tsx index 286bf18cbbe5..8babed005899 100644 --- a/editor/src/components/navigator/left-pane/index.tsx +++ b/editor/src/components/navigator/left-pane/index.tsx @@ -48,7 +48,7 @@ export const LeftPaneComponent = React.memo((props) => { const dispatch = useDispatch() - const onClickTab = React.useCallback( + const onMouseDownTab = React.useCallback( (menuTab: LeftMenuTab) => { let actions: Array = [] actions.push(setLeftMenuTab(menuTab)) @@ -57,21 +57,21 @@ export const LeftPaneComponent = React.memo((props) => { [dispatch], ) - const onClickPagesTab = React.useCallback(() => { - onClickTab(LeftMenuTab.Pages) - }, [onClickTab]) + const onMouseDownPagesTab = React.useCallback(() => { + onMouseDownTab(LeftMenuTab.Pages) + }, [onMouseDownTab]) - const onClickProjectTab = React.useCallback(() => { - onClickTab(LeftMenuTab.Project) - }, [onClickTab]) + const onMouseDownProjectTab = React.useCallback(() => { + onMouseDownTab(LeftMenuTab.Project) + }, [onMouseDownTab]) - const onClickNavigatorTab = React.useCallback(() => { - onClickTab(LeftMenuTab.Navigator) - }, [onClickTab]) + const onMouseDownNavigatorTab = React.useCallback(() => { + onMouseDownTab(LeftMenuTab.Navigator) + }, [onMouseDownTab]) - const onClickGithubTab = React.useCallback(() => { - onClickTab(LeftMenuTab.Github) - }, [onClickTab]) + const onMouseDownGithubTab = React.useCallback(() => { + onMouseDownTab(LeftMenuTab.Github) + }, [onMouseDownTab]) const isMyProject = useIsMyProject() @@ -126,23 +126,23 @@ export const LeftPaneComponent = React.memo((props) => { , )} , )} diff --git a/editor/src/components/navigator/navigator-item/navigator-condensed-entry.tsx b/editor/src/components/navigator/navigator-item/navigator-condensed-entry.tsx index 60f9e0afce4e..6f208b183679 100644 --- a/editor/src/components/navigator/navigator-item/navigator-condensed-entry.tsx +++ b/editor/src/components/navigator/navigator-item/navigator-condensed-entry.tsx @@ -20,7 +20,7 @@ import { LayoutIcon } from './layout-icon' import { DataReferenceCartoucheControl } from '../../inspector/sections/component-section/data-reference-cartouche' import { NavigatorRowClickableWrapper, - useGetNavigatorClickActions, + useGetNavigatorMouseDownActions, } from './navigator-item-clickable-wrapper' import type { ThemeObject } from '../../../uuiui/styles/theme/theme-helpers' import { useNavigatorSelectionBoundsForEntry } from './use-navigator-selection-bounds-for-entry' @@ -341,18 +341,18 @@ const CondensedEntryItemContent = React.memo( ]) }, [props.entry, dispatch, highlightedViews]) - const getClickActions = useGetNavigatorClickActions( + const getMouseDownActions = useGetNavigatorMouseDownActions( props.entry.elementPath, props.selected, condensedNavigatorRow([props.entry], 'leaf', props.indentation), ) - const onClick = React.useCallback( + const onMouseDown = React.useCallback( (e: React.MouseEvent) => { e.stopPropagation() - dispatch(getClickActions(e)) + dispatch(getMouseDownActions(e)) }, - [dispatch, getClickActions], + [dispatch, getMouseDownActions], ) return ( @@ -374,7 +374,7 @@ const CondensedEntryItemContent = React.memo( }} onMouseOver={onMouseOver} onMouseOut={onMouseOut} - onClick={onClick} + onMouseDown={onMouseDown} >
EP.pathsEqual(targetPath, view)) }, [selectedViews, targetPath]) - const getActions = useGetNavigatorClickActions(targetPath, selected, props.row) + const getMouseDownActions = useGetNavigatorMouseDownActions(targetPath, selected, props.row) - const onClick = React.useCallback( + const onMouseDown = React.useCallback( (e: React.MouseEvent) => { e.stopPropagation() e.preventDefault() - const actions = getActions(e) + const actions = getMouseDownActions(e) dispatch(actions) }, - [dispatch, getActions], + [dispatch, getMouseDownActions], ) return ( -
+
{props.children}
) @@ -68,11 +68,11 @@ export const NavigatorRowClickableWrapper = React.memo( ) NavigatorRowClickableWrapper.displayName = 'NavigatorRowClickableWrapper' -export function useGetNavigatorClickActions( +export function useGetNavigatorMouseDownActions( targetPath: ElementPath, selected: boolean, row: NavigatorRow, -) { +): (event: React.MouseEvent) => Array { const navigatorTargets = useRefEditorState(navigatorTargetsSelector) const selectedViews = useRefEditorState((store) => store.editor.selectedViews) const collapsedViews = useRefEditorState((store) => store.editor.navigator.collapsedViews) diff --git a/editor/src/components/navigator/navigator-item/navigator-item-components.tsx b/editor/src/components/navigator/navigator-item/navigator-item-components.tsx index 3fe002f4ea84..1686b791019d 100644 --- a/editor/src/components/navigator/navigator-item/navigator-item-components.tsx +++ b/editor/src/components/navigator/navigator-item/navigator-item-components.tsx @@ -180,7 +180,7 @@ interface VisiblityIndicatorProps { visibilityEnabled: boolean selected: boolean iconColor: IcnProps['color'] - onClick: () => void + onMouseDown: () => void } export const VisibilityIndicator: React.FunctionComponent< @@ -190,7 +190,7 @@ export const VisibilityIndicator: React.FunctionComponent< return ( + ) + }, []) + + const alignSelected = React.useCallback( + (alignment: Alignment) => { + if (activeAlignments[alignment]) { + const unsetAlignment = getUnsetAlignmentsActions() + .filter((a) => a.alignments.includes(alignment)) + .map((a) => a.action) + dispatch(unsetAlignment) + } else { + dispatch([alignSelectedViews(alignment)], 'everyone') + } + }, + [dispatch, activeAlignments, getUnsetAlignmentsActions], + ) + + const dropdownItems = React.useMemo(() => { + let items: DropdownMenuItem[] = [] + + if (hasActiveAlignments) { + items.push( + regularDropdownMenuItem({ + id: 'unset', + label: 'Unset', + onSelect: unsetAllAlignments, + }), + separatorDropdownMenuItem('sep'), + ) + } + + items.push( + regularDropdownMenuItem({ + id: 'distribute-horizontal', + label: 'Distribute Horizontal', + onSelect: distributeHorizontal, + disabled: disableDistribute, + icon: ( + + ), + }), + regularDropdownMenuItem({ + id: 'distribute-vertical', + label: 'Distribute Vertical', + onSelect: distributeVertical, + disabled: disableDistribute, + icon: ( + + ), + }), + ) + + return items + }, [ + disableDistribute, + distributeHorizontal, + distributeVertical, + hasActiveAlignments, + unsetAllAlignments, + ]) + + const chainValueJustify = React.useMemo(() => { + return activeAlignments.left + ? 'left' + : activeAlignments.hcenter + ? 'hcenter' + : activeAlignments.right + ? 'right' + : null + }, [activeAlignments]) + + const chainValueAlign = React.useMemo(() => { + return activeAlignments.top + ? 'top' + : activeAlignments.vcenter + ? 'vcenter' + : activeAlignments.bottom + ? 'bottom' + : null + }, [activeAlignments]) + + return ( + + + + + + + ) +}) +AlignmentButtons.displayName = 'AlignmentButtons' + +function useActiveAlignments(): ActiveAlignments { + const selectedViews = useRefEditorState((store) => store.editor.selectedViews) + + const jsxMetadata = useEditorState( + Substores.metadata, + (store) => store.editor.jsxMetadata, + 'useActiveAlignments jsxMetadata', + ) + + const isActive = React.useCallback( + (alignment: Alignment) => { + if (selectedViews.current.length === 0) { + return false + } + return selectedViews.current.every((view) => { + const isFlexOrGridChild = MetadataUtils.isFlexOrGridChild(jsxMetadata, view) + const { align, justify } = MetadataUtils.getRelativeAlignJustify(jsxMetadata, view) + + const meta = MetadataUtils.findElementByElementPath(jsxMetadata, view) + if (meta == null) { + return false + } + + const parent = MetadataUtils.findElementByElementPath(jsxMetadata, EP.parentPath(view)) + const parentFrame = + parent != null ? zeroRectIfNullOrInfinity(parent.globalFrame) : zeroRectangle + + switch (alignment) { + case 'top': + return isFlexOrGridChild + ? meta.specialSizeMeasurements[align] === 'flex-start' || + meta.specialSizeMeasurements[align] === 'start' + : meta.specialSizeMeasurements.offset.y === 0 + case 'bottom': + return isFlexOrGridChild + ? meta.specialSizeMeasurements[align] === 'flex-end' || + meta.specialSizeMeasurements[align] === 'end' + : parent != null && + meta.specialSizeMeasurements.offset.y === + parentFrame.height - meta.specialSizeMeasurements.clientHeight + case 'vcenter': + return isFlexOrGridChild + ? meta.specialSizeMeasurements[align] === 'center' + : parent != null && + meta.specialSizeMeasurements.offset.y === + Math.ceil( + parentFrame.height / 2 - meta.specialSizeMeasurements.clientHeight / 2, + ) + case 'left': + return isFlexOrGridChild + ? meta.specialSizeMeasurements[justify] === 'flex-start' || + meta.specialSizeMeasurements[justify] === 'start' + : meta.specialSizeMeasurements.offset.x === 0 + case 'right': + return isFlexOrGridChild + ? meta.specialSizeMeasurements[justify] === 'flex-end' || + meta.specialSizeMeasurements[justify] === 'end' + : parent != null && + meta.specialSizeMeasurements.offset.x === + parentFrame.width - meta.specialSizeMeasurements.clientWidth + case 'hcenter': + return isFlexOrGridChild + ? meta.specialSizeMeasurements[justify] === 'center' + : parent != null && + meta.specialSizeMeasurements.offset.x === + Math.ceil(parentFrame.width / 2 - meta.specialSizeMeasurements.clientWidth / 2) + default: + assertNever(alignment) + return false + } + }) + }, + [jsxMetadata, selectedViews], + ) + + return React.useMemo(() => { + return { + left: isActive('left'), + hcenter: isActive('hcenter'), + right: isActive('right'), + top: isActive('top'), + vcenter: isActive('vcenter'), + bottom: isActive('bottom'), + } + }, [isActive]) +} + +type UnsetAlignment = { + alignments: Alignment[] + action: EditorAction +} + +function useGetUnsetAlignmentsActions(activeAlignments: ActiveAlignments) { + const selectedViews = useRefEditorState((store) => store.editor.selectedViews) + + const jsxMetadata = useEditorState( + Substores.metadata, + (store) => store.editor.jsxMetadata, + 'useGetUnsetAlignmentsActions jsxMetadata', + ) + + return React.useCallback((): UnsetAlignment[] => { + const activeAlignmentsList = Object.entries(activeAlignments).reduce((acc, [key, set]) => { + if (set) { + return acc.concat(key as Alignment) + } + return acc + }, [] as Alignment[]) + + return mapDropNulls((path) => { + let actions: UnsetAlignment[] = [] + + const isFlexOrGridChild = MetadataUtils.isFlexOrGridChild(jsxMetadata, path) + const { align, justify } = MetadataUtils.getRelativeAlignJustify(jsxMetadata, path) + + if (activeAlignments.left || activeAlignments.hcenter || activeAlignments.right) { + const alignments: Alignment[] = activeAlignmentsList.filter( + (alignment) => alignment === 'left' || alignment === 'hcenter' || alignment === 'right', + ) + actions.push({ + action: unsetProperty(path, PP.create('style', isFlexOrGridChild ? justify : 'left')), + alignments: alignments, + }) + } + + if (activeAlignments.top || activeAlignments.vcenter || activeAlignments.bottom) { + const alignments: Alignment[] = activeAlignmentsList.filter( + (alignment) => alignment === 'top' || alignment === 'vcenter' || alignment === 'bottom', + ) + actions.push({ + action: unsetProperty(path, PP.create('style', isFlexOrGridChild ? align : 'top')), + alignments: alignments, + }) + } + + return actions + }, selectedViews.current).flat() + }, [activeAlignments, selectedViews, jsxMetadata]) +} diff --git a/editor/src/components/inspector/controls/option-chain-control.tsx b/editor/src/components/inspector/controls/option-chain-control.tsx index cdcf1b84b9fa..a0000f4fb299 100644 --- a/editor/src/components/inspector/controls/option-chain-control.tsx +++ b/editor/src/components/inspector/controls/option-chain-control.tsx @@ -16,6 +16,7 @@ export interface OptionChainOption { label?: string tooltip?: string forceCallOnSubmitValue?: boolean // Call the onSubmitValue again even when the control is already on that value + disabled?: boolean } export function getOptionControlTestId(testIdPrefix: string, postfix: string): string { @@ -93,6 +94,9 @@ export const OptionChainControl: React.FunctionComponent< value={props.value === option.value} // eslint-disable-next-line react/jsx-no-bind onSubmitValue={(isChecked: boolean) => { + if (option.disabled === true) { + return + } if (isChecked || option.forceCallOnSubmitValue) { props.onSubmitValue(option.value) } else { diff --git a/editor/src/components/inspector/inspector-common.ts b/editor/src/components/inspector/inspector-common.ts index 8718b4106c3f..e51e2fecd4fd 100644 --- a/editor/src/components/inspector/inspector-common.ts +++ b/editor/src/components/inspector/inspector-common.ts @@ -101,6 +101,7 @@ export function getFlexJustifyContent(value: string | null): FlexJustifyContent } export type FlexAlignment = StartCenterEnd | 'auto' | 'stretch' +export type SelfAlignment = FlexAlignment | 'end' | 'start' export function getFlexAlignment(value: string | null): FlexAlignment | null { switch (value) { @@ -119,6 +120,17 @@ export function getFlexAlignment(value: string | null): FlexAlignment | null { } } +export function getSelfAlignment(value: string | null): SelfAlignment | null { + switch (value) { + case 'end': + return 'end' + case 'start': + return 'start' + default: + return getFlexAlignment(value) + } +} + function stringToFlexDirection(str: string | null): FlexDirection | null { switch (str) { case 'row': diff --git a/editor/src/components/inspector/inspector.tsx b/editor/src/components/inspector/inspector.tsx index ead15872c320..e4ea5d8d688c 100644 --- a/editor/src/components/inspector/inspector.tsx +++ b/editor/src/components/inspector/inspector.tsx @@ -14,15 +14,9 @@ import * as PP from '../../core/shared/property-path' import * as EP from '../../core/shared/element-path' import Utils from '../../utils/utils' import { setFocus } from '../common/actions' -import type { Alignment, Distribution, EditorAction } from '../editor/action-types' +import type { EditorAction } from '../editor/action-types' import * as EditorActions from '../editor/actions/action-creators' -import { - alignSelectedViews, - distributeSelectedViews, - setProp_UNSAFE, - transientActions, - unsetProperty, -} from '../editor/actions/action-creators' +import { setProp_UNSAFE, transientActions, unsetProperty } from '../editor/actions/action-creators' import type { ElementsToRerender } from '../editor/store/editor-state' import { @@ -51,7 +45,6 @@ import { useKeepReferenceEqualityIfPossible, useKeepShallowReferenceEquality, } from '../../utils/react-performance' -import { Icn, useColorTheme, UtopiaTheme, FlexRow, Button, SquareButton } from '../../uuiui' import { getElementsToTarget } from './common/inspector-utils' import type { ElementPath, PropertyPath } from '../../core/shared/project-file-types' import { unless, when } from '../../utils/react-conditionals' @@ -112,128 +105,6 @@ export interface InspectorProps extends TargetSelectorSectionProps { selectedViews: Array } -interface AlignDistributeButtonProps { - onMouseUp: () => void - toolTip: string - iconType: string - disabled: boolean -} - -const AlignDistributeButton = React.memo( - (props: AlignDistributeButtonProps) => { - return ( - - - - ) - }, -) -AlignDistributeButton.displayName = 'AlignDistributeButton' - -const AlignmentButtons = React.memo((props: { numberOfTargets: number }) => { - const colorTheme = useColorTheme() - const dispatch = useDispatch() - const alignSelected = React.useCallback( - (alignment: Alignment) => { - dispatch([alignSelectedViews(alignment)], 'everyone') - }, - [dispatch], - ) - - const distributeSelected = React.useCallback( - (distribution: Distribution) => { - dispatch([distributeSelectedViews(distribution)], 'everyone') - }, - [dispatch], - ) - const disableAlign = props.numberOfTargets === 0 - const disableDistribute = props.numberOfTargets < 3 - const multipleTargets = props.numberOfTargets > 1 - - const alignLeft = React.useCallback(() => alignSelected('left'), [alignSelected]) - const alignHCenter = React.useCallback(() => alignSelected('hcenter'), [alignSelected]) - const alignRight = React.useCallback(() => alignSelected('right'), [alignSelected]) - const alignTop = React.useCallback(() => alignSelected('top'), [alignSelected]) - const alignVCenter = React.useCallback(() => alignSelected('vcenter'), [alignSelected]) - const alignBottom = React.useCallback(() => alignSelected('bottom'), [alignSelected]) - const distributeHorizontal = React.useCallback( - () => distributeSelected('horizontal'), - [distributeSelected], - ) - const distributeVertical = React.useCallback( - () => distributeSelected('vertical'), - [distributeSelected], - ) - - return ( - - - - - - - - - - - ) -}) -AlignmentButtons.displayName = 'AlignmentButtons' - function buildNonDefaultPositionPaths(propertyTarget: Array): Array { return [ stylePropPathMappingFn('right', propertyTarget), @@ -415,7 +286,6 @@ export const Inspector = React.memo((props: InspectorProps) => { const shouldShowStyleSectionContents = styleSectionOpen && !shouldHideInspectorSections const shouldShowAdvancedSectionContents = advancedSectionOpen && !shouldHideInspectorSections - const shouldShowAlignmentButtons = !isCodeElement && inspectorPreferences.includes('layout') const shouldShowClassNameSubsection = isTwindEnabled() && inspectorPreferences.includes('visual') const shouldShowTargetSelectorSection = canEdit && inspectorPreferences.includes('visual') const shouldShowFlexSection = @@ -475,14 +345,7 @@ export const Inspector = React.memo((props: InspectorProps) => { paddingBottom: 50, }} > - {rootElementIsSelected ? ( - - ) : ( - when( - shouldShowAlignmentButtons, - , - ) - )} + {when(rootElementIsSelected, )} {anyComponents || multiselectedContract === 'fragment' ? ( ) : null} diff --git a/editor/src/components/inspector/sections/layout-section/self-layout-subsection/frame-updating-layout-section.tsx b/editor/src/components/inspector/sections/layout-section/self-layout-subsection/frame-updating-layout-section.tsx index 0c729df8b904..794b24cbe1d9 100644 --- a/editor/src/components/inspector/sections/layout-section/self-layout-subsection/frame-updating-layout-section.tsx +++ b/editor/src/components/inspector/sections/layout-section/self-layout-subsection/frame-updating-layout-section.tsx @@ -93,8 +93,6 @@ interface LTWHPixelValues { export const FrameUpdatingLayoutSection = React.memo(() => { const dispatch = useDispatch() const metadataRef = useRefEditorState(metadataSelector) - const allElementsPropsRef = useRefEditorState((store) => store.editor.allElementProps) - const pathTreesRef = useRefEditorState((store) => store.editor.elementPathTree) const selectedViewsRef = useRefEditorState(selectedViewsSelector) const projectContentsRef = useRefEditorState((store) => store.editor.projectContents) const originalGlobalFrame: CanvasRectangle = useEditorState( @@ -292,14 +290,14 @@ export const FrameUpdatingLayoutSection = React.memo(() => { { const selectedElementContract = useEditorState( @@ -33,6 +30,32 @@ export const SimplifiedLayoutSubsection = React.memo(() => { const showWrapperSectionWarning = selectedElementContract === 'wrapper-div' + const isCodeElement = useEditorState( + Substores.metadata, + (store) => + store.editor.selectedViews.length > 0 && + store.editor.selectedViews.every( + (path) => + MetadataUtils.isConditional(path, store.editor.jsxMetadata) || + MetadataUtils.isExpressionOtherJavascript(path, store.editor.jsxMetadata) || + MetadataUtils.isJSXMapExpression(path, store.editor.jsxMetadata), + ), + 'SimplifiedLayoutSubsection isCodeElement', + ) + + const inspectorPreferences = useEditorState( + Substores.propertyControlsInfo, + (store) => + getInspectorPreferencesForTargets( + store.editor.selectedViews, + store.editor.propertyControlsInfo, + store.editor.projectContents, + ), + 'SimplifiedLayoutSubsection inspectorPreferences', + ) + + const shouldShowAlignmentButtons = !isCodeElement && inspectorPreferences.includes('layout') + return ( { {when( showLayoutSection, <> + {when(shouldShowAlignmentButtons, )} diff --git a/editor/src/core/model/element-metadata-utils.ts b/editor/src/core/model/element-metadata-utils.ts index af022ad5a6e8..fb5587eb39d7 100644 --- a/editor/src/core/model/element-metadata-utils.ts +++ b/editor/src/core/model/element-metadata-utils.ts @@ -630,6 +630,24 @@ export const MetadataUtils = { MetadataUtils.getFlexDirection(instance), ) }, + isFlexOrGridChild: function (jsxMetadata: ElementInstanceMetadataMap, path: ElementPath) { + return ( + MetadataUtils.isFlexLayoutedContainer( + MetadataUtils.findElementByElementPath(jsxMetadata, EP.parentPath(path)), + ) || MetadataUtils.isGridCell(jsxMetadata, path) + ) + }, + getRelativeAlignJustify: function ( + jsxMetadata: ElementInstanceMetadataMap, + path: ElementPath, + ): { align: 'alignSelf' | 'justifySelf'; justify: 'alignSelf' | 'justifySelf' } { + const direction = MetadataUtils.getSimpleFlexDirection( + MetadataUtils.findElementByElementPath(jsxMetadata, EP.parentPath(path)), + ) + const align = direction.direction === 'horizontal' ? 'alignSelf' : 'justifySelf' + const justify = direction.direction === 'horizontal' ? 'justifySelf' : 'alignSelf' + return { align, justify } + }, flexDirectionToSimpleFlexDirection: function (flexDirection: FlexDirection): { direction: Direction forwardOrReverse: ForwardOrReverse diff --git a/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap b/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap index 911b3ef6a132..0dc742581b14 100644 --- a/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap +++ b/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap @@ -112,7 +112,7 @@ Array [ "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/Symbol(react.memo)()", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/Symbol(react.memo)()", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/UtopiaSpiedExoticType(Symbol(react.fragment))", - "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/Symbol(react.memo)(AlignmentButtons)", + "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/UtopiaSpiedFunctionComponent(RootElementIndicator)", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/UtopiaSpiedClass(ComponentSection)", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/UtopiaSpiedFunctionComponent(InspectorSectionHeader)", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/Symbol(react.memo)(FragmentSection)", @@ -278,6 +278,133 @@ Array [ "/div/UtopiaSpiedFunctionComponent(DropdownIndicator)/UtopiaSpiedFunctionComponent(DropdownIndicator)/Symbol(react.forward_ref)(render)", "/UtopiaSpiedFunctionComponent(DropdownIndicator)/UtopiaSpiedFunctionComponent(DropdownIndicator)/Symbol(react.forward_ref)(render)/UtopiaSpiedExoticType(Symbol(react.context))", "/Symbol(react.forward_ref)(render)/UtopiaSpiedExoticType(Symbol(react.context))/Symbol(react.context)/div", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)(Icon)", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)(Icon)", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)", + "/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div//Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-0'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-0'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-1'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-1'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-2'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-2'", + "/label/div/Icon/img", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div//Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-0'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-0'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-1'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-1'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-2'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-2'", + "/label/div/Icon/img", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(Styled(div))", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(DropdownMenuTrigger)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-unset'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Separator)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-distribute-horizontal'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-distribute-vertical'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(Styled.DropdownMenuContent)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(DropdownMenuPortal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(DropdownMenu)", + "/Symbol(react.forward_ref)(Primitive.button)/button/Symbol(react.forward_ref)(Styled(div))/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/FixedHugDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())", "/FixedHugDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedClass(StateManager)", @@ -772,7 +899,7 @@ Array [ "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/Symbol(react.memo)()", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/Symbol(react.memo)()", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/UtopiaSpiedExoticType(Symbol(react.fragment))", - "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/Symbol(react.memo)(AlignmentButtons)", + "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/UtopiaSpiedFunctionComponent(RootElementIndicator)", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/UtopiaSpiedClass(ComponentSection)", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/UtopiaSpiedFunctionComponent(InspectorSectionHeader)", "/UtopiaSpiedExoticType(Symbol(react.provider))/Symbol(react.provider)/Inspector/Symbol(react.memo)(FragmentSection)", @@ -877,6 +1004,133 @@ Array [ "/div/UtopiaSpiedFunctionComponent(DropdownIndicator)/UtopiaSpiedFunctionComponent(DropdownIndicator)/Symbol(react.forward_ref)(render)", "/UtopiaSpiedFunctionComponent(DropdownIndicator)/UtopiaSpiedFunctionComponent(DropdownIndicator)/Symbol(react.forward_ref)(render)/UtopiaSpiedExoticType(Symbol(react.context))", "/Symbol(react.forward_ref)(render)/UtopiaSpiedExoticType(Symbol(react.context))/Symbol(react.context)/div", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)(Icon)", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)(Icon)", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)", + "/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div//Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-0'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-0'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-1'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-1'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-2'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-2'", + "/label/div/Icon/img", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div//Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-0'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-0'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-1'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-1'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-2'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-2'", + "/label/div/Icon/img", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(Styled(div))", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(DropdownMenuTrigger)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-unset'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Separator)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-distribute-horizontal'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-distribute-vertical'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(Styled.DropdownMenuContent)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(DropdownMenuPortal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(DropdownMenu)", + "/Symbol(react.forward_ref)(Primitive.button)/button/Symbol(react.forward_ref)(Styled(div))/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/FixedHugDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())", "/FixedHugDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedClass(StateManager)", @@ -1640,6 +1894,133 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)", "/div/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)/UtopiaSpiedFunctionComponent($)", "/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)/UtopiaSpiedFunctionComponent($)/UtopiaSpiedExoticType(Symbol(react.provider))", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)(Icon)", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)(Icon)", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)", + "/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div//Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-0'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-0'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-1'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-1'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-2'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-2'", + "/label/div/Icon/img", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div//Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-0'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-0'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-1'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-1'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-2'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-2'", + "/label/div/Icon/img", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(Styled(div))", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(DropdownMenuTrigger)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-unset'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Separator)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-distribute-horizontal'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-distribute-vertical'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(Styled.DropdownMenuContent)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(DropdownMenuPortal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(DropdownMenu)", + "/Symbol(react.forward_ref)(Primitive.button)/button/Symbol(react.forward_ref)(Styled(div))/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/FixedHugDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())", "/FixedHugDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedClass(StateManager)", @@ -2562,6 +2943,133 @@ Array [ "/UtopiaSpiedExoticType(Symbol(react.fragment))/PropertyControlsSection/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/PropertyControlsSection/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", "/div/div/Symbol(react.forward_ref)(Styled(span))/span", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)(Icon)", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)(Icon)", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.memo)()", + "/div/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)", + "/UtopiaSpiedExoticType(Symbol(react.fragment))/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/AlignmentButtons/Symbol(react.forward_ref)(UIGridRow)/Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div//Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-0'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-0'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-1'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-1'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-2'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-2'", + "/label/div/Icon/img", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div//Symbol(react.forward_ref)(EmotionCssPropInternal)/div", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-0'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-0'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-1'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-1'", + "/label/div/Icon/img", + "/div/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/input", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.memo)(Icon)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='left-2'", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/UtopiaSpiedFunctionComponent(Tooltip)", + "/div/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedFunctionComponent(OptionControl)/div", + "/UtopiaSpiedFunctionComponent(OptionControl)/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)", + "/div/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)", + "/UtopiaSpiedFunctionComponent(Tooltip)/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/Symbol(react.forward_ref)(TippyWrapper)/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/UtopiaSpiedFunctionComponent(Tippy)/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(EmotionCssPropInternal)/label:data-testid='left-2'", + "/label/div/Icon/img", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(Styled(div))", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(DropdownMenuTrigger)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-unset'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)(Separator)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-distribute-horizontal'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.memo)()", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//div", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//span", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(EmotionCssPropInternal):data-testid='item-container-distribute-vertical'", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//Symbol(react.forward_ref)(Styled.DropdownMenuContent)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(DropdownMenuPortal)", + "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div//UtopiaSpiedFunctionComponent(DropdownMenu)", + "/Symbol(react.forward_ref)(Primitive.button)/button/Symbol(react.forward_ref)(Styled(div))/div", "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/FixedHugDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())", "/FixedHugDropdown/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)", "/Symbol(react.memo)(Symbol(react.forward_ref)())/Symbol(react.forward_ref)()/Symbol(react.forward_ref)(EmotionCssPropInternal)/UtopiaSpiedClass(StateManager)", diff --git a/editor/src/core/performance/performance-regression-tests.spec.tsx b/editor/src/core/performance/performance-regression-tests.spec.tsx index 3c487db99578..b5f21e06e6c8 100644 --- a/editor/src/core/performance/performance-regression-tests.spec.tsx +++ b/editor/src/core/performance/performance-regression-tests.spec.tsx @@ -65,7 +65,7 @@ describe('React Render Count Tests -', () => { const renderCountAfter = renderResult.getNumberOfRenders() // if this breaks, GREAT NEWS but update the test please :) - expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`737`) + expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`864`) expect(renderResult.getRenderInfo()).toMatchSnapshot() }) @@ -127,7 +127,7 @@ describe('React Render Count Tests -', () => { const renderCountAfter = renderResult.getNumberOfRenders() // if this breaks, GREAT NEWS but update the test please :) - expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`989`) + expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`1116`) expect(renderResult.getRenderInfo()).toMatchSnapshot() }) @@ -183,7 +183,7 @@ describe('React Render Count Tests -', () => { const renderCountAfter = renderResult.getNumberOfRenders() // if this breaks, GREAT NEWS but update the test please :) - expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`530`) + expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`657`) expect(renderResult.getRenderInfo()).toMatchSnapshot() }) @@ -249,7 +249,7 @@ describe('React Render Count Tests -', () => { const renderCountAfter = renderResult.getNumberOfRenders() // if this breaks, GREAT NEWS but update the test please :) - expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`655`) + expect(renderCountAfter - renderCountBefore).toMatchInlineSnapshot(`782`) expect(renderResult.getRenderInfo()).toMatchSnapshot() }) }) diff --git a/editor/src/core/shared/element-template.ts b/editor/src/core/shared/element-template.ts index 63442cce8e72..f0c68e7b10f1 100644 --- a/editor/src/core/shared/element-template.ts +++ b/editor/src/core/shared/element-template.ts @@ -34,7 +34,11 @@ import { firstLetterIsLowerCase } from './string-utils' import { intrinsicHTMLElementNamesAsStrings } from './dom-utils' import type { MapLike } from 'typescript' import { forceNotNull } from './optional-utils' -import type { FlexAlignment, FlexJustifyContent } from '../../components/inspector/inspector-common' +import type { + FlexAlignment, + FlexJustifyContent, + SelfAlignment, +} from '../../components/inspector/inspector-common' import { allComments } from './utopia-flags' import type { Optic } from './optics/optics' import { fromField } from './optics/optic-creators' @@ -2812,6 +2816,8 @@ export interface SpecialSizeMeasurements { justifyContent: FlexJustifyContent | null alignContent: FlexJustifyContent | null alignItems: FlexAlignment | null + alignSelf: SelfAlignment | null + justifySelf: SelfAlignment | null htmlElementName: string renderedChildrenCount: number globalContentBoxForChildren: MaybeInfinityCanvasRectangle | null @@ -2882,6 +2888,8 @@ export function specialSizeMeasurements( elementGridPropertiesFromProps: GridElementProperties, rowGap: number | null, columnGap: number | null, + justifySelf: SelfAlignment | null, + alignSelf: SelfAlignment | null, ): SpecialSizeMeasurements { return { offset, @@ -2932,6 +2940,8 @@ export function specialSizeMeasurements( elementGridPropertiesFromProps, rowGap, columnGap, + justifySelf, + alignSelf, } } @@ -3009,6 +3019,8 @@ export const emptySpecialSizeMeasurements = specialSizeMeasurements( }, null, null, + null, + null, ) export function walkElement( diff --git a/editor/src/uuiui/radix-components.tsx b/editor/src/uuiui/radix-components.tsx index 1e5e446bd83d..4d1192f407b0 100644 --- a/editor/src/uuiui/radix-components.tsx +++ b/editor/src/uuiui/radix-components.tsx @@ -151,6 +151,7 @@ export const DropdownMenu = React.memo((props) => { key={item.id} onSelect={item.onSelect} css={{ + opacity: item.disabled ? 0.5 : 1, ':hover': { backgroundColor: item.danger ? colorTheme.errorForeground.value From 94a6c071a3bbe8e0586994b20af376cddef39c3b Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Fri, 27 Sep 2024 02:10:33 +0300 Subject: [PATCH 052/272] chore(editor): remove unneeded network call (#6399) **Problem:** We have a `/permissions` network call on our loading critical path, but its result is not being used (yet?) **Fix:** Remove the call for now since it is sometimes blocking loading the editor (competing for network) - [X] I opened a hydrogen project and it loaded - [X] I could navigate to various routes in Preview mode --- editor/src/templates/editor.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/editor/src/templates/editor.tsx b/editor/src/templates/editor.tsx index f6bcba73af2a..da7f5d0b2c6c 100644 --- a/editor/src/templates/editor.tsx +++ b/editor/src/templates/editor.tsx @@ -34,7 +34,6 @@ import { import { getLoginState, getUserConfiguration, - getUserPermissions, startPollingLoginState, } from '../components/editor/server' import type { DispatchResult } from '../components/editor/store/dispatch' @@ -347,10 +346,7 @@ export class Editor { const projectId = getProjectID() startPollingLoginState(this.boundDispatch, loginState) this.storedState.userState.loginState = loginState - void Promise.all([ - getUserConfiguration(loginState), - getUserPermissions(loginState, projectId), - ]).then(([shortcutConfiguration, permissions]) => { + void getUserConfiguration(loginState).then((shortcutConfiguration) => { const userState = { ...this.storedState.userState, ...shortcutConfiguration, From fde6292978e24a7bf8310acbdb5e0cebe33cced9 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Fri, 27 Sep 2024 09:42:17 +0200 Subject: [PATCH 053/272] Fix alignment controls duplicate key (#6417) This PR fixes a typo error in https://github.com/concrete-utopia/utopia/pull/6413 that caused duplicate keys errors when rendering the new alignment controls. --------- Co-authored-by: Balint Gabor <127662+gbalint@users.noreply.github.com> --- .../inspector/alignment-buttons.tsx | 12 +-- ...performance-regression-tests.spec.tsx.snap | 96 +++++++++---------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/editor/src/components/inspector/alignment-buttons.tsx b/editor/src/components/inspector/alignment-buttons.tsx index e34735130ae2..b99efdfd7de9 100644 --- a/editor/src/components/inspector/alignment-buttons.tsx +++ b/editor/src/components/inspector/alignment-buttons.tsx @@ -174,9 +174,9 @@ export const AlignmentButtons = React.memo(() => { return ( { ]} /> Date: Sun, 29 Sep 2024 14:37:39 +0300 Subject: [PATCH 054/272] fix(parse): mutable highlight bounds (#6419) This PR optimizes highlight bounds manipulation by: 1. Making the `highlightBounds` mutable *only when being edited* - to avoid re-creating them when inside loops 2. Replaces `for-of` implementation with `reduce` and mutable assignment, which is a bit more performant: (going with option 2 instead of the current 1): image **Manual Tests:** I hereby swear that: - [X] I opened a hydrogen project and it loaded - [X] I could navigate to various routes in Preview mode --- .../parser-printer/parser-printer-parsing.ts | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/editor/src/core/workers/parser-printer/parser-printer-parsing.ts b/editor/src/core/workers/parser-printer/parser-printer-parsing.ts index f9843fc0ddb9..bb9387d43563 100644 --- a/editor/src/core/workers/parser-printer/parser-printer-parsing.ts +++ b/editor/src/core/workers/parser-printer/parser-printer-parsing.ts @@ -1100,7 +1100,7 @@ function parseOtherJavaScript( } let parsedElementsWithin: ElementsWithinInPosition = [] - let highlightBounds = existingHighlightBounds + let highlightBounds_MUTABLE = { ...existingHighlightBounds } function addToParsedElementsWithin( currentScope: Array, @@ -1114,7 +1114,7 @@ function parseOtherJavaScript( imports, topLevelNames, propsObjectName, - highlightBounds, + highlightBounds_MUTABLE, alreadyExistingUIDs, applySteganography, ) @@ -1133,7 +1133,10 @@ function parseOtherJavaScript( ? firstChild.startColumn - startColumnShift : firstChild.startColumn, }) - highlightBounds = mergeHighlightBounds(highlightBounds, success.highlightBounds) + highlightBounds_MUTABLE = mergeHighlightBounds( + highlightBounds_MUTABLE, + success.highlightBounds, + ) fastForEach(success.definedElsewhere, (val) => pushToDefinedElsewhereIfNotThere(currentScope, val), @@ -1513,11 +1516,11 @@ function parseOtherJavaScript( return mapEither((created) => { // Add in the bounds for the entire value. - highlightBounds = addToHighlightBounds( - highlightBounds, + addToHighlightBoundsMutate( + highlightBounds_MUTABLE, buildHighlightBoundsForExpressionsAndText(sourceFile, expressionsAndTexts, created.uid), ) - return withParserMetadata(created, highlightBounds, propsUsed, definedElsewhere) + return withParserMetadata(created, highlightBounds_MUTABLE, propsUsed, definedElsewhere) }, failOnNullResult(create(code, definedWithin, definedElsewhere, fileNode, parsedElementsWithin, paramsToUse, statements))) } } @@ -2995,11 +2998,13 @@ function buildHighlightBoundsForUids( function mergeHighlightBounds( ...multipleBounds: Array ): Readonly { - let result: HighlightBoundsForUids = {} + const acc: HighlightBoundsForUids = {} for (const bounds of multipleBounds) { - Object.assign(result, bounds) + for (const key in bounds) { + acc[key] = bounds[key] + } } - return result + return acc } function merge2WithParserMetadata( @@ -3032,17 +3037,14 @@ function addBoundsIntoWithParser( } } -function addToHighlightBounds( - existing: Readonly, +function addToHighlightBoundsMutate( + existing: HighlightBoundsForUids, toAdd: HighlightBounds | null, -): Readonly { - if (toAdd == null) { - return existing - } else { - let result: HighlightBoundsForUids = { ...existing } - result[toAdd.uid] = toAdd - return result +): HighlightBoundsForUids { + if (toAdd != null) { + existing[toAdd.uid] = toAdd } + return existing } interface UpdateUIDResult { From 3cf3883b613cecb9bc28714e7c56dba41dc46ed2 Mon Sep 17 00:00:00 2001 From: Sean Parsons <217400+seanparsons@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:35:44 +0100 Subject: [PATCH 055/272] performance(editor) Mutation and Resize observers now async the DOM walker. (#6414) - Added `queueUpDomWalker` function that manages the triggering of the dispatch of the dom walker action. - Observers now call `queueUpDomWalker` so that only one run is triggered at some point soon. --- .../canvas/dom-walker.spec.browser2.tsx | 30 ++++++--- editor/src/components/canvas/dom-walker.ts | 14 +++- ...performance-regression-tests.spec.tsx.snap | 64 +++++++++---------- 3 files changed, 65 insertions(+), 43 deletions(-) diff --git a/editor/src/components/canvas/dom-walker.spec.browser2.tsx b/editor/src/components/canvas/dom-walker.spec.browser2.tsx index 43d4423bc2d5..5e24dfa510cd 100644 --- a/editor/src/components/canvas/dom-walker.spec.browser2.tsx +++ b/editor/src/components/canvas/dom-walker.spec.browser2.tsx @@ -33,9 +33,27 @@ import { mouseClickAtPoint, mouseDownAtPoint, mouseMoveToPoint } from './event-h import { EditorModes } from '../editor/editor-modes' import { MetadataUtils } from '../../core/model/element-metadata-utils' import { optionalMap } from '../../core/shared/optional-utils' +import type { SinonFakeTimers } from 'sinon' +import sinon from 'sinon' disableStoredStateforTests() +function configureSetupTeardown(): { clock: { current: SinonFakeTimers } } { + let clock: { current: SinonFakeTimers } = { current: null as any } // it will be non-null thanks to beforeEach + beforeEach(function () { + // TODO there is something wrong with sinon fake timers here that remotely break other tests that come after these. If your new browser tests are broken, this may be the reason. + clock.current = sinon.useFakeTimers({ + // the timers will tick so the editor is not totally broken, but we can fast-forward time at will + // WARNING: the Sinon fake timers will advance in 20ms increments + shouldAdvanceTime: true, + }) + }) + afterEach(function () { + clock.current?.restore() + }) + return { clock: clock } +} + describe('DOM Walker', () => { it('Test Project metadata contains entry for all elements', async () => { const renderResult = await renderTestEditorWithCode(TestProject, 'await-first-dom-report') @@ -413,6 +431,7 @@ describe('Capturing closest offset parent', () => { }) describe('Observing runtime changes', () => { + const { clock } = configureSetupTeardown() const changingProjectCode = ` import * as React from 'react' import { Scene, Storyboard } from 'utopia-api' @@ -502,8 +521,6 @@ describe('Observing runtime changes', () => { ) expect(metadataBefore).toBeNull() - const recordedActionsBefore = [...renderResult.getRecordedActions()] - const buttonToClick = renderResult.renderedDOM.getByTestId('click-me') const buttonToClickBounds = buttonToClick.getBoundingClientRect() const clickPoint = { @@ -512,14 +529,9 @@ describe('Observing runtime changes', () => { } await mouseClickAtPoint(buttonToClick, clickPoint) - await wait(20) + clock.current.tick(100) await renderResult.getDispatchFollowUpActionsFinished() - - const recordedActionsAfter = [...renderResult.getRecordedActions()] - const recordedActionsDuring = recordedActionsAfter.slice(recordedActionsBefore.length) - - const runDomWalkerActions = recordedActionsDuring.filter((a) => a.action === 'RUN_DOM_WALKER') - expect(runDomWalkerActions.length).toEqual(2) // Both the resize observer and mutation observer will fire + clock.current.tick(100) // Check there is metadata for the target at the end const metadataAfter = MetadataUtils.findElementByElementPath( diff --git a/editor/src/components/canvas/dom-walker.ts b/editor/src/components/canvas/dom-walker.ts index 50c273f01bb7..5b2ea0ba4de3 100644 --- a/editor/src/components/canvas/dom-walker.ts +++ b/editor/src/components/canvas/dom-walker.ts @@ -322,6 +322,16 @@ export function initDomWalkerObservers( editorStore: UtopiaStoreAPI, dispatch: EditorDispatch, ): { resizeObserver: ResizeObserver; mutationObserver: MutationObserver } { + let domWalkerTimeoutID: number | null = null + function queueUpDomWalker(): void { + if (domWalkerTimeoutID == null) { + domWalkerTimeoutID = window.setTimeout(() => { + dispatch([runDOMWalker()]) + domWalkerTimeoutID = null + }) + } + } + // Warning: I modified this code so it runs in all modes, not just in live mode. We still don't trigger // the DOM walker during canvas interactions, so the performance impact doesn't seem that bad. But it is // necessary, because after remix navigation, and after dynamic changes coming from loaders sometimes the @@ -352,7 +362,7 @@ export function initDomWalkerObservers( } } if (shouldRunDOMWalker) { - dispatch([runDOMWalker()]) + queueUpDomWalker() } } }) @@ -384,7 +394,7 @@ export function initDomWalkerObservers( } } if (shouldRunDOMWalker) { - dispatch([runDOMWalker()]) + queueUpDomWalker() } } }) diff --git a/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap b/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap index fb7e636a06dc..8f9197517fbc 100644 --- a/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap +++ b/editor/src/core/performance/__snapshots__/performance-regression-tests.spec.tsx.snap @@ -2460,6 +2460,22 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)", "/div/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)/UtopiaSpiedFunctionComponent($)", "/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)/UtopiaSpiedFunctionComponent($)/UtopiaSpiedExoticType(Symbol(react.provider))", + "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", + "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", + "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", + "/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)(Storyboard)", + "/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)/Storyboard/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/Storyboard/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)()", + "/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)()//Symbol(react.memo)()", + "/Symbol(react.memo)()///UtopiaSpiedFunctionComponent(View)", + "///UtopiaSpiedFunctionComponent(View)/div", + "/UtopiaSpiedFunctionComponent(View)/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))", + "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)", + "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)", + "/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)", + "/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)/div", + "/UtopiaSpiedFunctionComponent(View)/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)", + "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)/div", "/UtopiaSpiedFunctionComponent(SimpleFlexColumn)/div//UtopiaSpiedClass(EditorCanvas)", "/UtopiaSpiedFunctionComponent(SimpleFlexColumn)/div//Symbol(react.memo)(FloatingPostActionMenu)", "/UtopiaSpiedFunctionComponent(SimpleFlexColumn)/div//div", @@ -2551,22 +2567,6 @@ Array [ "/Symbol(react.forward_ref)(EmotionCssPropInternal)/div/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)", "/div/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)/UtopiaSpiedFunctionComponent($)", "/UtopiaSpiedFunctionComponent(ContextMenu)/UtopiaSpiedFunctionComponent(it)/UtopiaSpiedFunctionComponent($)/UtopiaSpiedExoticType(Symbol(react.provider))", - "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", - "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", - "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", - "/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)(Storyboard)", - "/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)/Storyboard/UtopiaSpiedExoticType(Symbol(react.fragment))", - "/Storyboard/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)()", - "/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)()//Symbol(react.memo)()", - "/Symbol(react.memo)()///UtopiaSpiedFunctionComponent(View)", - "///UtopiaSpiedFunctionComponent(View)/div", - "/UtopiaSpiedFunctionComponent(View)/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))", - "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)", - "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)", - "/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)", - "/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)/div", - "/UtopiaSpiedFunctionComponent(View)/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)", - "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)/div", ] `; @@ -3387,6 +3387,22 @@ Array [ "/div/div/UtopiaSpiedFunctionComponent(NewCanvasControlsInner)/Symbol(react.memo)(SelectionAreaRectangle)", "/div/div/UtopiaSpiedFunctionComponent(NewCanvasControlsInner)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/Symbol(react.forward_ref)(Styled(div))/div/Symbol(react.forward_ref)(Styled(div))/div", + "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", + "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", + "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", + "/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)(Storyboard)", + "/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)/Storyboard/UtopiaSpiedExoticType(Symbol(react.fragment))", + "/Storyboard/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)()", + "/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)()//Symbol(react.memo)()", + "/Symbol(react.memo)()///UtopiaSpiedFunctionComponent(View)", + "///UtopiaSpiedFunctionComponent(View)/div", + "/UtopiaSpiedFunctionComponent(View)/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))", + "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)", + "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)", + "/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)", + "/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)/div", + "/UtopiaSpiedFunctionComponent(View)/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)", + "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)/div", "/UtopiaSpiedFunctionComponent(SimpleFlexColumn)/div//UtopiaSpiedClass(EditorCanvas)", "/UtopiaSpiedFunctionComponent(SimpleFlexColumn)/div//Symbol(react.memo)(FloatingPostActionMenu)", "/UtopiaSpiedFunctionComponent(SimpleFlexColumn)/div//div", @@ -3420,21 +3436,5 @@ Array [ "/div/div/UtopiaSpiedFunctionComponent(NewCanvasControlsInner)/Symbol(react.memo)(SelectionAreaRectangle)", "/div/div/UtopiaSpiedFunctionComponent(NewCanvasControlsInner)/UtopiaSpiedExoticType(Symbol(react.fragment))", "/Symbol(react.forward_ref)(Styled(div))/div/Symbol(react.forward_ref)(Styled(div))/div", - "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", - "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", - "/UtopiaSpiedFunctionComponent(Provider)/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)", - "/UtopiaSpiedExoticType(Symbol(react.fragment))/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)(Storyboard)", - "/UtopiaSpiedFunctionComponent(ComponentRenderer(storyboard))/Symbol(react.forward_ref)(SpyWrapper)/Storyboard/UtopiaSpiedExoticType(Symbol(react.fragment))", - "/Storyboard/UtopiaSpiedExoticType(Symbol(react.fragment))/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)()", - "/Symbol(react.forward_ref)(SpyWrapper)/Symbol(react.memo)()//Symbol(react.memo)()", - "/Symbol(react.memo)()///UtopiaSpiedFunctionComponent(View)", - "///UtopiaSpiedFunctionComponent(View)/div", - "/UtopiaSpiedFunctionComponent(View)/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))", - "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)", - "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)", - "/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)", - "/UtopiaSpiedFunctionComponent(ComponentRenderer(App))/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)/div", - "/UtopiaSpiedFunctionComponent(View)/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)", - "/div/Symbol(react.forward_ref)(SpyWrapper)/UtopiaSpiedFunctionComponent(View)/div", ] `; From ef8c8ed6820d7a54084f1f93a2763328606c5d89 Mon Sep 17 00:00:00 2001 From: Sean Parsons <217400+seanparsons@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:36:16 +0100 Subject: [PATCH 056/272] refactor(strategies) Mandatory Elements To Rerender For Strategies (#6408) - Added `combineElementsToRerender` utility function. - Added `appendElementsToRerenderToApplyResult` utility function. - Added `StrategyApplicationResult.elementsToRerender`. - Removed `setElementsToRerenderCommand` and `appendElementsToRerenderCommand` and the associated supporting code. - Moved values originally passed to `setElementsToRerenderCommand` to the new parameter that `strategyApplicationResult` now has. - Moved values originally passed to `appendElementsToRerenderCommand` to a call to `appendElementsToRerenderToApplyResult`. - Added `applyElementsToRerenderFromStrategyResult` utility function. - Hooked in the `applyElementsToRerenderFromStrategyResult` function into various strategy functions to update the `EditorState`. --- .../canvas-strategies/canvas-strategies.tsx | 13 ++ .../canvas-strategy-types.ts | 6 +- .../absolute-duplicate-strategy.tsx | 6 +- ...absolute-reparent-strategy-canvas.spec.tsx | 12 +- .../absolute-reparent-strategy.spec.tsx | 12 +- .../strategies/absolute-reparent-strategy.tsx | 6 +- .../absolute-resize-bounding-box-strategy.tsx | 31 +++-- .../strategies/ancestor-metastrategy.tsx | 71 ++++++---- .../strategies/basic-resize-strategy.tsx | 41 +++--- .../convert-to-absolute-and-move-strategy.tsx | 11 +- .../drag-to-insert-metastrategy.tsx | 5 + .../strategies/drag-to-move-metastrategy.tsx | 31 +++-- .../draw-to-insert-metastrategy.tsx | 10 ++ .../draw-to-insert-text-strategy.tsx | 44 +++--- .../flex-reparent-to-absolute-strategy.tsx | 7 +- .../strategies/flex-resize-basic-strategy.tsx | 41 +++--- .../strategies/flex-resize-strategy.tsx | 41 +++--- .../grid-draw-to-insert-strategy.tsx | 5 + .../grid-rearrange-keyboard-strategy.ts | 4 + .../grid-rearrange-move-duplicate-strategy.ts | 4 +- .../grid-rearrange-move-strategy.ts | 4 + .../strategies/grid-reparent-strategy.tsx | 3 +- .../grid-resize-element-strategy.ts | 4 + .../keyboard-absolute-move-strategy.ts | 5 +- .../keyboard-absolute-resize-strategy.tsx | 5 +- .../strategies/keyboard-reorder-strategy.ts | 10 +- .../keyboard-set-font-size-strategy.tsx | 2 +- .../keyboard-set-font-weight-strategy.tsx | 8 +- .../keyboard-set-opacity-strategy.tsx | 8 +- .../rearrange-grid-swap-strategy.ts | 8 +- .../strategies/reorder-slider-strategy.tsx | 7 +- .../strategies/reorder-utils.ts | 15 +- .../reparent-as-static-strategy.tsx | 4 +- .../reparent-helpers/reparent-helpers.ts | 7 +- .../strategies/resize-grid-strategy.ts | 9 +- .../strategies/set-border-radius-strategy.tsx | 34 ++--- .../strategies/set-flex-gap-strategy.tsx | 52 ++++--- .../strategies/set-grid-gap-strategy.tsx | 52 ++++--- .../strategies/set-padding-strategy.tsx | 131 ++++++++++-------- ...shared-absolute-resize-strategy-helpers.ts | 6 +- .../shared-move-strategies-helpers.ts | 58 ++++---- .../components/canvas/commands/commands.ts | 14 -- .../set-elements-to-rerender-command.ts | 85 ------------ .../canvas-strategy-picker.spec.browser2.tsx | 8 +- .../src/components/editor/actions/actions.tsx | 9 +- .../editor/store/dispatch-strategies.spec.tsx | 11 +- .../editor/store/dispatch-strategies.tsx | 54 +++++--- .../components/editor/store/editor-state.ts | 11 ++ 48 files changed, 557 insertions(+), 468 deletions(-) delete mode 100644 editor/src/components/canvas/commands/set-elements-to-rerender-command.ts diff --git a/editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx b/editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx index 02751f5b3c75..a43af7b2c7dc 100644 --- a/editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx +++ b/editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx @@ -465,6 +465,19 @@ export function applyCanvasStrategy( return strategy.apply(strategyLifecycle) } +export function applyElementsToRerenderFromStrategyResult( + editorState: EditorState, + strategyResult: StrategyApplicationResult, +): EditorState { + return { + ...editorState, + canvas: { + ...editorState.canvas, + elementsToRerender: strategyResult.elementsToRerender, + }, + } +} + export function useDelayedEditorState( selector: StateSelector, selectorName: string, diff --git a/editor/src/components/canvas/canvas-strategies/canvas-strategy-types.ts b/editor/src/components/canvas/canvas-strategies/canvas-strategy-types.ts index dff0105a300e..4a0686b16e2c 100644 --- a/editor/src/components/canvas/canvas-strategies/canvas-strategy-types.ts +++ b/editor/src/components/canvas/canvas-strategies/canvas-strategy-types.ts @@ -7,7 +7,7 @@ import type { ElementPath, NodeModules } from '../../../core/shared/project-file import type { ProjectContentTreeRoot } from '../../assets' import type { PropertyControlsInfo } from '../../custom-code/code-file' import type { InsertionSubject } from '../../editor/editor-modes' -import type { AllElementProps } from '../../editor/store/editor-state' +import type { AllElementProps, ElementsToRerender } from '../../editor/store/editor-state' import type { CanvasCommand } from '../commands/commands' import type { ActiveFrameAction } from '../commands/set-active-frames-command' import type { StrategyApplicationStatus } from './interaction-state' @@ -53,23 +53,27 @@ export function defaultCustomStrategyState(): CustomStrategyState { export interface StrategyApplicationResult { commands: Array + elementsToRerender: ElementsToRerender customStatePatch: CustomStrategyStatePatch status: StrategyApplicationStatus } export const emptyStrategyApplicationResult: StrategyApplicationResult = { commands: [], + elementsToRerender: 'rerender-all-elements', customStatePatch: {}, status: 'success', } export function strategyApplicationResult( commands: Array, + elementsToRerender: ElementsToRerender, customStatePatch: CustomStrategyStatePatch = {}, status: StrategyApplicationStatus = 'success', ): StrategyApplicationResult { return { commands: commands, + elementsToRerender: elementsToRerender, customStatePatch: customStatePatch, status: status, } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-duplicate-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-duplicate-strategy.tsx index 2dff81adbae2..9fae9c8996d2 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-duplicate-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-duplicate-strategy.tsx @@ -12,7 +12,7 @@ import type { CanvasCommand } from '../../commands/commands' import { foldAndApplyCommandsInner } from '../../commands/commands' import { duplicateElement } from '../../commands/duplicate-element-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateFunctionCommand } from '../../commands/update-function-command' import { updateSelectedViews } from '../../commands/update-selected-views-command' import { ImmediateParentBounds } from '../../controls/parent-bounds' @@ -127,7 +127,6 @@ export function absoluteDuplicateStrategy( [ ...duplicateCommands, ...maybeAddContainLayoutCommand(commonParentPath), - setElementsToRerenderCommand([commonParentPath, ...selectedElements, ...newPaths]), updateSelectedViews('always', selectedElements), updateFunctionCommand('always', (editorState, commandLifecycle) => runMoveStrategy( @@ -140,13 +139,14 @@ export function absoluteDuplicateStrategy( ), setCursorCommand(CSSCursor.Duplicate), ], + [commonParentPath, ...selectedElements, ...newPaths], { duplicatedElementNewUids: duplicatedElementNewUids, }, ) } else { // Fallback for when the checks above are not satisfied. - return strategyApplicationResult([setCursorCommand(CSSCursor.Duplicate)]) + return strategyApplicationResult([setCursorCommand(CSSCursor.Duplicate)], []) } }, } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy-canvas.spec.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy-canvas.spec.tsx index e438034e8e9c..5031daf5b2b3 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy-canvas.spec.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy-canvas.spec.tsx @@ -151,15 +151,11 @@ function reparentElement( expect(strategyResult.customStatePatch).toEqual({}) expect(strategyResult.status).toEqual('success') - // Check if there are set SetElementsToRerenderCommands with the new parent path expect( - strategyResult.commands.find( - (c) => - c.type === 'SET_ELEMENTS_TO_RERENDER_COMMAND' && - c.value !== 'rerender-all-elements' && - c.value.every((p) => EP.pathsEqual(EP.parentPath(p), newParent)), - ), - ).not.toBeNull() + strategyResult.elementsToRerender === 'rerender-all-elements' + ? [] + : strategyResult.elementsToRerender.map(EP.parentPath), + ).toEqual([newParent]) const finalEditor = foldAndApplyCommands( editorState, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.spec.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.spec.tsx index 464de829ae5b..77328c3d5894 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.spec.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.spec.tsx @@ -222,15 +222,11 @@ function reparentElement( expect(strategyResult.customStatePatch).toEqual({}) expect(strategyResult.status).toEqual('success') - // Check if there are set SetElementsToRerenderCommands with the new parent path expect( - strategyResult.commands.find( - (c) => - c.type === 'SET_ELEMENTS_TO_RERENDER_COMMAND' && - c.value !== 'rerender-all-elements' && - c.value.every((p) => EP.pathsEqual(EP.parentPath(p), newParent)), - ), - ).not.toBeNull() + strategyResult.elementsToRerender === 'rerender-all-elements' + ? [] + : strategyResult.elementsToRerender.map(EP.parentPath), + ).toEqual([newParent]) return foldAndApplyCommands( editorState, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.tsx index 557f1c8724cf..0a448ca2b6c3 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.tsx @@ -13,7 +13,7 @@ import type { InsertionPath } from '../../../editor/store/insertion-path' import { CSSCursor } from '../../canvas-types' import type { CanvasCommand } from '../../commands/commands' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setProperty } from '../../commands/set-property-command' import { updateSelectedViews } from '../../commands/update-selected-views-command' import { ParentBounds } from '../../controls/parent-bounds' @@ -217,7 +217,6 @@ export function applyAbsoluteReparent( ...moveCommands, ...commands.flatMap((c) => c.commands), updateSelectedViews('always', newPaths), - setElementsToRerenderCommand(elementsToRerender), ...maybeAddContainLayout( canvasState.startingMetadata, canvasState.startingAllElementProps, @@ -226,6 +225,7 @@ export function applyAbsoluteReparent( ), setCursorCommand(CSSCursor.Reparent), ], + elementsToRerender, { elementsToRerender, }, @@ -236,7 +236,7 @@ export function applyAbsoluteReparent( ...defaultCustomStrategyState(), action: 'reparent', })?.strategy.apply(strategyLifecycle).commands ?? [] - return strategyApplicationResult(moveCommands) + return strategyApplicationResult(moveCommands, 'rerender-all-elements') } }, ) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.tsx index 9ce4abe252c4..19b27d644757 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.tsx @@ -29,7 +29,7 @@ import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended- import { queueTrueUpElement } from '../../commands/queue-true-up-command' import { activeFrameTargetRect, setActiveFrames } from '../../commands/set-active-frames-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setSnappingGuidelines } from '../../commands/set-snapping-guidelines-command' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { gatherParentAndSiblingTargets } from '../../controls/guideline-helpers' @@ -141,7 +141,7 @@ export function absoluteResizeBoundingBoxStrategy( }), ], fitness: onlyFitWhenDraggingThisControl(interactionSession, 'RESIZE_HANDLE', 1), - apply: () => { + apply: (lifecycle) => { if ( interactionSession != null && interactionSession.interactionData.type === 'DRAG' && @@ -289,19 +289,24 @@ export function absoluteResizeBoundingBoxStrategy( ] }) - return strategyApplicationResult([ - ...commandsForSelectedElements, - setSnappingGuidelines('mid-interaction', guidelinesWithSnappingVector), - updateHighlightedViews('mid-interaction', []), - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - setElementsToRerenderCommand(retargetedTargets), - ]) + return strategyApplicationResult( + [ + ...commandsForSelectedElements, + setSnappingGuidelines('mid-interaction', guidelinesWithSnappingVector), + updateHighlightedViews('mid-interaction', []), + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + ], + lifecycle === 'mid-interaction' ? retargetedTargets : 'rerender-all-elements', + ) } } else { - return strategyApplicationResult([ - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - updateHighlightedViews('mid-interaction', []), - ]) + return strategyApplicationResult( + [ + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + updateHighlightedViews('mid-interaction', []), + ], + [], + ) } } // Fallback for when the checks above are not satisfied. diff --git a/editor/src/components/canvas/canvas-strategies/strategies/ancestor-metastrategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/ancestor-metastrategy.tsx index bc4b655e30ea..123b4f4a8fcd 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/ancestor-metastrategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/ancestor-metastrategy.tsx @@ -1,3 +1,7 @@ +import { + combineElementsToRerender, + type ElementsToRerender, +} from '../../../../components/editor/store/editor-state' import { getSimpleAttributeAtPath, MetadataUtils, @@ -9,20 +13,20 @@ import { CSSCursor } from '../../canvas-types' import type { CanvasCommand } from '../../commands/commands' import { highlightElementsCommand } from '../../commands/highlight-element-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { appendElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' import { wildcardPatch } from '../../commands/wildcard-patch-command' import { onlyFitWhenThisControlIsActive, type MetaCanvasStrategy } from '../canvas-strategies' import type { CanvasStrategy, InteractionCanvasState, InteractionLifecycle, + StrategyApplicationResult, } from '../canvas-strategy-types' import { getTargetPathsFromInteractionTarget, targetPaths } from '../canvas-strategy-types' import { DoNothingStrategyID } from './drag-to-move-metastrategy' -import { - retargetStrategyToChildrenOfFragmentLikeElements, - treatElementAsFragmentLike, -} from './fragment-like-helpers' +import { retargetStrategyToChildrenOfFragmentLikeElements } from './fragment-like-helpers' +import type { Optic } from '../../../../core/shared/optics/optics' +import { filtered, fromField } from '../../../../core/shared/optics/optic-creators' +import { modify } from '../../../../core/shared/optics/optic-utilities' const ANCESTOR_INCOMPATIBLE_STRATEGIES = [DoNothingStrategyID] @@ -125,11 +129,7 @@ export function ancestorMetaStrategy( return nextAncestorResult.map((s) => ({ ...s, fitness: fitness(s), - apply: appendCommandsToApplyResult( - s.apply, - [appendElementsToRerenderCommand([target])], - [], - ), + apply: appendElementsToRerenderToApplyResult(s.apply, [target]), })) } else { // Otherwise we should stop at this ancestor and return the strategies for this ancestor @@ -150,22 +150,21 @@ export function ancestorMetaStrategy( id: `${s.id}_ANCESTOR_${level}`, name: applyLevelSuffix(s.name, level), fitness: fitness(s), - apply: appendCommandsToApplyResult( - s.apply, - [ - appendElementsToRerenderCommand([target]), - highlightElementsCommand([parentPath]), - setCursorCommand(CSSCursor.MovingMagic), - ], - [ - wildcardPatch('mid-interaction', { - canvas: { - controls: { - dragToMoveIndicatorFlags: { ancestor: { $set: true } }, + apply: appendElementsToRerenderToApplyResult( + appendCommandsToApplyResult( + s.apply, + [highlightElementsCommand([parentPath]), setCursorCommand(CSSCursor.MovingMagic)], + [ + wildcardPatch('mid-interaction', { + canvas: { + controls: { + dragToMoveIndicatorFlags: { ancestor: { $set: true } }, + }, }, - }, - }), - ], + }), + ], + ), + [target], ), } }), @@ -175,6 +174,7 @@ export function ancestorMetaStrategy( } type ApplyFn = CanvasStrategy['apply'] + export function appendCommandsToApplyResult( applyFn: ApplyFn, commandsToAppendToExtendResult: Array, @@ -204,6 +204,27 @@ export function appendCommandsToApplyResult( } } +const strategyResultElementsToRerenderOptic: Optic = + filtered((result) => result.status === 'success').compose( + fromField('elementsToRerender'), + ) + +export function appendElementsToRerenderToApplyResult( + applyFn: ApplyFn, + additionalElementsToRerender: ElementsToRerender, +): ApplyFn { + return (strategyLifecycle: InteractionLifecycle) => { + const result = applyFn(strategyLifecycle) + return modify( + strategyResultElementsToRerenderOptic, + (toRerender) => { + return combineElementsToRerender(toRerender, additionalElementsToRerender) + }, + result, + ) + } +} + function applyLevelSuffix(name: string, level: number): string { // FIXME What should we use for the label here? const newSuffix = `(Up ${level})` diff --git a/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx index 60eccfac3a28..2da9612b7ae7 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx @@ -30,7 +30,7 @@ import { import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command' import { queueTrueUpElement } from '../../commands/queue-true-up-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { controlsForGridPlaceholders } from '../../controls/grid-controls' import { ImmediateParentBounds } from '../../controls/parent-bounds' @@ -219,24 +219,29 @@ export function basicResizeStrategy( const elementsToRerender = [...selectedElements, ...gridsToRerender] - return strategyApplicationResult([ - adjustCssLengthProperties('always', selectedElement, null, resizeProperties), - updateHighlightedViews('mid-interaction', []), - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - setElementsToRerenderCommand(elementsToRerender), - pushIntendedBoundsAndUpdateGroups( - [{ target: selectedElement, frame: resizedBounds }], - 'starting-metadata', - ), - ...groupChildren.map((c) => - queueTrueUpElement([trueUpGroupElementChanged(c.elementPath)]), - ), - ]) + return strategyApplicationResult( + [ + adjustCssLengthProperties('always', selectedElement, null, resizeProperties), + updateHighlightedViews('mid-interaction', []), + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + pushIntendedBoundsAndUpdateGroups( + [{ target: selectedElement, frame: resizedBounds }], + 'starting-metadata', + ), + ...groupChildren.map((c) => + queueTrueUpElement([trueUpGroupElementChanged(c.elementPath)]), + ), + ], + elementsToRerender, + ) } else { - return strategyApplicationResult([ - updateHighlightedViews('mid-interaction', []), - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - ]) + return strategyApplicationResult( + [ + updateHighlightedViews('mid-interaction', []), + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + ], + [], + ) } } // Fallback for when the checks above are not satisfied. diff --git a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx index ff61a2be348c..34695730d6b5 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx @@ -278,10 +278,13 @@ function convertToAbsoluteAndMoveStrategyFactory(setHuggingParentToFixed: SetHug }, }) - return strategyApplicationResult([ - ...absoluteMoveApplyResult.commands, - strategyIndicatorCommand, - ]) + return strategyApplicationResult( + [...absoluteMoveApplyResult.commands, strategyIndicatorCommand], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) } // Fallback for when the checks above are not satisfied. return emptyStrategyApplicationResult diff --git a/editor/src/components/canvas/canvas-strategies/strategies/drag-to-insert-metastrategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/drag-to-insert-metastrategy.tsx index 04da545d72f5..2804f0f5302d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/drag-to-insert-metastrategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/drag-to-insert-metastrategy.tsx @@ -216,6 +216,7 @@ function dragToInsertStrategyFactory( if (insertionSubjects.length === 0) { return strategyApplicationResult( [setCursorCommand(CSSCursor.NotPermitted)], + [], {}, 'failure', ) @@ -280,6 +281,10 @@ function dragToInsertStrategyFactory( reparentCommand, ...optionalWrappingCommand, ], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', { strategyGeneratedUidsCache: { [insertionSubjects[0].uid]: maybeWrapperWithUid?.uid, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/drag-to-move-metastrategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/drag-to-move-metastrategy.tsx index 45dfa9f1d595..67255fe562d1 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/drag-to-move-metastrategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/drag-to-move-metastrategy.tsx @@ -153,23 +153,26 @@ export function doNothingStrategy(canvasState: InteractionCanvasState): CanvasSt ], fitness: DoNothingFitness, apply: () => { - return strategyApplicationResult([ - wildcardPatch('mid-interaction', { - canvas: { - controls: { - dragToMoveIndicatorFlags: { - $set: { - showIndicator: true, - dragType: 'none', - reparent: 'none', - ancestor: false, + return strategyApplicationResult( + [ + wildcardPatch('mid-interaction', { + canvas: { + controls: { + dragToMoveIndicatorFlags: { + $set: { + showIndicator: true, + dragType: 'none', + reparent: 'none', + ancestor: false, + }, }, }, }, - }, - }), - setCursorCommand(CSSCursor.NotPermitted), - ]) + }), + setCursorCommand(CSSCursor.NotPermitted), + ], + [], + ) }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-metastrategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-metastrategy.tsx index 3ce8cfb1f4f6..907b6178eed7 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-metastrategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-metastrategy.tsx @@ -303,6 +303,10 @@ export function drawToInsertStrategyFactory( resizeCommand, ...optionalWrappingCommand, ], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', { strategyGeneratedUidsCache: { [insertionSubject.uid]: maybeWrapperWithUid?.uid, @@ -348,6 +352,10 @@ export function drawToInsertStrategyFactory( return strategyApplicationResult( [insertionCommand.command, reparentCommand, ...optionalWrappingCommand], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', { strategyGeneratedUidsCache: { [insertionSubject.uid]: maybeWrapperWithUid?.uid, @@ -359,11 +367,13 @@ export function drawToInsertStrategyFactory( // drag is null, the cursor is not moved yet, but the mousedown already happened return strategyApplicationResult( getHighlightAndReorderIndicatorCommands(targetParent.intendedParentPath, targetIndex), + [], ) } } else if (interactionSession.interactionData.type === 'HOVER') { return strategyApplicationResult( getHighlightAndReorderIndicatorCommands(targetParent.intendedParentPath, targetIndex), + [], ) } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-text-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-text-strategy.tsx index 5ab27f69b3d5..81b24156f222 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-text-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-text-strategy.tsx @@ -87,7 +87,7 @@ export const drawToInsertTextMetaStrategy: MetaCanvasStrategy = ( ['hasOnlyTextChildren', 'supportsChildren'], ) if (applicableReparentFactories.length < 1) { - return strategyApplicationResult([]) + return strategyApplicationResult([], []) } const factory = applicableReparentFactories[0] @@ -107,24 +107,30 @@ export const drawToInsertTextMetaStrategy: MetaCanvasStrategy = ( const isRoot = targetParentPathParts === 1 const isClick = s === 'end-interaction' && interactionSession.interactionData.drag == null if (!isRoot && textEditableAndHasText && isClick) { - return strategyApplicationResult([ - updateSelectedViews('on-complete', [targetParent.intendedParentPath]), - setCursorCommand(CSSCursor.Select), - wildcardPatch('on-complete', { - mode: { - $set: EditorModes.textEditMode( - targetParent.intendedParentPath, - canvasPointToWindowPoint( - pointOnCanvas, - canvasState.scale, - canvasState.canvasOffset, + return strategyApplicationResult( + [ + updateSelectedViews('on-complete', [targetParent.intendedParentPath]), + setCursorCommand(CSSCursor.Select), + wildcardPatch('on-complete', { + mode: { + $set: EditorModes.textEditMode( + targetParent.intendedParentPath, + canvasPointToWindowPoint( + pointOnCanvas, + canvasState.scale, + canvasState.canvasOffset, + ), + 'existing', + 'no-text-selection', ), - 'existing', - 'no-text-selection', - ), - }, - }), - ]) + }, + }), + ], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) } const strategy = drawToInsertStrategyFactory( @@ -138,7 +144,7 @@ export const drawToInsertTextMetaStrategy: MetaCanvasStrategy = ( factory.targetIndex, ) if (strategy == null) { - return strategyApplicationResult([]) + return strategyApplicationResult([], []) } const targetElement = EP.appendToPath(targetParent.intendedParentPath, insertionSubject.uid) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx index 60941a9865e5..39d6fe1b8255 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx @@ -1,7 +1,7 @@ import { canvasPoint } from '../../../../core/shared/math-utils' import type { EditorStatePatch } from '../../../editor/store/editor-state' import { foldAndApplyCommandsInner } from '../../commands/commands' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateFunctionCommand } from '../../commands/update-function-command' import { ParentBounds } from '../../controls/parent-bounds' import { ParentOutlines } from '../../controls/parent-outlines' @@ -105,10 +105,6 @@ export function baseFlexReparentToAbsoluteStrategy( [ ...placeholderCommands.commands, ...escapeHatchCommands, - setElementsToRerenderCommand([ - newParent.intendedParentPath, - ...filteredSelectedElements, - ]), updateFunctionCommand( 'always', (editorState, commandLifecycle): Array => { @@ -137,6 +133,7 @@ export function baseFlexReparentToAbsoluteStrategy( }, ), ], + [newParent.intendedParentPath, ...filteredSelectedElements], { duplicatedElementNewUids: placeholderCommands.duplicatedElementNewUids, }, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/flex-resize-basic-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/flex-resize-basic-strategy.tsx index 3d8a48bebaa5..12b843038f08 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/flex-resize-basic-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/flex-resize-basic-strategy.tsx @@ -8,7 +8,7 @@ import { lengthPropertyToAdjust, } from '../../commands/adjust-css-length-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { ImmediateParentBounds } from '../../controls/parent-bounds' import { ImmediateParentOutlines } from '../../controls/parent-outlines' @@ -220,24 +220,29 @@ export function flexResizeBasicStrategy( elementParentBounds?.height, ) - return strategyApplicationResult([ - adjustCssLengthProperties('always', selectedElement, null, resizeProperties), - updateHighlightedViews('mid-interaction', []), - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - setElementsToRerenderCommand(selectedElements), - pushIntendedBoundsAndUpdateGroups( - [{ target: selectedElement, frame: resizedBounds }], - 'starting-metadata', - ), - ...groupChildren.map((c) => - queueTrueUpElement([trueUpGroupElementChanged(c.elementPath)]), - ), - ]) + return strategyApplicationResult( + [ + adjustCssLengthProperties('always', selectedElement, null, resizeProperties), + updateHighlightedViews('mid-interaction', []), + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + pushIntendedBoundsAndUpdateGroups( + [{ target: selectedElement, frame: resizedBounds }], + 'starting-metadata', + ), + ...groupChildren.map((c) => + queueTrueUpElement([trueUpGroupElementChanged(c.elementPath)]), + ), + ], + selectedElements, + ) } else { - return strategyApplicationResult([ - updateHighlightedViews('mid-interaction', []), - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - ]) + return strategyApplicationResult( + [ + updateHighlightedViews('mid-interaction', []), + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + ], + [], + ) } } // Fallback for when the checks above are not satisfied. diff --git a/editor/src/components/canvas/canvas-strategies/strategies/flex-resize-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/flex-resize-strategy.tsx index 1cff33d7db1f..1197e3c9fe62 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/flex-resize-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/flex-resize-strategy.tsx @@ -24,7 +24,7 @@ import { lengthPropertyToAdjust, } from '../../commands/adjust-css-length-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { ImmediateParentBounds } from '../../controls/parent-bounds' import { ImmediateParentOutlines } from '../../controls/parent-outlines' @@ -353,24 +353,29 @@ export function flexResizeStrategy( 'center-based', ) - return strategyApplicationResult([ - ...resizeCommands, - updateHighlightedViews('mid-interaction', []), - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - setElementsToRerenderCommand(selectedElements), - pushIntendedBoundsAndUpdateGroups( - [{ target: selectedElement, frame: newFrame }], - 'starting-metadata', - ), - ...groupChildren.map((c) => - queueTrueUpElement([trueUpGroupElementChanged(c.elementPath)]), - ), - ]) + return strategyApplicationResult( + [ + ...resizeCommands, + updateHighlightedViews('mid-interaction', []), + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + pushIntendedBoundsAndUpdateGroups( + [{ target: selectedElement, frame: newFrame }], + 'starting-metadata', + ), + ...groupChildren.map((c) => + queueTrueUpElement([trueUpGroupElementChanged(c.elementPath)]), + ), + ], + selectedElements, + ) } else { - return strategyApplicationResult([ - updateHighlightedViews('mid-interaction', []), - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - ]) + return strategyApplicationResult( + [ + updateHighlightedViews('mid-interaction', []), + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + ], + [], + ) } } // Fallback for when the checks above are not satisfied. diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx index 01c45b432ede..7036621bc9c1 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx @@ -165,6 +165,7 @@ const gridDrawToInsertStrategyInner = showGridControls('mid-interaction', targetParent), updateHighlightedViews('mid-interaction', [targetParent]), ], + [], { ...customStrategyState, grid: { @@ -258,6 +259,10 @@ const gridDrawToInsertStrategyInner = : null, ]), ], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', { strategyGeneratedUidsCache: { [insertionSubject.uid]: maybeWrapperWithUid?.uid, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts index ec4a6e55511f..2b34b4cddc36 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-keyboard-strategy.ts @@ -133,6 +133,10 @@ export function gridRearrangeResizeKeyboardStrategy( gridRowStart, gridRowEnd, }), + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', ) }, } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts index 8418611cdc88..671f74fe51f6 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-duplicate-strategy.ts @@ -4,7 +4,7 @@ import * as EP from '../../../../core/shared/element-path' import { CSSCursor } from '../../../../uuiui-deps' import { duplicateElement } from '../../commands/duplicate-element-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { updateSelectedViews } from '../../commands/update-selected-views-command' import { controlsForGridPlaceholders } from '../../controls/grid-controls' @@ -93,11 +93,11 @@ export const gridRearrangeMoveDuplicateStrategy: CanvasStrategyFactory = ( [ duplicateElement('always', selectedElement, newUid), ...moveCommands, - setElementsToRerenderCommand([...selectedElements, targetElement]), updateSelectedViews('always', [targetElement]), updateHighlightedViews('always', [targetElement]), setCursorCommand(CSSCursor.Duplicate), ], + [...selectedElements, targetElement], { grid: { targetCellData: targetGridCellData, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts index 9a9fe23d1c81..c9ab491743f1 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-rearrange-move-strategy.ts @@ -155,6 +155,10 @@ export const gridRearrangeMoveStrategy: CanvasStrategyFactory = ( return strategyApplicationResult( [...midInteractionCommands, ...onCompleteCommands, ...commands], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', patch, ) }, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx index 4249b4b699fa..e348e82132ac 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-reparent-strategy.tsx @@ -46,7 +46,6 @@ import type { ReparentTarget } from './reparent-helpers/reparent-strategy-helper import { getReparentOutcome, pathToReparent } from './reparent-utils' import { flattenSelection } from './shared-move-strategies-helpers' import { getGridCellUnderMouseFromMetadata, type GridCellCoordinates } from './grid-cell-bounds' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' export function gridReparentStrategy( reparentTarget: ReparentTarget, @@ -245,8 +244,8 @@ export function applyGridReparent( updateSelectedViews('always', newPaths), setCursorCommand(CSSCursor.Reparent), showGridControls('mid-interaction', reparentTarget.newParent.intendedParentPath), - setElementsToRerenderCommand(elementsToRerender), ], + elementsToRerender, { elementsToRerender: elementsToRerender, grid: { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts index 64730c52ff48..2f47003ac5ce 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts @@ -140,6 +140,10 @@ export const gridResizeElementStrategy: CanvasStrategyFactory = ( return strategyApplicationResult( setGridPropsCommands(selectedElement, gridTemplate, gridPropsWithDragOver(gridProps)), + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', { grid: { ...customState.grid, targetCellData: targetCell }, }, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-move-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-move-strategy.ts index 41c3f2f5eeca..2e15719b0104 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-move-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-move-strategy.ts @@ -19,7 +19,7 @@ import { getInteractionMoveCommandsForSelectedElement, getMultiselectBounds, } from './shared-move-strategies-helpers' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setSnappingGuidelines } from '../../commands/set-snapping-guidelines-command' import type { CanvasCommand } from '../../commands/commands' import { @@ -120,8 +120,7 @@ export function keyboardAbsoluteMoveStrategy( commands.push(setSnappingGuidelines('mid-interaction', guidelines)) commands.push(pushIntendedBoundsAndUpdateGroups(intendedBounds, 'starting-metadata')) - commands.push(setElementsToRerenderCommand(selectedElements)) - return strategyApplicationResult(commands) + return strategyApplicationResult(commands, selectedElements) } else { return emptyStrategyApplicationResult } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-resize-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-resize-strategy.tsx index 785a8cd041f1..70f8b5e5a474 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-resize-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-resize-strategy.tsx @@ -12,7 +12,7 @@ import type { CanvasFrameAndTarget, EdgePosition } from '../../canvas-types' import { EdgePositionBottom, EdgePositionRight } from '../../canvas-types' import type { CanvasCommand } from '../../commands/commands' import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setSnappingGuidelines } from '../../commands/set-snapping-guidelines-command' import { AbsoluteResizeControl } from '../../controls/select-mode/absolute-resize-control' import type { CanvasStrategy, InteractionCanvasState } from '../canvas-strategy-types' @@ -225,8 +225,7 @@ export function keyboardAbsoluteResizeStrategy( const guidelines = getKeyboardStrategyGuidelines(snapTargets, interactionSession, newFrame) commands.push(setSnappingGuidelines('mid-interaction', guidelines)) commands.push(pushIntendedBoundsAndUpdateGroups(intendedBounds, 'starting-metadata')) - commands.push(setElementsToRerenderCommand(selectedElements)) - return strategyApplicationResult(commands) + return strategyApplicationResult(commands, selectedElements) } else { return emptyStrategyApplicationResult } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-reorder-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-reorder-strategy.ts index eaa0abf15914..8a0cdcdc73dc 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-reorder-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-reorder-strategy.ts @@ -5,7 +5,7 @@ import { shallowEqual } from '../../../../core/shared/equality-utils' import { emptyModifiers, Modifier } from '../../../../utils/modifiers' import { absolute } from '../../../../utils/utils' import { reorderElement } from '../../commands/reorder-element-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import type { CanvasStrategy, @@ -90,10 +90,8 @@ export function keyboardReorderStrategy( if (newIndex === unpatchedIndex) { return strategyApplicationResult( - [ - updateHighlightedViews('mid-interaction', []), - setElementsToRerenderCommand(siblingsAndParent), - ], + [updateHighlightedViews('mid-interaction', [])], + siblingsAndParent, { lastReorderIdx: newIndex, }, @@ -102,9 +100,9 @@ export function keyboardReorderStrategy( return strategyApplicationResult( [ reorderElement('always', target, absolute(newIndex)), - setElementsToRerenderCommand(siblingsAndParent), updateHighlightedViews('mid-interaction', []), ], + siblingsAndParent, { lastReorderIdx: newIndex, }, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-font-size-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-font-size-strategy.tsx index 6bf48e00b559..89bac012ea17 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-font-size-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-font-size-strategy.tsx @@ -79,7 +79,7 @@ export function keyboardSetFontSizeStrategy( ), ) - return strategyApplicationResult(commands) + return strategyApplicationResult(commands, 'rerender-all-elements') }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-font-weight-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-font-weight-strategy.tsx index faab0cfca6d9..69d248f68f12 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-font-weight-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-font-weight-strategy.tsx @@ -87,7 +87,13 @@ export function keyboardSetFontWeightStrategy( ), ) - return strategyApplicationResult(commands) + return strategyApplicationResult( + commands, + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-opacity-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-opacity-strategy.tsx index f3b9c1350ad2..12ccaecd396d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-opacity-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-set-opacity-strategy.tsx @@ -57,7 +57,13 @@ export function keyboardSetOpacityStrategy( setProperty('always', path, PP.create('style', 'opacity'), inputValue), ) - return strategyApplicationResult(commands) + return strategyApplicationResult( + commands, + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/rearrange-grid-swap-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/rearrange-grid-swap-strategy.ts index fdfcb3eb6574..ef9bf83e2afe 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/rearrange-grid-swap-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/rearrange-grid-swap-strategy.ts @@ -121,7 +121,13 @@ export const rearrangeGridSwapStrategy: CanvasStrategyFactory = ( return emptyStrategyApplicationResult } - return strategyApplicationResult(commands) + return strategyApplicationResult( + commands, + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/reorder-slider-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/reorder-slider-strategy.tsx index 73ed8070f7f4..6ed0746c318c 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/reorder-slider-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/reorder-slider-strategy.tsx @@ -4,7 +4,7 @@ import { absolute } from '../../../../utils/utils' import { CSSCursor } from '../../canvas-types' import { reorderElement } from '../../commands/reorder-element-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { ReorderSliderControl } from '../../controls/reorder-slider-control' import type { CanvasStrategy, InteractionCanvasState } from '../canvas-strategy-types' @@ -83,6 +83,7 @@ export function reorderSliderStategy( if (!isReorderAllowed(siblingsOfTarget)) { return strategyApplicationResult( [setCursorCommand(CSSCursor.NotPermitted)], + [], {}, 'failure', ) @@ -103,17 +104,17 @@ export function reorderSliderStategy( return strategyApplicationResult( [ reorderElement('always', target, absolute(newIndex)), - setElementsToRerenderCommand(siblingsAndParent), updateHighlightedViews('mid-interaction', []), setCursorCommand(CSSCursor.ResizeEW), ], + siblingsAndParent, { lastReorderIdx: newIndex, }, ) } else { // Fallback for when the checks above are not satisfied. - return strategyApplicationResult([setCursorCommand(CSSCursor.ResizeEW)]) + return strategyApplicationResult([setCursorCommand(CSSCursor.ResizeEW)], []) } } else { return emptyStrategyApplicationResult diff --git a/editor/src/components/canvas/canvas-strategies/strategies/reorder-utils.ts b/editor/src/components/canvas/canvas-strategies/strategies/reorder-utils.ts index 37cbc20bf15d..7900e6a2eb93 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/reorder-utils.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/reorder-utils.ts @@ -13,7 +13,7 @@ import { absolute } from '../../../../utils/utils' import { CSSCursor } from '../../canvas-types' import { reorderElement } from '../../commands/reorder-element-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import type { CustomStrategyState, @@ -60,7 +60,12 @@ export function applyReorderCommon( const siblingsAndParent = siblings.concat(EP.parentPath(target)) if (!isReorderAllowed(siblings)) { - return strategyApplicationResult([setCursorCommand(CSSCursor.NotPermitted)], {}, 'failure') + return strategyApplicationResult( + [setCursorCommand(CSSCursor.NotPermitted)], + [], + {}, + 'failure', + ) } const pointOnCanvas = offsetPoint( @@ -100,9 +105,9 @@ export function applyReorderCommon( { action: 'reorder', target: activeFrameTargetRect(targetFrame), source: sourceFrame }, ]), updateHighlightedViews('mid-interaction', []), - setElementsToRerenderCommand(siblingsAndParent), setCursorCommand(CSSCursor.Move), ], + siblingsAndParent, { lastReorderIdx: newResultOrLastIndex, }, @@ -114,10 +119,10 @@ export function applyReorderCommon( { action: 'reorder', target: activeFrameTargetRect(targetFrame), source: sourceFrame }, ]), reorderElement('always', target, absolute(newResultOrLastIndex)), - setElementsToRerenderCommand(siblingsAndParent), updateHighlightedViews('mid-interaction', []), setCursorCommand(CSSCursor.Move), ], + siblingsAndParent, { lastReorderIdx: newResultOrLastIndex, }, @@ -125,7 +130,7 @@ export function applyReorderCommon( } } else { // Fallback for when the checks above are not satisfied. - return strategyApplicationResult([setCursorCommand(CSSCursor.Move)]) + return strategyApplicationResult([setCursorCommand(CSSCursor.Move)], 'rerender-all-elements') } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/reparent-as-static-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/reparent-as-static-strategy.tsx index a932268764d4..7eb3bb7f5d2c 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/reparent-as-static-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/reparent-as-static-strategy.tsx @@ -14,7 +14,6 @@ import type { CanvasCommand } from '../../commands/commands' import { reorderElement } from '../../commands/reorder-element-command' import { activeFrameTargetRect, setActiveFrames } from '../../commands/set-active-frames-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' import { showReorderIndicator } from '../../commands/show-reorder-indicator-command' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { updateSelectedViews } from '../../commands/update-selected-views-command' @@ -229,7 +228,7 @@ export function applyStaticReparent( const commandsAfterReorder = [ ...propertyChangeCommands, - setElementsToRerenderCommand(elementsToRerender), + updateHighlightedViews('mid-interaction', []), setCursorCommand(CSSCursor.Move), ] @@ -348,6 +347,7 @@ export function applyStaticReparent( return { commands: [...midInteractionCommands, ...interactionFinishCommands], + elementsToRerender: elementsToRerender, customStatePatch: { duplicatedElementNewUids, elementsToRerender }, status: 'success', } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-helpers.ts index a8df61f98d0b..3f6b30158503 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-helpers.ts @@ -249,7 +249,12 @@ export function ifAllowedToReparent( if (allowed) { return ifAllowed() } else { - return strategyApplicationResult([setCursorCommand(CSSCursor.NotPermitted)], {}, 'failure') + return strategyApplicationResult( + [setCursorCommand(CSSCursor.NotPermitted)], + 'rerender-all-elements', + {}, + 'failure', + ) } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts index f78da315415b..6a0d12b74acc 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.ts @@ -30,7 +30,6 @@ import { printArrayGridDimensions, } from '../../../../components/inspector/common/css-utils' import { toFirst } from '../../../../core/shared/optics/optic-utilities' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' import type { Either } from '../../../../core/shared/either' import { foldEither, isLeft, isRight } from '../../../../core/shared/either' import { roundToNearestWhole } from '../../../../core/shared/math-utils' @@ -119,7 +118,10 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( } if (!canResizeGridTemplate(originalValues)) { - return strategyApplicationResult([setCursorCommand(CSSCursor.NotPermitted)]) + return strategyApplicationResult( + [setCursorCommand(CSSCursor.NotPermitted)], + 'rerender-all-elements', + ) } const expandedOriginalValues = expandGridDimensions(originalValues.dimensions) @@ -186,10 +188,9 @@ export const resizeGridStrategy: CanvasStrategyFactory = ( ), propertyValueAsString, ), - setElementsToRerenderCommand([gridPath]), ] - return strategyApplicationResult(commands) + return strategyApplicationResult(commands, [gridPath]) }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/set-border-radius-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/set-border-radius-strategy.tsx index f53fd038bc83..c2e84920c45c 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/set-border-radius-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/set-border-radius-strategy.tsx @@ -46,7 +46,7 @@ import { import { CSSCursor } from '../../canvas-types' import type { CanvasCommand } from '../../commands/commands' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setProperty } from '../../commands/set-property-command' import { BorderRadiusControl } from '../../controls/select-mode/border-radius-control' import type { CSSNumberWithRenderedValue } from '../../controls/select-mode/controls-common' @@ -155,21 +155,23 @@ export const setBorderRadiusStrategy: CanvasStrategyFactory = ( }), ], apply: () => - strategyApplicationResult([ - setCursorCommand(CSSCursor.Radius), - ...commands(selectedElement), - ...getAddOverflowHiddenCommands(selectedElement, canvasState.projectContents), - setElementsToRerenderCommand(selectedElements), - setActiveFrames( - selectedElements.map((path) => ({ - action: 'set-radius', - target: activeFrameTargetPath(path), - source: zeroRectIfNullOrInfinity( - MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata), - ), - })), - ), - ]), + strategyApplicationResult( + [ + setCursorCommand(CSSCursor.Radius), + ...commands(selectedElement), + ...getAddOverflowHiddenCommands(selectedElement, canvasState.projectContents), + setActiveFrames( + selectedElements.map((path) => ({ + action: 'set-radius', + target: activeFrameTargetPath(path), + source: zeroRectIfNullOrInfinity( + MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata), + ), + })), + ), + ], + selectedElements, + ), } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/set-flex-gap-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/set-flex-gap-strategy.tsx index 8a1cb6aa2dfb..77d73a39247c 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/set-flex-gap-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/set-flex-gap-strategy.tsx @@ -14,7 +14,7 @@ import { printCSSNumber } from '../../../inspector/common/css-utils' import { stylePropPathMappingFn } from '../../../inspector/common/property-path-hooks' import { deleteProperties } from '../../commands/delete-properties-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setProperty } from '../../commands/set-property-command' import { fallbackEmptyValue, @@ -172,30 +172,36 @@ export const setFlexGapStrategy: CanvasStrategyFactory = ( } if (shouldTearOffGap) { - return strategyApplicationResult([ - deleteProperties('always', selectedElement, [StyleGapProp]), - ]) + return strategyApplicationResult( + [deleteProperties('always', selectedElement, [StyleGapProp])], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) } - return strategyApplicationResult([ - setProperty( - 'always', - selectedElement, - StyleGapProp, - printCSSNumber(fallbackEmptyValue(updatedFlexGapMeasurement), null), - ), - setCursorCommand(cursorFromFlexDirection(flexGap.direction)), - setElementsToRerenderCommand([...selectedElements, ...children.map((c) => c.elementPath)]), - setActiveFrames([ - { - action: 'set-gap', - target: activeFrameTargetPath(selectedElement), - source: zeroRectIfNullOrInfinity( - MetadataUtils.getFrameInCanvasCoords(selectedElement, canvasState.startingMetadata), - ), - }, - ]), - ]) + return strategyApplicationResult( + [ + setProperty( + 'always', + selectedElement, + StyleGapProp, + printCSSNumber(fallbackEmptyValue(updatedFlexGapMeasurement), null), + ), + setCursorCommand(cursorFromFlexDirection(flexGap.direction)), + setActiveFrames([ + { + action: 'set-gap', + target: activeFrameTargetPath(selectedElement), + source: zeroRectIfNullOrInfinity( + MetadataUtils.getFrameInCanvasCoords(selectedElement, canvasState.startingMetadata), + ), + }, + ]), + ], + [...selectedElements, ...children.map((c) => c.elementPath)], + ) }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx index b99698f01649..cb2afe25f6de 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/set-grid-gap-strategy.tsx @@ -12,7 +12,7 @@ import { printCSSNumber } from '../../../inspector/common/css-utils' import { stylePropPathMappingFn } from '../../../inspector/common/property-path-hooks' import { deleteProperties } from '../../commands/delete-properties-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setProperty } from '../../commands/set-property-command' import { fallbackEmptyValue, @@ -171,30 +171,36 @@ export const setGridGapStrategy: CanvasStrategyFactory = ( axis === 'row' ? updatedGridGapMeasurement.row : updatedGridGapMeasurement.column if (shouldTearOffGapByAxis) { - return strategyApplicationResult([ - deleteProperties('always', selectedElement, [axisStyleProp]), - ]) + return strategyApplicationResult( + [deleteProperties('always', selectedElement, [axisStyleProp])], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) } - return strategyApplicationResult([ - setProperty( - 'always', - selectedElement, - axisStyleProp, - printCSSNumber(fallbackEmptyValue(gridGapMeasurement), null), - ), - setCursorCommand(cursorFromAxis(axis)), - setElementsToRerenderCommand([...selectedElements, ...children.map((c) => c.elementPath)]), - setActiveFrames([ - { - action: 'set-gap', - target: activeFrameTargetPath(selectedElement), - source: zeroRectIfNullOrInfinity( - MetadataUtils.getFrameInCanvasCoords(selectedElement, canvasState.startingMetadata), - ), - }, - ]), - ]) + return strategyApplicationResult( + [ + setProperty( + 'always', + selectedElement, + axisStyleProp, + printCSSNumber(fallbackEmptyValue(gridGapMeasurement), null), + ), + setCursorCommand(cursorFromAxis(axis)), + setActiveFrames([ + { + action: 'set-gap', + target: activeFrameTargetPath(selectedElement), + source: zeroRectIfNullOrInfinity( + MetadataUtils.getFrameInCanvasCoords(selectedElement, canvasState.startingMetadata), + ), + }, + ]), + ], + [...selectedElements, ...children.map((c) => c.elementPath)], + ) }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/set-padding-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/set-padding-strategy.tsx index 7210fb3da37e..01f65b4b22c2 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/set-padding-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/set-padding-strategy.tsx @@ -14,7 +14,7 @@ import type { EdgePiece } from '../../canvas-types' import { CSSCursor, isHorizontalEdgePiece, oppositeEdgePiece } from '../../canvas-types' import { deleteProperties } from '../../commands/delete-properties-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setProperty } from '../../commands/set-property-command' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { isZeroSizedElement } from '../../controls/outline-utils' @@ -207,7 +207,6 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti const basicCommands: CanvasCommand[] = [ updateHighlightedViews('mid-interaction', []), setCursorCommand(pickCursorFromEdge(edgePiece)), - setElementsToRerenderCommand(selectedElements), ] const nonZeroPropsToAdd = IndividualPaddingProps.flatMap( @@ -246,11 +245,76 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti // "tearing off" padding if (newPaddingEdge.renderedValuePx < PaddingTearThreshold) { - return strategyApplicationResult([ + return strategyApplicationResult( + [ + ...basicCommands, + deleteProperties('always', selectedElement, [ + StylePaddingProp, + stylePropPathMappingFn(paddingPropInteractedWith, styleStringInArray), + ]), + ...nonZeroPropsToAdd.map(([p, value]) => + setProperty( + 'always', + selectedElement, + stylePropPathMappingFn(p, styleStringInArray), + value, + ), + ), + setActiveFrames( + selectedElements.map((path) => ({ + action: 'set-padding', + target: activeFrameTargetPath(path), + source: zeroRectIfNullOrInfinity( + MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata), + ), + })), + ), + ], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) + } + + const allPaddingPropsDefined = maybeFullPadding(newPaddingMaxed) + + // all 4 sides present - can be represented via the padding shorthand property + if (allPaddingPropsDefined != null) { + const paddingString = paddingToPaddingString(allPaddingPropsDefined) + return strategyApplicationResult( + [ + ...basicCommands, + ...IndividualPaddingProps.map((p) => + deleteProperties('always', selectedElement, [ + stylePropPathMappingFn(p, styleStringInArray), + ]), + ), + setProperty('always', selectedElement, StylePaddingProp, paddingString), + setActiveFrames( + selectedElements.map((path) => ({ + action: 'set-padding', + target: activeFrameTargetPath(path), + source: zeroRectIfNullOrInfinity( + MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata), + ), + })), + ), + ], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) + } + + // only some sides are present - longhand properties have to be used + return strategyApplicationResult( + [ ...basicCommands, deleteProperties('always', selectedElement, [ StylePaddingProp, - stylePropPathMappingFn(paddingPropInteractedWith, styleStringInArray), + ...IndividualPaddingProps.map((p) => stylePropPathMappingFn(p, styleStringInArray)), ]), ...nonZeroPropsToAdd.map(([p, value]) => setProperty( @@ -269,59 +333,12 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti ), })), ), - ]) - } - - const allPaddingPropsDefined = maybeFullPadding(newPaddingMaxed) - - // all 4 sides present - can be represented via the padding shorthand property - if (allPaddingPropsDefined != null) { - const paddingString = paddingToPaddingString(allPaddingPropsDefined) - return strategyApplicationResult([ - ...basicCommands, - ...IndividualPaddingProps.map((p) => - deleteProperties('always', selectedElement, [ - stylePropPathMappingFn(p, styleStringInArray), - ]), - ), - setProperty('always', selectedElement, StylePaddingProp, paddingString), - setActiveFrames( - selectedElements.map((path) => ({ - action: 'set-padding', - target: activeFrameTargetPath(path), - source: zeroRectIfNullOrInfinity( - MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata), - ), - })), - ), - ]) - } - - // only some sides are present - longhand properties have to be used - return strategyApplicationResult([ - ...basicCommands, - deleteProperties('always', selectedElement, [ - StylePaddingProp, - ...IndividualPaddingProps.map((p) => stylePropPathMappingFn(p, styleStringInArray)), - ]), - ...nonZeroPropsToAdd.map(([p, value]) => - setProperty( - 'always', - selectedElement, - stylePropPathMappingFn(p, styleStringInArray), - value, - ), - ), - setActiveFrames( - selectedElements.map((path) => ({ - action: 'set-padding', - target: activeFrameTargetPath(path), - source: zeroRectIfNullOrInfinity( - MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata), - ), - })), - ), - ]) + ], + // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 + // This was to maintain the existing behaviour, but it should be replaced with a more specific value + // appropriate to this particular case. + 'rerender-all-elements', + ) }, } } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/shared-absolute-resize-strategy-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/shared-absolute-resize-strategy-helpers.ts index bc658645f1f5..17c7d5f55b7e 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/shared-absolute-resize-strategy-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/shared-absolute-resize-strategy-helpers.ts @@ -57,7 +57,7 @@ import { MetadataUtils } from '../../../../core/model/element-metadata-utils' import { addOrMergeIntendedBounds } from './shared-keyboard-strategy-helpers' import type { InspectorStrategy } from '../../../../components/inspector/inspector-strategies/inspector-strategy' import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { withUnderlyingTarget } from '../../../../components/editor/store/editor-state' import type { SetCssLengthProperty } from '../../commands/set-css-length-command' import { @@ -416,7 +416,7 @@ export function resizeInspectorStrategy( commands.push( pushIntendedBoundsAndUpdateGroups(changeBoundsResult.intendedBounds, 'live-metadata'), ) - commands.push(setElementsToRerenderCommand(selectedElements)) + return commands }, } @@ -460,7 +460,7 @@ export function directResizeInspectorStrategy( pushIntendedBoundsAndUpdateGroups(changeBoundsResult.intendedBounds, 'live-metadata'), ) } - commands.push(setElementsToRerenderCommand(selectedElements)) + return commands }, } diff --git a/editor/src/components/canvas/canvas-strategies/strategies/shared-move-strategies-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/shared-move-strategies-helpers.ts index 5397ee1f84a9..4f93b1e1f635 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/shared-move-strategies-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/shared-move-strategies-helpers.ts @@ -44,7 +44,7 @@ import { import type { CanvasCommand } from '../../commands/commands' import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command' import { setCursorCommand } from '../../commands/set-cursor-command' -import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command' + import { setSnappingGuidelines } from '../../commands/set-snapping-guidelines-command' import { updateHighlightedViews } from '../../commands/update-highlighted-views-command' import { @@ -152,17 +152,20 @@ export function applyMoveCommon( if (cmdKeyPressed) { const commandsForSelectedElements = getMoveCommands(drag) - return strategyApplicationResult([ - ...commandsForSelectedElements.commands, - pushIntendedBoundsAndUpdateGroups( - commandsForSelectedElements.intendedBounds, - 'starting-metadata', - ), - updateHighlightedViews('mid-interaction', []), - setElementsToRerenderCommand(targets), - setCursorCommand(CSSCursor.Select), - setActiveFrames(getActiveFrames(commandsForSelectedElements.intendedBounds)), - ]) + return strategyApplicationResult( + [ + ...commandsForSelectedElements.commands, + pushIntendedBoundsAndUpdateGroups( + commandsForSelectedElements.intendedBounds, + 'starting-metadata', + ), + updateHighlightedViews('mid-interaction', []), + + setCursorCommand(CSSCursor.Select), + setActiveFrames(getActiveFrames(commandsForSelectedElements.intendedBounds)), + ], + targets, + ) } else { const constrainedDragAxis = shiftKeyPressed && drag != null ? determineConstrainedDragAxis(drag) : null @@ -189,18 +192,21 @@ export function applyMoveCommon( canvasState.scale, ) const commandsForSelectedElements = getMoveCommands(snappedDragVector) - return strategyApplicationResult([ - ...commandsForSelectedElements.commands, - updateHighlightedViews('mid-interaction', []), - setSnappingGuidelines('mid-interaction', guidelinesWithSnappingVector), - pushIntendedBoundsAndUpdateGroups( - commandsForSelectedElements.intendedBounds, - 'starting-metadata', - ), - setElementsToRerenderCommand([...targets, ...targetsForSnapping]), - setCursorCommand(CSSCursor.Select), - setActiveFrames(getActiveFrames(commandsForSelectedElements.intendedBounds)), - ]) + return strategyApplicationResult( + [ + ...commandsForSelectedElements.commands, + updateHighlightedViews('mid-interaction', []), + setSnappingGuidelines('mid-interaction', guidelinesWithSnappingVector), + pushIntendedBoundsAndUpdateGroups( + commandsForSelectedElements.intendedBounds, + 'starting-metadata', + ), + + setCursorCommand(CSSCursor.Select), + setActiveFrames(getActiveFrames(commandsForSelectedElements.intendedBounds)), + ], + [...targets, ...targetsForSnapping], + ) } } else { // Fallback for when the checks above are not satisfied. @@ -354,7 +360,7 @@ export function moveInspectorStrategy( intendedBounds.push(...moveCommandsResult.intendedBounds) } commands.push(pushIntendedBoundsAndUpdateGroups(intendedBounds, 'live-metadata')) - commands.push(setElementsToRerenderCommand(selectedElementPaths)) + return commands }, } @@ -385,7 +391,7 @@ export function directMoveInspectorStrategy( intendedBounds.push(...moveCommandsResult.intendedBounds) } commands.push(pushIntendedBoundsAndUpdateGroups(intendedBounds, 'live-metadata')) - commands.push(setElementsToRerenderCommand(selectedElementPaths)) + return commands }, } diff --git a/editor/src/components/canvas/commands/commands.ts b/editor/src/components/canvas/commands/commands.ts index 2e5241d5c0b3..2e496effcfa0 100644 --- a/editor/src/components/canvas/commands/commands.ts +++ b/editor/src/components/canvas/commands/commands.ts @@ -31,14 +31,6 @@ import type { ShowOutlineHighlight } from './show-outline-highlight-command' import { runShowOutlineHighlight } from './show-outline-highlight-command' import type { SetCursorCommand } from './set-cursor-command' import { runSetCursor } from './set-cursor-command' -import type { - AppendElementsToRerenderCommand, - SetElementsToRerenderCommand, -} from './set-elements-to-rerender-command' -import { - runAppendElementsToRerender, - runSetElementsToRerender, -} from './set-elements-to-rerender-command' import type { DuplicateElement } from './duplicate-element-command' import { runDuplicateElement } from './duplicate-element-command' import type { UpdateFunctionCommand } from './update-function-command' @@ -121,8 +113,6 @@ export type CanvasCommand = | ShowOutlineHighlight | ShowReorderIndicator | SetCursorCommand - | SetElementsToRerenderCommand - | AppendElementsToRerenderCommand | PushIntendedBoundsAndUpdateGroups | PushIntendedBoundsAndUpdateHuggingElements | DeleteProperties @@ -184,10 +174,6 @@ export function runCanvasCommand( return runShowReorderIndicator(editorState, command) case 'SET_CURSOR_COMMAND': return runSetCursor(editorState, command) - case 'SET_ELEMENTS_TO_RERENDER_COMMAND': - return runSetElementsToRerender(editorState, command) - case 'APPEND_ELEMENTS_TO_RERENDER_COMMAND': - return runAppendElementsToRerender(editorState, command) case 'PUSH_INTENDED_BOUNDS_AND_UPDATE_GROUPS': return runPushIntendedBoundsAndUpdateGroups(editorState, command, commandLifecycle) case 'PUSH_INTENDED_BOUNDS_AND_UPDATE_HUGGING_ELEMENTS': diff --git a/editor/src/components/canvas/commands/set-elements-to-rerender-command.ts b/editor/src/components/canvas/commands/set-elements-to-rerender-command.ts deleted file mode 100644 index 1b6c52fa3368..000000000000 --- a/editor/src/components/canvas/commands/set-elements-to-rerender-command.ts +++ /dev/null @@ -1,85 +0,0 @@ -import * as EP from '../../../core/shared/element-path' -import type { - EditorState, - EditorStatePatch, - ElementsToRerender, -} from '../../editor/store/editor-state' -import type { BaseCommand, CommandFunction } from './commands' - -export interface SetElementsToRerenderCommand extends BaseCommand { - type: 'SET_ELEMENTS_TO_RERENDER_COMMAND' - value: ElementsToRerender -} - -export function setElementsToRerenderCommand( - value: ElementsToRerender, -): SetElementsToRerenderCommand { - const uniqueValues = value === 'rerender-all-elements' ? value : EP.uniqueElementPaths(value) - return { - type: 'SET_ELEMENTS_TO_RERENDER_COMMAND', - whenToRun: 'mid-interaction', - value: uniqueValues, - } -} - -export const runSetElementsToRerender: CommandFunction = ( - e: EditorState, - command: SetElementsToRerenderCommand, -) => { - const editorStatePatch: EditorStatePatch = { - canvas: { - elementsToRerender: { $set: command.value }, - }, - } - return { - editorStatePatches: [editorStatePatch], - commandDescription: `Set Elements To Rerender: [${ - typeof command.value === 'string' ? command.value : command.value.map(EP.toString).join(', ') - }]`, - } -} - -// NOTE: You probably want to use the command above! Since we don't explicitly clear the current -// value of canvas.elementsToRerender, and the default value is 'render-all-elements', if you use -// this command in the wrong place you can very easily end up re-rendering everything -export interface AppendElementsToRerenderCommand extends BaseCommand { - type: 'APPEND_ELEMENTS_TO_RERENDER_COMMAND' - value: ElementsToRerender -} - -export function appendElementsToRerenderCommand( - value: ElementsToRerender, -): AppendElementsToRerenderCommand { - return { - type: 'APPEND_ELEMENTS_TO_RERENDER_COMMAND', - whenToRun: 'mid-interaction', - value: value, - } -} - -function mergeElementsToRerender(l: ElementsToRerender, r: ElementsToRerender): ElementsToRerender { - if (l === 'rerender-all-elements' || r === 'rerender-all-elements') { - return 'rerender-all-elements' - } else { - return [...l, ...r] - } -} - -export const runAppendElementsToRerender: CommandFunction = ( - e: EditorState, - command: AppendElementsToRerenderCommand, -) => { - const editorStatePatch: EditorStatePatch = { - canvas: { - elementsToRerender: { - $apply: (current: ElementsToRerender) => mergeElementsToRerender(current, command.value), - }, - }, - } - return { - editorStatePatches: [editorStatePatch], - commandDescription: `Append Elements To Rerender: [${ - typeof command.value === 'string' ? command.value : command.value.map(EP.toString).join(', ') - }]`, - } -} diff --git a/editor/src/components/canvas/controls/select-mode/canvas-strategy-picker.spec.browser2.tsx b/editor/src/components/canvas/controls/select-mode/canvas-strategy-picker.spec.browser2.tsx index 1982d17b690b..a3dfe5df0d87 100644 --- a/editor/src/components/canvas/controls/select-mode/canvas-strategy-picker.spec.browser2.tsx +++ b/editor/src/components/canvas/controls/select-mode/canvas-strategy-picker.spec.browser2.tsx @@ -32,7 +32,7 @@ const BestStrategy: CanvasStrategy = { icon: { category: 'tools', type: 'pointer' }, controlsToRender: [], fitness: 10, - apply: () => strategyApplicationResult([]), + apply: () => strategyApplicationResult([], 'rerender-all-elements'), } const AverageStrategy: CanvasStrategy = { @@ -42,7 +42,7 @@ const AverageStrategy: CanvasStrategy = { icon: { category: 'tools', type: 'pointer' }, controlsToRender: [], fitness: 5, - apply: () => strategyApplicationResult([]), + apply: () => strategyApplicationResult([], 'rerender-all-elements'), } const WorstStrategy: CanvasStrategy = { @@ -52,7 +52,7 @@ const WorstStrategy: CanvasStrategy = { icon: { category: 'tools', type: 'pointer' }, controlsToRender: [], fitness: 1, - apply: () => strategyApplicationResult([]), + apply: () => strategyApplicationResult([], 'rerender-all-elements'), } const UnfitStrategy: CanvasStrategy = { @@ -62,7 +62,7 @@ const UnfitStrategy: CanvasStrategy = { icon: { category: 'tools', type: 'pointer' }, controlsToRender: [], fitness: 0, - apply: () => strategyApplicationResult([]), + apply: () => strategyApplicationResult([], 'rerender-all-elements'), } // Deliberately not in sorted order diff --git a/editor/src/components/editor/actions/actions.tsx b/editor/src/components/editor/actions/actions.tsx index a1c4cea4ef20..14cc63ab0cfa 100644 --- a/editor/src/components/editor/actions/actions.tsx +++ b/editor/src/components/editor/actions/actions.tsx @@ -485,7 +485,6 @@ import { } from '../../canvas/canvas-strategies/strategies/shared-move-strategies-helpers' import type { CanvasCommand } from '../../canvas/commands/commands' import { foldAndApplyCommandsSimple } from '../../canvas/commands/commands' -import { setElementsToRerenderCommand } from '../../canvas/commands/set-elements-to-rerender-command' import type { UiJsxCanvasContextData } from '../../canvas/ui-jsx-canvas' import { notice } from '../../common/notice' import type { ShortcutConfiguration } from '../shortcut-definitions' @@ -5781,7 +5780,13 @@ export const UPDATE_FNS = { } }, SET_ELEMENTS_TO_RERENDER: (action: SetElementsToRerender, editor: EditorModel): EditorModel => { - return foldAndApplyCommandsSimple(editor, [setElementsToRerenderCommand(action.value)]) + return { + ...editor, + canvas: { + ...editor.canvas, + elementsToRerender: action.value, + }, + } }, TOGGLE_SELECTION_LOCK: (action: ToggleSelectionLock, editor: EditorModel): EditorModel => { const targets = action.targets diff --git a/editor/src/components/editor/store/dispatch-strategies.spec.tsx b/editor/src/components/editor/store/dispatch-strategies.spec.tsx index 79b1e71e1a0b..a3ffdb94c054 100644 --- a/editor/src/components/editor/store/dispatch-strategies.spec.tsx +++ b/editor/src/components/editor/store/dispatch-strategies.spec.tsx @@ -157,9 +157,10 @@ const testStrategy: MetaCanvasStrategy = ( controlsToRender: [], fitness: 10, apply: function (): StrategyApplicationResult { - return strategyApplicationResult([ - wildcardPatch('always', { canvas: { scale: { $set: 100 } } }), - ]) + return strategyApplicationResult( + [wildcardPatch('always', { canvas: { scale: { $set: 100 } } })], + 'rerender-all-elements', + ) }, descriptiveLabel: 'A Test Strategy', icon: { @@ -984,7 +985,7 @@ describe('only update metadata on SAVE_DOM_REPORT', () => { }, apply: function (): StrategyApplicationResult { if (interactionSession == null) { - return strategyApplicationResult([]) + return strategyApplicationResult([], 'rerender-all-elements') } expect(canvasState.startingMetadata).not.toBe(interactionSession.latestMetadata) expect(canvasState.startingAllElementProps).not.toBe( @@ -1011,7 +1012,7 @@ describe('only update metadata on SAVE_DOM_REPORT', () => { .backgroundColor, ).toBeDefined() testStrategyRan = true - return strategyApplicationResult([]) + return strategyApplicationResult([], 'rerender-all-elements') }, }, ], diff --git a/editor/src/components/editor/store/dispatch-strategies.tsx b/editor/src/components/editor/store/dispatch-strategies.tsx index 682477d3084e..7801ff49e943 100644 --- a/editor/src/components/editor/store/dispatch-strategies.tsx +++ b/editor/src/components/editor/store/dispatch-strategies.tsx @@ -5,6 +5,7 @@ import type { } from '../../canvas/canvas-strategies/canvas-strategies' import { applyCanvasStrategy, + applyElementsToRerenderFromStrategyResult, findCanvasStrategy, interactionInProgress, pickCanvasStateFromEditorState, @@ -47,6 +48,7 @@ import type { CustomStrategyState, CustomStrategyStatePatch, InteractionCanvasState, + StrategyApplicationResult, } from '../../canvas/canvas-strategies/canvas-strategy-types' import { strategyApplicationResult } from '../../canvas/canvas-strategies/canvas-strategy-types' import { isFeatureEnabled } from '../../../utils/feature-switches' @@ -91,7 +93,7 @@ export function interactionFinished( result.strategyState.currentStrategy, ) - const strategyResult = + const strategyResult: StrategyApplicationResult = strategy != null ? applyCanvasStrategy( strategy.strategy, @@ -100,9 +102,7 @@ export function interactionFinished( result.strategyState.customStrategyState, 'end-interaction', ) - : { - commands: [], - } + : strategyApplicationResult([], 'rerender-all-elements') const commandResult = foldAndApplyCommands( newEditorState, storedState.patchedEditor, @@ -111,13 +111,16 @@ export function interactionFinished( 'end-interaction', ) - const finalEditor: EditorState = { - ...commandResult.editorState, - // TODO instead of clearing the metadata, we should save the latest valid metadata here to save a dom-walker run - jsxMetadata: {}, - domMetadata: {}, - spyMetadata: {}, - } + const finalEditor: EditorState = applyElementsToRerenderFromStrategyResult( + { + ...commandResult.editorState, + // TODO instead of clearing the metadata, we should save the latest valid metadata here to save a dom-walker run + jsxMetadata: {}, + domMetadata: {}, + spyMetadata: {}, + }, + strategyResult, + ) return { unpatchedEditorState: finalEditor, @@ -217,7 +220,10 @@ export function interactionHardReset( return { unpatchedEditorState: newEditorState, - patchedEditorState: commandResult.editorState, + patchedEditorState: applyElementsToRerenderFromStrategyResult( + commandResult.editorState, + strategyResult, + ), newStrategyState: newStrategyState, } } else { @@ -380,7 +386,10 @@ export function interactionStart( return { unpatchedEditorState: newEditorState, - patchedEditorState: commandResult.editorState, + patchedEditorState: applyElementsToRerenderFromStrategyResult( + commandResult.editorState, + strategyResult, + ), newStrategyState: newStrategyState, } } else { @@ -483,7 +492,10 @@ function handleUserChangedStrategy( return { unpatchedEditorState: newEditorState, - patchedEditorState: commandResult.editorState, + patchedEditorState: applyElementsToRerenderFromStrategyResult( + commandResult.editorState, + strategyResult, + ), newStrategyState: newStrategyState, } } else { @@ -537,7 +549,7 @@ function handleAccumulatingKeypresses( strategyState.customStrategyState, 'mid-interaction', ) - : strategyApplicationResult([]) + : strategyApplicationResult([], 'rerender-all-elements') const commandResult = foldAndApplyCommands( updatedEditorState, storedEditorState, @@ -565,7 +577,10 @@ function handleAccumulatingKeypresses( return { unpatchedEditorState: updatedEditorState, - patchedEditorState: commandResult.editorState, + patchedEditorState: applyElementsToRerenderFromStrategyResult( + commandResult.editorState, + strategyResult, + ), newStrategyState: newStrategyState, } } @@ -601,7 +616,7 @@ function handleUpdate( strategyState.customStrategyState, 'mid-interaction', ) - : strategyApplicationResult([]) + : strategyApplicationResult([], 'rerender-all-elements') const commandResult = foldAndApplyCommands( newEditorState, storedEditorState, @@ -628,7 +643,10 @@ function handleUpdate( } return { unpatchedEditorState: newEditorState, - patchedEditorState: commandResult.editorState, + patchedEditorState: applyElementsToRerenderFromStrategyResult( + commandResult.editorState, + strategyResult, + ), newStrategyState: newStrategyState, } } else { diff --git a/editor/src/components/editor/store/editor-state.ts b/editor/src/components/editor/store/editor-state.ts index aa3231f356da..d6090a49e8bb 100644 --- a/editor/src/components/editor/store/editor-state.ts +++ b/editor/src/components/editor/store/editor-state.ts @@ -852,6 +852,17 @@ export function editorStateCanvasControls( export type ElementsToRerender = Array | 'rerender-all-elements' +export function combineElementsToRerender( + first: ElementsToRerender, + second: ElementsToRerender, +): ElementsToRerender { + if (first === 'rerender-all-elements' || second === 'rerender-all-elements') { + return 'rerender-all-elements' + } else { + return [...first, ...second] + } +} + export interface InternalClipboard { styleClipboard: Array elements: Array From 7f1f4709206afadb0ead384301bba6b17332b168 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:33:08 +0200 Subject: [PATCH 057/272] Grid resize fix striped area positioning and sizing (#6422) **Problem:** The grid resize striped area has two issues: 1. it is positioned and sized based on the container size and not the actual grid template 2. it does not get positioned correctly when zoomed **Fix:** This PR fixes both issues. | Before | After | |--------|------------| | ![Kapture 2024-09-27 at 15 02 14](https://github.com/user-attachments/assets/8d74f95c-7eec-43d3-9952-90d6dd77c567) | ![Kapture 2024-09-27 at 15 00 47](https://github.com/user-attachments/assets/a4d52f24-430f-462c-9d07-52fa0208c2de) | Fixes #6421 --- .../canvas/controls/grid-controls.tsx | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 2b47c4e806b1..a72f25fbb4b5 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -157,10 +157,11 @@ export interface GridResizingControlProps { axis: Axis containingFrame: CanvasRectangle fromPropsAxisValues: GridAutoOrTemplateDimensions | null - padding: number | null + padding: number resizing: 'resize-target' | 'resize-generated' | 'not-resizing' setResizingIndex: (v: number | null) => void resizeLocked: boolean + stripedAreaLength: number | null } export const GridResizingControl = React.memo((props: GridResizingControlProps) => { @@ -229,6 +230,11 @@ export const GridResizingControl = React.memo((props: GridResizingControlProps) : props.containingFrame.width + GRID_RESIZE_HANDLE_CONTAINER_SIZE }, [props.containingFrame, props.axis]) + const stripedAreaSkew = React.useMemo( + () => GRID_RESIZE_HANDLE_CONTAINER_SIZE / scale + props.padding, + [scale, props.padding], + ) + return (
{ dimensionIndex={dimensionIndex} dimension={dimension} fromPropsAxisValues={fromProps} + stripedAreaLength={props.stripedAreaLength} axis={props.axis} containingFrame={props.containingFrame} resizing={ @@ -444,8 +460,8 @@ export const GridResizing = React.memo((props: GridResizingProps) => { props.padding == null ? 0 : props.axis === 'column' - ? props.padding.left ?? 0 - : props.padding.top ?? 0 + ? props.padding.top ?? 0 + : props.padding.left ?? 0 } /> ) @@ -552,6 +568,18 @@ export const GridRowColumnResizingControls = controlForStrategyMemoized(({ target }) => { const grids = useGridData([target]) + function getStripedAreaLength(template: GridAutoOrTemplateBase | null, gap: number) { + if (template?.type !== 'DIMENSIONS') { + return null + } + return template.dimensions.reduce((acc, curr, index) => { + if (curr.type === 'NUMBER') { + return acc + curr.value.value + (index > 0 ? gap : 0) + } + return acc + }, 0) + } + return ( {grids.flatMap((grid) => { @@ -564,6 +592,7 @@ export const GridRowColumnResizingControls = axis={'column'} gap={grid.columnGap ?? grid.gap} padding={grid.padding} + stripedAreaLength={getStripedAreaLength(grid.gridTemplateRows, grid.gap ?? 0)} /> ) })} @@ -577,6 +606,7 @@ export const GridRowColumnResizingControls = axis={'row'} gap={grid.rowGap ?? grid.gap} padding={grid.padding} + stripedAreaLength={getStripedAreaLength(grid.gridTemplateColumns, grid.gap ?? 0)} /> ) })} From 46a961eb3b8a9ebb0f0a985ea4269953786eb0b5 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:53:34 +0200 Subject: [PATCH 058/272] Use stretch instead of fill for grid children (#6424) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem:** The inspector should show `Stretch` instead of `Fill` for grid children, and set `alignSelf`/`justifySelf` in those cases. **Fix:** 1. Set `alignSelf`/`justifySelf` to `stretch` if `Stretch` is selected in the inspector dropdown for grid children 2. Show `Stretch` instead of `Fill` for label for grid children (note: I opted for just changing the label here instead of having a different strategy altogether, since in my mind it's still fulfilling the goal of "filling" the parent – but lmk if this is the wrong take) Fixes #6423 --- .../strategies/basic-resize-strategy.tsx | 44 +++++++---- .../select-mode/absolute-resize-control.tsx | 2 + .../src/components/editor/actions/actions.tsx | 79 +++++++++++++++---- .../inspector/fill-hug-fixed-control.tsx | 7 ++ .../components/inspector/inspector-common.ts | 50 +++++++++++- .../fill-container-basic-strategy.ts | 78 +++++++++++++++++- .../fixed-size-basic-strategy.ts | 7 +- .../inspector-strategies.ts | 2 + .../inspector/resize-to-fit-control.tsx | 1 + 9 files changed, 232 insertions(+), 38 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx index 2da9612b7ae7..53f768b6e61d 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx @@ -11,6 +11,7 @@ import { isInfinityRectangle, offsetPoint, } from '../../../../core/shared/math-utils' +import * as PP from '../../../../core/shared/property-path' import { styleStringInArray } from '../../../../utils/common-constants' import { trueUpGroupElementChanged } from '../../../editor/store/editor-state' import { stylePropPathMappingFn } from '../../../inspector/common/property-path-hooks' @@ -20,6 +21,7 @@ import { oppositeEdgePosition } from '../../canvas-types' import { isEdgePositionACorner, isEdgePositionAHorizontalEdge, + isEdgePositionAVerticalEdge, pickPointOnRect, } from '../../canvas-utils' import type { LengthPropertyToAdjust } from '../../commands/adjust-css-length-command' @@ -27,6 +29,8 @@ import { adjustCssLengthProperties, lengthPropertyToAdjust, } from '../../commands/adjust-css-length-command' +import type { CanvasCommand } from '../../commands/commands' +import { deleteProperties } from '../../commands/delete-properties-command' import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command' import { queueTrueUpElement } from '../../commands/queue-true-up-command' import { setCursorCommand } from '../../commands/set-cursor-command' @@ -219,21 +223,31 @@ export function basicResizeStrategy( const elementsToRerender = [...selectedElements, ...gridsToRerender] - return strategyApplicationResult( - [ - adjustCssLengthProperties('always', selectedElement, null, resizeProperties), - updateHighlightedViews('mid-interaction', []), - setCursorCommand(pickCursorFromEdgePosition(edgePosition)), - pushIntendedBoundsAndUpdateGroups( - [{ target: selectedElement, frame: resizedBounds }], - 'starting-metadata', - ), - ...groupChildren.map((c) => - queueTrueUpElement([trueUpGroupElementChanged(c.elementPath)]), - ), - ], - elementsToRerender, - ) + let commands: CanvasCommand[] = [ + adjustCssLengthProperties('always', selectedElement, null, resizeProperties), + updateHighlightedViews('mid-interaction', []), + setCursorCommand(pickCursorFromEdgePosition(edgePosition)), + pushIntendedBoundsAndUpdateGroups( + [{ target: selectedElement, frame: resizedBounds }], + 'starting-metadata', + ), + ...groupChildren.map((c) => + queueTrueUpElement([trueUpGroupElementChanged(c.elementPath)]), + ), + ] + + if (isEdgePositionAHorizontalEdge(edgePosition)) { + commands.push( + deleteProperties('always', selectedElement, [PP.create('style', 'justifySelf')]), + ) + } + if (isEdgePositionAVerticalEdge(edgePosition)) { + commands.push( + deleteProperties('always', selectedElement, [PP.create('style', 'alignSelf')]), + ) + } + + return strategyApplicationResult(commands, elementsToRerender) } else { return strategyApplicationResult( [ diff --git a/editor/src/components/canvas/controls/select-mode/absolute-resize-control.tsx b/editor/src/components/canvas/controls/select-mode/absolute-resize-control.tsx index 38f456abf349..c8db573bd4af 100644 --- a/editor/src/components/canvas/controls/select-mode/absolute-resize-control.tsx +++ b/editor/src/components/canvas/controls/select-mode/absolute-resize-control.tsx @@ -398,6 +398,8 @@ const sizeLabel = (state: FixedHugFill['type'], actualSize: number): string => { case 'detected': case 'computed': return `${actualSize}` + case 'stretch': + return 'Stretch' default: assertNever(state) } diff --git a/editor/src/components/editor/actions/actions.tsx b/editor/src/components/editor/actions/actions.tsx index 14cc63ab0cfa..4b02829f691a 100644 --- a/editor/src/components/editor/actions/actions.tsx +++ b/editor/src/components/editor/actions/actions.tsx @@ -4,8 +4,7 @@ import localforage from 'localforage' import { imagePathURL } from '../../../common/server' import { roundAttributeLayoutValues } from '../../../core/layout/layout-utils' import { - findElementAtPath, - findJSXElementAtPath, + getSimpleAttributeAtPath, getZIndexOrderedViewsWithoutDirectChildren, MetadataUtils, } from '../../../core/model/element-metadata-utils' @@ -102,6 +101,7 @@ import type { LocalRectangle, Size, CanvasVector, + MaybeInfinityCanvasRectangle, } from '../../../core/shared/math-utils' import { canvasRectangle, @@ -157,7 +157,7 @@ import { assertNever, fastForEach, getProjectLockedKey, identity } from '../../. import { emptyImports, mergeImports } from '../../../core/workers/common/project-file-utils' import type { UtopiaTsWorkers } from '../../../core/workers/common/worker-types' import type { IndexPosition } from '../../../utils/utils' -import Utils, { absolute } from '../../../utils/utils' +import Utils from '../../../utils/utils' import type { ProjectContentTreeRoot } from '../../assets' import { isProjectContentFile, @@ -430,7 +430,7 @@ import { import { loadStoredState } from '../stored-state' import { applyMigrations } from './migrations/migrations' -import { boundsInFile, defaultConfig } from 'utopia-vscode-common' +import { defaultConfig } from 'utopia-vscode-common' import { reorderElement } from '../../../components/canvas/commands/reorder-element-command' import type { BuiltInDependencies } from '../../../core/es-modules/package-manager/built-in-dependencies-list' import { fetchNodeModules } from '../../../core/es-modules/package-manager/fetch-packages' @@ -495,7 +495,6 @@ import { clearImageFileBlob, enableInsertModeForJSXElement, finishCheckpointTimer, - insertAsChildTarget, insertJSXElement, openCodeEditorFile, replaceMappedElement, @@ -524,7 +523,6 @@ import { styleStringInArray } from '../../../utils/common-constants' import { collapseTextElements } from '../../../components/text-editor/text-handling' import { LayoutPropertyList, StyleProperties } from '../../inspector/common/css-utils' import { - getFromPropOrFlagComment, isUtopiaPropOrCommentFlag, makeUtopiaFlagComment, removePropOrFlagComment, @@ -543,7 +541,10 @@ import { replaceWithElementsWrappedInFragmentBehaviour, } from '../store/insertion-path' import { getConditionalCaseCorrespondingToBranchPath } from '../../../core/model/conditionals' -import { deleteProperties } from '../../canvas/commands/delete-properties-command' +import { + deleteProperties, + deleteValuesAtPath, +} from '../../canvas/commands/delete-properties-command' import { treatElementAsFragmentLike } from '../../canvas/canvas-strategies/strategies/fragment-like-helpers' import { fixParentContainingBlockSettings, @@ -619,11 +620,12 @@ import { import type { FixUIDsState } from '../../../core/workers/parser-printer/uid-fix' import { fixTopLevelElementsUIDs } from '../../../core/workers/parser-printer/uid-fix' import { nextSelectedTab } from '../../navigator/left-pane/left-pane-utils' -import { getDefaultedRemixRootDir, getRemixRootDir } from '../store/remix-derived-data' +import { getDefaultedRemixRootDir } from '../store/remix-derived-data' import { isReplaceKeepChildrenAndStyleTarget } from '../../navigator/navigator-item/component-picker-context-menu' import { canCondenseJSXElementChild } from '../../../utils/can-condense' import { getNavigatorTargetsFromEditorState } from '../../navigator/navigator-utils' import { applyValuesAtPath } from '../../canvas/commands/adjust-number-command' +import { styleP } from '../../inspector/inspector-common' export const MIN_CODE_PANE_REOPEN_WIDTH = 100 @@ -6589,10 +6591,54 @@ function removeErrorMessagesForFile(editor: EditorState, filename: string): Edit function alignFlexOrGridChildren(editor: EditorState, views: ElementPath[], alignment: Alignment) { let workingEditorState = { ...editor } for (const view of views) { - function apply(prop: 'alignSelf' | 'justifySelf', value: string) { - return applyValuesAtPath(workingEditorState, view, [ + // When updating alongside the given alignment, also update the opposite one so that it makes sense: + // For example, if alignment is 'alignSelf', delete the 'justifySelf' if currently set to stretch and, if so, + // set the explicit height of the element (and vice versa for 'justifySelf'). + function updateOpposite( + editorState: EditorState, + frame: MaybeInfinityCanvasRectangle | null, + target: 'alignSelf' | 'justifySelf', + dimension: 'width' | 'height', + ) { + let working = { ...editorState } + + working = deleteValuesAtPath(working, view, [styleP(target)]).editorStateWithChanges + + working = applyValuesAtPath(working, view, [ + { + path: styleP(dimension), + value: jsExpressionValue(zeroRectIfNullOrInfinity(frame)[dimension], emptyComments), + }, + ]).editorStateWithChanges + + return working + } + + function apply(editorState: EditorState, prop: 'alignSelf' | 'justifySelf', value: string) { + const element = MetadataUtils.findElementByElementPath(editor.jsxMetadata, view) + if (element == null || isLeft(element.element) || !isJSXElement(element.element.value)) { + return workingEditorState + } + + let working = editorState + + working = applyValuesAtPath(working, view, [ { path: PP.create('style', prop), value: jsExpressionValue(value, emptyComments) }, ]).editorStateWithChanges + + const alignSelfStretch = + getSimpleAttributeAtPath(right(element.element.value.props), styleP('alignSelf')).value === + 'stretch' + const justifySelfStretch = + getSimpleAttributeAtPath(right(element.element.value.props), styleP('justifySelf')) + .value === 'stretch' + + if (prop === 'alignSelf' && justifySelfStretch) { + working = updateOpposite(working, element.globalFrame, 'justifySelf', 'height') + } else if (prop === 'justifySelf' && alignSelfStretch) { + working = updateOpposite(working, element.globalFrame, 'alignSelf', 'width') + } + return working } const { align, justify } = MetadataUtils.getRelativeAlignJustify( @@ -6602,27 +6648,28 @@ function alignFlexOrGridChildren(editor: EditorState, views: ElementPath[], alig switch (alignment) { case 'bottom': - workingEditorState = apply(align, 'end') + workingEditorState = apply(workingEditorState, align, 'end') break case 'top': - workingEditorState = apply(align, 'start') + workingEditorState = apply(workingEditorState, align, 'start') break case 'vcenter': - workingEditorState = apply(align, 'center') + workingEditorState = apply(workingEditorState, align, 'center') break case 'hcenter': - workingEditorState = apply(justify, 'center') + workingEditorState = apply(workingEditorState, justify, 'center') break case 'left': - workingEditorState = apply(justify, 'start') + workingEditorState = apply(workingEditorState, justify, 'start') break case 'right': - workingEditorState = apply(justify, 'end') + workingEditorState = apply(workingEditorState, justify, 'end') break default: assertNever(alignment) } } + return workingEditorState } diff --git a/editor/src/components/inspector/fill-hug-fixed-control.tsx b/editor/src/components/inspector/fill-hug-fixed-control.tsx index e97e7e2e5e5b..08dd8f40050e 100644 --- a/editor/src/components/inspector/fill-hug-fixed-control.tsx +++ b/editor/src/components/inspector/fill-hug-fixed-control.tsx @@ -80,6 +80,7 @@ export const CollapsedLabel = 'Collapsed' as const export const HugGroupContentsLabel = 'Hug' as const export const ComputedLabel = 'Computed' as const export const DetectedLabel = 'Detected' as const +export const StretchLabel = 'Stretch' as const export function selectOptionLabel(mode: FixedHugFillMode): string { switch (mode) { @@ -101,6 +102,8 @@ export function selectOptionLabel(mode: FixedHugFillMode): string { return ComputedLabel case 'detected': return DetectedLabel + case 'stretch': + return StretchLabel default: assertNever(mode) } @@ -126,6 +129,8 @@ export function selectOptionIconType( return `fixed-${dimension}` case 'detected': return `fixed-${dimension}` + case 'stretch': + return `fill-${dimension}` default: assertNever(mode) } @@ -396,6 +401,7 @@ function strategyForChangingFillFixedHugType( ): Array { switch (mode) { case 'fill': + case 'stretch': return setPropFillStrategies(metadata, selectedElements, axis, 'default', otherAxisSetToFill) case 'hug': case 'squeeze': @@ -427,6 +433,7 @@ function pickFixedValue(value: FixedHugFill): CSSNumber | undefined { case 'fill': case 'hug-group': return value.value + case 'stretch': case 'hug': case 'squeeze': case 'collapsed': diff --git a/editor/src/components/inspector/inspector-common.ts b/editor/src/components/inspector/inspector-common.ts index e51e2fecd4fd..7f0b03ef28a1 100644 --- a/editor/src/components/inspector/inspector-common.ts +++ b/editor/src/components/inspector/inspector-common.ts @@ -647,6 +647,7 @@ export type FixedHugFill = | { type: 'computed'; value: CSSNumber } | { type: 'detected'; value: CSSNumber } | { type: 'scaled'; value: CSSNumber } + | { type: 'stretch' } export type FixedHugFillMode = FixedHugFill['type'] @@ -666,6 +667,30 @@ export function detectFillHugFixedState( return { fixedHugFill: null, controlStatus: 'off' } } + const width = foldEither( + () => null, + (value) => defaultEither(null, parseCSSNumber(value, 'Unitless')), + getSimpleAttributeAtPath(right(element.element.value.props), PP.create('style', 'width')), + ) + const height = foldEither( + () => null, + (value) => defaultEither(null, parseCSSNumber(value, 'Unitless')), + getSimpleAttributeAtPath(right(element.element.value.props), PP.create('style', 'height')), + ) + + if (MetadataUtils.isGridCell(metadata, elementPath)) { + if ( + (element.specialSizeMeasurements.alignSelf === 'stretch' && + axis === 'horizontal' && + width == null) || + (element.specialSizeMeasurements.justifySelf === 'stretch' && + axis === 'vertical' && + height == null) + ) { + return { fixedHugFill: { type: 'stretch' }, controlStatus: 'detected' } + } + } + const flexGrowLonghand = foldEither( () => null, (value) => defaultEither(null, parseCSSNumber(value, 'Unitless')), @@ -1071,7 +1096,11 @@ export function getFixedFillHugOptionsForElement( (!isGroup && basicHugContentsApplicableForContainer(metadata, pathTrees, selectedView)) ? 'hug' : null, - fillContainerApplicable(metadata, selectedView) ? 'fill' : null, + fillContainerApplicable(metadata, selectedView) + ? MetadataUtils.isGridCell(metadata, selectedView) + ? 'stretch' + : 'fill' + : null, ]), ) } @@ -1198,6 +1227,20 @@ export function removeExtraPinsWhenSettingSize( ) } +export function removeAlignJustifySelf( + axis: Axis, + elementMetadata: ElementInstanceMetadata | null, +): Array { + if (elementMetadata == null) { + return [] + } + return [ + deleteProperties('always', elementMetadata.elementPath, [ + styleP(axis === 'horizontal' ? 'alignSelf' : 'justifySelf'), + ]), + ] +} + export function isFixedHugFillEqual( a: { fixedHugFill: FixedHugFill | null; controlStatus: ControlStatus }, b: { fixedHugFill: FixedHugFill | null; controlStatus: ControlStatus }, @@ -1230,9 +1273,10 @@ export function isFixedHugFillEqual( a.fixedHugFill.value.value === b.fixedHugFill.value.value && a.fixedHugFill.value.unit === b.fixedHugFill.value.unit ) + case 'stretch': + return a.fixedHugFill.type === b.fixedHugFill.type default: - const _exhaustiveCheck: never = a.fixedHugFill - throw new Error(`Unknown type in FixedHugFill ${JSON.stringify(a.fixedHugFill)}`) + assertNever(a.fixedHugFill) } } diff --git a/editor/src/components/inspector/inspector-strategies/fill-container-basic-strategy.ts b/editor/src/components/inspector/inspector-strategies/fill-container-basic-strategy.ts index 230669cf7a09..20ca8f6a8b7b 100644 --- a/editor/src/components/inspector/inspector-strategies/fill-container-basic-strategy.ts +++ b/editor/src/components/inspector/inspector-strategies/fill-container-basic-strategy.ts @@ -1,7 +1,12 @@ import * as PP from '../../../core/shared/property-path' -import { MetadataUtils } from '../../../core/model/element-metadata-utils' +import { getSimpleAttributeAtPath, MetadataUtils } from '../../../core/model/element-metadata-utils' import { clamp } from '../../../core/shared/math-utils' -import { setProperty } from '../../canvas/commands/set-property-command' +import { + propertyToDelete, + propertyToSet, + setProperty, + updateBulkProperties, +} from '../../canvas/commands/set-property-command' import type { FlexDirection } from '../common/css-utils' import { cssNumber, printCSSNumber } from '../common/css-utils' import type { Axis } from '../inspector-common' @@ -14,6 +19,8 @@ import { nukeSizingPropsForAxisCommand, nullOrNonEmpty, setParentToFixedIfHugCommands, + removeAlignJustifySelf, + styleP, } from '../inspector-common' import type { InspectorStrategy } from './inspector-strategy' import { @@ -24,8 +31,13 @@ import { groupErrorToastCommand, maybeInvalidGroupState, } from '../../canvas/canvas-strategies/strategies/group-helpers' -import type { ElementInstanceMetadataMap } from '../../../core/shared/element-template' +import { + isJSXElement, + type ElementInstanceMetadataMap, +} from '../../../core/shared/element-template' import type { ElementPath } from '../../../core/shared/project-file-types' +import { foldEither, defaultEither, right, isLeft } from '../../../core/shared/either' +import { parseString } from '../../../utils/value-parser-utils' export const fillContainerStrategyFlow = ( metadata: ElementInstanceMetadataMap, @@ -102,6 +114,8 @@ export const fillContainerStrategyFlexParent = ( } const commands = elements.flatMap((path) => { + const elementMetadata = MetadataUtils.findElementByElementPath(metadata, path) + const flexDirection = overrides.forceFlexDirectionForParent ?? detectParentFlexDirection(metadata, path) ?? 'row' @@ -113,6 +127,7 @@ export const fillContainerStrategyFlexParent = ( value === 'default' ? cssNumber(100, '%') : cssNumber(clamp(0, 100, value), '%') return [ ...setParentToFixedIfHugCommands(axis, metadata, path), + ...removeAlignJustifySelf(axis, elementMetadata), setCssLengthProperty( 'always', path, @@ -128,6 +143,7 @@ export const fillContainerStrategyFlexParent = ( return [ ...nukeAllAbsolutePositioningPropsCommands(path), + ...removeAlignJustifySelf(axis, elementMetadata), ...setParentToFixedIfHugCommands(axis, metadata, path), nukeSizingPropsForAxisCommand(axis, path), setProperty( @@ -142,3 +158,59 @@ export const fillContainerStrategyFlexParent = ( return nullOrNonEmpty(commands) }, }) + +export const fillContainerStrategyGridParent = ( + metadata: ElementInstanceMetadataMap, + elementPaths: ElementPath[], + axis: Axis, +): InspectorStrategy => ({ + name: 'Set to Fill Container, in grid layout', + strategy: () => { + const elements = elementPaths.filter( + (path) => fillContainerApplicable(metadata, path) && MetadataUtils.isGridCell(metadata, path), + ) + + if (elements.length === 0) { + return null + } + + const commands = elements.flatMap((path) => { + const element = MetadataUtils.findElementByElementPath(metadata, path) + if (element == null || isLeft(element.element) || !isJSXElement(element.element.value)) { + return [] + } + + const alignSelf = foldEither( + () => null, + (value) => defaultEither(null, parseString(value)), + getSimpleAttributeAtPath(right(element.element.value.props), styleP('alignSelf')), + ) + + const justifySelf = foldEither( + () => null, + (value) => defaultEither(null, parseString(value)), + getSimpleAttributeAtPath(right(element.element.value.props), styleP('justifySelf')), + ) + + let updates = [ + propertyToSet(styleP(axis === 'horizontal' ? 'alignSelf' : 'justifySelf'), 'stretch'), + ] + + // delete the opposite side value (justify <> align) if not set to stretch + if (axis === 'vertical' && alignSelf !== 'stretch') { + updates.push(propertyToDelete(styleP('alignSelf'))) + } else if (axis === 'horizontal' && justifySelf !== 'stretch') { + updates.push(propertyToDelete(styleP('justifySelf'))) + } + + return [ + ...nukeAllAbsolutePositioningPropsCommands(path), + ...setParentToFixedIfHugCommands(axis, metadata, path), + nukeSizingPropsForAxisCommand(axis, path), + updateBulkProperties('always', path, updates), + ] + }) + + return nullOrNonEmpty(commands) + }, +}) diff --git a/editor/src/components/inspector/inspector-strategies/fixed-size-basic-strategy.ts b/editor/src/components/inspector/inspector-strategies/fixed-size-basic-strategy.ts index 1c62f3d07fcf..504650a00db9 100644 --- a/editor/src/components/inspector/inspector-strategies/fixed-size-basic-strategy.ts +++ b/editor/src/components/inspector/inspector-strategies/fixed-size-basic-strategy.ts @@ -7,7 +7,11 @@ import { } from '../../canvas/commands/set-css-length-command' import type { CSSNumber } from '../common/css-utils' import type { Axis } from '../inspector-common' -import { removeExtraPinsWhenSettingSize, widthHeightFromAxis } from '../inspector-common' +import { + removeAlignJustifySelf, + removeExtraPinsWhenSettingSize, + widthHeightFromAxis, +} from '../inspector-common' import type { InspectorStrategy } from './inspector-strategy' import { queueTrueUpElement } from '../../canvas/commands/queue-true-up-command' import { @@ -48,6 +52,7 @@ export const fixedSizeBasicStrategy = ( return [ ...removeExtraPinsWhenSettingSize(axis, elementMetadata), + ...removeAlignJustifySelf(axis, elementMetadata), setCssLengthProperty( whenToRun, path, diff --git a/editor/src/components/inspector/inspector-strategies/inspector-strategies.ts b/editor/src/components/inspector/inspector-strategies/inspector-strategies.ts index 3e87820adcfb..a066a3494321 100644 --- a/editor/src/components/inspector/inspector-strategies/inspector-strategies.ts +++ b/editor/src/components/inspector/inspector-strategies/inspector-strategies.ts @@ -26,6 +26,7 @@ import { import { fillContainerStrategyFlexParent, fillContainerStrategyFlow, + fillContainerStrategyGridParent, } from './fill-container-basic-strategy' import { setSpacingModePacked, setSpacingModeSpaceBetween } from './spacing-mode-strategies' import { convertLayoutToFlexCommands } from '../../common/shared-strategies/convert-to-flex-strategy' @@ -226,6 +227,7 @@ export const setPropFillStrategies = ( value: 'default' | number, otherAxisSetToFill: boolean, ): Array => [ + fillContainerStrategyGridParent(metadata, elementPaths, axis), fillContainerStrategyFlexParent(metadata, elementPaths, axis, value), fillContainerStrategyFlow(metadata, elementPaths, axis, value, otherAxisSetToFill), ] diff --git a/editor/src/components/inspector/resize-to-fit-control.tsx b/editor/src/components/inspector/resize-to-fit-control.tsx index 7e5598f4aa9a..84f8d46a3e0c 100644 --- a/editor/src/components/inspector/resize-to-fit-control.tsx +++ b/editor/src/components/inspector/resize-to-fit-control.tsx @@ -40,6 +40,7 @@ function checkGroupSuitability( // Do not let a group be the target of a resize to fit operation. return !treatElementAsGroupLike(metadata, target) case 'fill': + case 'stretch': // Neither a group or the child of a group should be eligible for a resize to fill operation. return !( treatElementAsGroupLike(metadata, target) || treatElementAsGroupLike(metadata, parentPath) From f7d6be2c720856475a657d49f4391fa0fb690c31 Mon Sep 17 00:00:00 2001 From: Balazs Bajorics <2226774+balazsbajorics@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:28:21 +0200 Subject: [PATCH 059/272] LocalSelectedViews 2: Electric Boogaloo (#6411) **Problem:** Selection change can be upwards of 100ms, in a large enough project it may reach half a second. This is because almost all parts of the Editor UI use EditorState.selectedViews as a main part of their state, which means changing the selected elements triggers a re-render of all of the editor. For historical reasons, we also use this as an opportunity to re-render and re-measure the canvas, correcting all metadata that may be stale because of partial updates during interactions. **Fix:** The idea is that instead of speeding up the actual rerender, we make the selection outline change first in a fast frame, then run the expensive editor UI update in the next frame. Turns out that _perceptually_ this is the desired behavior: the user looks at where the mouse is, they see a very responsive UI change, and after having clicked with the mouse, we have a 200-300ms deadzone of user perception before that can click or move the mouse again. We fill that space with the expensive state update, by the time the user moves their mouse or clicks again, the editor is ready again to handle events responsively. **Commit details** - Adding `temporarilyDisableStoreUpdates` to `editor.tsx` - Adding 'canvas-fast-selection-hack' and 'resume-canvas-fast-selection-hack' to the dispatch function's "priority" parameter, which toggles `temporarilyDisableStoreUpdates` to true or false. - `mouseHandler` in `select-mode-hooks.tsx` dispatches 'canvas-fast-selection-hack' and then TWO animatonFrames later, a 'resume-canvas-fast-selection-hack'. - Some selectors and hooks, most notably `useGetApplicableStrategyControls` get a separate selectedViews field, instead of using EditorState.selectedViews (which may be stale). This selectedViews parameter is fed from localSelectedViews which is updated sooner than the zustand editor store is. this is what enables the canvas controls to draw the changed controls immediately while the rest of the editor UI is temporarily one frame behind. **Notes:** - The tests DO NOT use the `temporarilyDisableStoreUpdates` system, because the test's fake mouse helper events we dispatch are all fired in a single animation frame (unlike Chrome's real mouse events). Changing all this felt like too invasive for little benefit. - IF we find event listeners that fire out of order or with stale state, we can create a fourth Zustand store, and delete the canvas controls localSelectedViews / localHighlightedViews. this fourth zustand store would be immediately updated, and select important parts of the UI could subscribe to it to get instant updates of the selection change. --- .../canvas-strategies.spec.browser2.tsx | 4 ++ .../canvas-strategies/canvas-strategies.tsx | 42 ++++++++++++------- .../absolute-duplicate-strategy.spec.tsx | 1 + ...absolute-reparent-strategy-canvas.spec.tsx | 1 + .../absolute-reparent-strategy.spec.tsx | 1 + ...lute-resize-bounding-box-strategy.spec.tsx | 1 + ...ert-to-absolute-and-move-strategy.spec.tsx | 1 + .../drag-to-insert-metastrategy.tsx | 1 + .../draw-to-insert-metastrategy.tsx | 7 +++- .../flex-reparent-to-absolute-strategy.tsx | 1 + .../keyboard-interaction.test-utils.tsx | 1 + .../canvas/controls/new-canvas-controls.tsx | 15 +++---- .../select-mode/select-mode-hooks.tsx | 27 ++++++++++-- editor/src/components/editor/action-types.ts | 3 ++ .../src/components/editor/actions/actions.tsx | 6 ++- .../editor/store/dispatch-strategies.tsx | 7 ++++ editor/src/templates/editor.tsx | 22 ++++++++-- editor/src/utils/feature-switches.ts | 3 ++ 18 files changed, 113 insertions(+), 31 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/canvas-strategies.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/canvas-strategies.spec.browser2.tsx index 3239dcd9cee1..c3dad1aac9a2 100644 --- a/editor/src/components/canvas/canvas-strategies/canvas-strategies.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/canvas-strategies.spec.browser2.tsx @@ -176,6 +176,7 @@ describe('Strategy Fitness', () => { const canvasStrategy = findCanvasStrategy( RegisteredCanvasStrategies, pickCanvasStateFromEditorState( + renderResult.getEditorState().editor.selectedViews, renderResult.getEditorState().editor, renderResult.getEditorState().builtInDependencies, ), @@ -226,6 +227,7 @@ describe('Strategy Fitness', () => { const canvasStrategy = findCanvasStrategy( RegisteredCanvasStrategies, pickCanvasStateFromEditorState( + renderResult.getEditorState().editor.selectedViews, renderResult.getEditorState().editor, renderResult.getEditorState().builtInDependencies, ), @@ -313,6 +315,7 @@ describe('Strategy Fitness', () => { const canvasStrategy = findCanvasStrategy( RegisteredCanvasStrategies, pickCanvasStateFromEditorState( + renderResult.getEditorState().editor.selectedViews, renderResult.getEditorState().editor, renderResult.getEditorState().builtInDependencies, ), @@ -363,6 +366,7 @@ describe('Strategy Fitness', () => { const canvasStrategy = findCanvasStrategy( RegisteredCanvasStrategies, pickCanvasStateFromEditorState( + renderResult.getEditorState().editor.selectedViews, renderResult.getEditorState().editor, renderResult.getEditorState().builtInDependencies, ), diff --git a/editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx b/editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx index a43af7b2c7dc..29d4ae683ffc 100644 --- a/editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx +++ b/editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx @@ -81,6 +81,7 @@ import type { ElementPath } from 'utopia-shared/src/types' import { reparentSubjectsForInteractionTarget } from './strategies/reparent-helpers/reparent-strategy-helpers' import { getReparentTargetUnified } from './strategies/reparent-helpers/reparent-strategy-parent-lookup' import { gridRearrangeResizeKeyboardStrategy } from './strategies/grid-rearrange-keyboard-strategy' +import createCachedSelector from 're-reselect' export type CanvasStrategyFactory = ( canvasState: InteractionCanvasState, @@ -197,12 +198,13 @@ export const RegisteredCanvasStrategies: Array = [ ] export function pickCanvasStateFromEditorState( + localSelectedViews: Array, editorState: EditorState, builtInDependencies: BuiltInDependencies, ): InteractionCanvasState { return { builtInDependencies: builtInDependencies, - interactionTarget: getInteractionTargetFromEditorState(editorState), + interactionTarget: getInteractionTargetFromEditorState(editorState, localSelectedViews), projectContents: editorState.projectContents, nodeModules: editorState.nodeModules.files, openFile: editorState.canvas.openFile?.filename, @@ -216,6 +218,7 @@ export function pickCanvasStateFromEditorState( } export function pickCanvasStateFromEditorStateWithMetadata( + localSelectedViews: Array, editorState: EditorState, builtInDependencies: BuiltInDependencies, metadata: ElementInstanceMetadataMap, @@ -223,7 +226,7 @@ export function pickCanvasStateFromEditorStateWithMetadata( ): InteractionCanvasState { return { builtInDependencies: builtInDependencies, - interactionTarget: getInteractionTargetFromEditorState(editorState), + interactionTarget: getInteractionTargetFromEditorState(editorState, localSelectedViews), projectContents: editorState.projectContents, nodeModules: editorState.nodeModules.files, openFile: editorState.canvas.openFile?.filename, @@ -236,7 +239,10 @@ export function pickCanvasStateFromEditorStateWithMetadata( } } -function getInteractionTargetFromEditorState(editor: EditorState): InteractionTarget { +function getInteractionTargetFromEditorState( + editor: EditorState, + localSelectedViews: Array, +): InteractionTarget { switch (editor.mode.type) { case 'insert': return insertionSubjects(editor.mode.subjects) @@ -245,7 +251,7 @@ function getInteractionTargetFromEditorState(editor: EditorState): InteractionTa case 'textEdit': case 'comment': case 'follow': - return targetPaths(editor.selectedViews) + return targetPaths(localSelectedViews) default: assertNever(editor.mode) } @@ -288,17 +294,21 @@ export function getApplicableStrategies( return strategies.flatMap((s) => s(canvasState, interactionSession, customStrategyState)) } -const getApplicableStrategiesSelector = createSelector( - (store: EditorStorePatched) => +const getApplicableStrategiesSelector = createCachedSelector( + (store: EditorStorePatched, _) => optionalMap( (sas) => sas.map((s) => s.strategy), store.strategyState.sortedApplicableStrategies, ), - (store: EditorStorePatched): InteractionCanvasState => { - return pickCanvasStateFromEditorState(store.editor, store.builtInDependencies) + (store: EditorStorePatched, localSelectedViews: Array): InteractionCanvasState => { + return pickCanvasStateFromEditorState( + localSelectedViews, + store.editor, + store.builtInDependencies, + ) }, - (store: EditorStorePatched) => store.editor.canvas.interactionSession, - (store: EditorStorePatched) => store.strategyState.customStrategyState, + (store: EditorStorePatched, _) => store.editor.canvas.interactionSession, + (store: EditorStorePatched, _) => store.strategyState.customStrategyState, ( applicableStrategiesFromStrategyState: Array | null, canvasState: InteractionCanvasState, @@ -316,12 +326,12 @@ const getApplicableStrategiesSelector = createSelector( ) } }, -) +)((_, localSelectedViews: Array) => localSelectedViews.map(EP.toString).join(',')) -function useGetApplicableStrategies(): Array { +function useGetApplicableStrategies(localSelectedViews: Array): Array { return useEditorState( Substores.fullStore, - getApplicableStrategiesSelector, + (store) => getApplicableStrategiesSelector(store, localSelectedViews), 'useGetApplicableStrategies', arrayEqualsByReference, ) @@ -624,8 +634,10 @@ function controlPriorityToNumber(prio: ControlWithProps['priority']): numbe } } -export function useGetApplicableStrategyControls(): Array> { - const applicableStrategies = useGetApplicableStrategies() +export function useGetApplicableStrategyControls( + localSelectedViews: Array, +): Array> { + const applicableStrategies = useGetApplicableStrategies(localSelectedViews) const currentStrategy = useDelayedCurrentStrategy() const currentlyInProgress = useEditorState( Substores.canvas, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-duplicate-strategy.spec.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-duplicate-strategy.spec.tsx index 39f4ab07acaa..8db594de244a 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-duplicate-strategy.spec.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-duplicate-strategy.spec.tsx @@ -74,6 +74,7 @@ function dragByPixelsIsApplicable( return ( absoluteDuplicateStrategy( pickCanvasStateFromEditorStateWithMetadata( + editorState.selectedViews, editorState, createBuiltInDependenciesList(null), metadata, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy-canvas.spec.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy-canvas.spec.tsx index 5031daf5b2b3..e7c5460c10c9 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy-canvas.spec.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy-canvas.spec.tsx @@ -133,6 +133,7 @@ function reparentElement( } const canvasState = pickCanvasStateFromEditorStateWithMetadata( + editorState.selectedViews, editorState, createBuiltInDependenciesList(null), startingMetadata, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.spec.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.spec.tsx index 77328c3d5894..b1832b2f795b 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.spec.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-reparent-strategy.spec.tsx @@ -202,6 +202,7 @@ function reparentElement( } const canvasState = pickCanvasStateFromEditorStateWithMetadata( + editorState.selectedViews, editorState, createBuiltInDependenciesList(null), startingMetadata, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.spec.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.spec.tsx index dc38cee0ac73..c159ff9fa5c5 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.spec.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.spec.tsx @@ -52,6 +52,7 @@ function multiselectResizeElements( const strategyResult = absoluteResizeBoundingBoxStrategy( pickCanvasStateFromEditorStateWithMetadata( + initialEditor.selectedViews, initialEditor, createBuiltInDependenciesList(null), metadata, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.spec.tsx b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.spec.tsx index 4fac80bc13c9..1d5682e256bd 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.spec.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.spec.tsx @@ -175,6 +175,7 @@ function dragByPixels( const strategyResultCommands = convertToAbsoluteAndMoveStrategy( pickCanvasStateFromEditorStateWithMetadata( + editorState.selectedViews, editorState, createBuiltInDependenciesList(null), metadata, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/drag-to-insert-metastrategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/drag-to-insert-metastrategy.tsx index 2804f0f5302d..031162699ef6 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/drag-to-insert-metastrategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/drag-to-insert-metastrategy.tsx @@ -394,6 +394,7 @@ function runTargetStrategiesForFreshlyInsertedElement( // because that element is inserted to the storyboard before reparenting to the correct location, // so its index amongst its starting siblings isn't relevant. const canvasState = pickCanvasStateFromEditorStateWithMetadata( + editorState.selectedViews, editorState, builtInDependencies, patchedMetadata, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-metastrategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-metastrategy.tsx index 907b6178eed7..0da5cf8ca11a 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-metastrategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/draw-to-insert-metastrategy.tsx @@ -590,7 +590,11 @@ function runTargetStrategiesForFreshlyInsertedElementToReparent( strategyLifecycle: InteractionLifecycle, startingMetadata: ElementInstanceMetadataMap, ): Array { - const canvasState = pickCanvasStateFromEditorState(editorState, builtInDependencies) + const canvasState = pickCanvasStateFromEditorState( + editorState.selectedViews, + editorState, + builtInDependencies, + ) const rootPath = getRootPath(startingMetadata) if (rootPath == null) { @@ -679,6 +683,7 @@ function runTargetStrategiesForFreshlyInsertedElementToResize( // when actually applying the strategies. If we ever need to pick a resize strategy based on the target // element's index, we will need to update the elementPathTree with the new element and pass it in here. const canvasState = pickCanvasStateFromEditorStateWithMetadata( + editorState.selectedViews, editorState, builtInDependencies, patchedMetadata, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx index 39d6fe1b8255..e94bdc502612 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/flex-reparent-to-absolute-strategy.tsx @@ -109,6 +109,7 @@ export function baseFlexReparentToAbsoluteStrategy( 'always', (editorState, commandLifecycle): Array => { const updatedCanvasState = pickCanvasStateFromEditorState( + editorState.selectedViews, editorState, canvasState.builtInDependencies, ) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-interaction.test-utils.tsx b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-interaction.test-utils.tsx index 70478e0390d7..457a84ac9304 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-interaction.test-utils.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-interaction.test-utils.tsx @@ -80,6 +80,7 @@ export function pressKeys( const strategy = strategyFactoryFunction( pickCanvasStateFromEditorStateWithMetadata( + editorState.selectedViews, editorState, createBuiltInDependenciesList(null), metadata, diff --git a/editor/src/components/canvas/controls/new-canvas-controls.tsx b/editor/src/components/canvas/controls/new-canvas-controls.tsx index b6cead1192f7..be85b3261131 100644 --- a/editor/src/components/canvas/controls/new-canvas-controls.tsx +++ b/editor/src/components/canvas/controls/new-canvas-controls.tsx @@ -274,9 +274,16 @@ interface NewCanvasControlsInnerProps { } const NewCanvasControlsInner = (props: NewCanvasControlsInnerProps) => { + const { + localSelectedViews, + localHighlightedViews, + setLocalSelectedViews, + setLocalHighlightedViews, + } = props + const dispatch = useDispatch() const colorTheme = useColorTheme() - const strategyControls = useGetApplicableStrategyControls() + const strategyControls = useGetApplicableStrategyControls(localSelectedViews) const [inspectorHoveredControls] = useAtom(InspectorHoveredCanvasControls) const [inspectorFocusedControls] = useAtom(InspectorFocusedCanvasControls) @@ -331,12 +338,6 @@ const NewCanvasControlsInner = (props: NewCanvasControlsInnerProps) => { 'NewCanvasControlsInner', ) - const { - localSelectedViews, - localHighlightedViews, - setLocalSelectedViews, - setLocalHighlightedViews, - } = props const cmdKeyPressed = keysPressed['cmd'] ?? false const contextMenuEnabled = !isLiveMode(editorMode) diff --git a/editor/src/components/canvas/controls/select-mode/select-mode-hooks.tsx b/editor/src/components/canvas/controls/select-mode/select-mode-hooks.tsx index 32852623061f..83047c82baf1 100644 --- a/editor/src/components/canvas/controls/select-mode/select-mode-hooks.tsx +++ b/editor/src/components/canvas/controls/select-mode/select-mode-hooks.tsx @@ -1,4 +1,5 @@ import React from 'react' +import ReactDOM from 'react-dom' import { MetadataUtils } from '../../../../core/model/element-metadata-utils' import { uniqBy } from '../../../../core/shared/array-utils' import type { ElementInstanceMetadataMap } from '../../../../core/shared/element-template' @@ -17,6 +18,7 @@ import { selectComponents, setHoveredView, clearHoveredViews, + runDOMWalker, } from '../../../editor/actions/action-creators' import { cancelInsertModeActions } from '../../../editor/actions/meta-actions' import { @@ -58,6 +60,9 @@ import { getAllLockedElementPaths } from '../../../../core/shared/element-lockin import { treatElementAsGroupLike } from '../../canvas-strategies/strategies/group-helpers' import { useCommentModeSelectAndHover } from '../comment-mode/comment-mode-hooks' import { useFollowModeSelectAndHover } from '../follow-mode/follow-mode-hooks' +import { wait } from '../../../../core/model/performance-scripts' +import { IS_TEST_ENVIRONMENT } from '../../../../common/env-vars' +import { isFeatureEnabled } from '../../../../utils/feature-switches' export function isDragInteractionActive(editorState: EditorState): boolean { return editorState.canvas.interactionSession?.interactionData.type === 'DRAG' @@ -640,7 +645,7 @@ function useSelectOrLiveModeSelectAndHover( [innerOnMouseMove, editorStoreRef], ) const mouseHandler = React.useCallback( - (event: React.MouseEvent) => { + async (event: React.MouseEvent) => { const isLeftClick = event.button === 0 const isRightClick = event.type === 'contextmenu' && event.detail === 0 const isCanvasPanIntention = @@ -773,8 +778,10 @@ function useSelectOrLiveModeSelectAndHover( } if (!foundTargetIsSelected) { - // first we only set the selected views for the canvas controls - setSelectedViewsForCanvasControlsOnly(updatedSelection) + // first we only set the selected views for the canvas controls. however this will be clumped together with the dispatch, unless we wait asynchronously before we dispatch + ReactDOM.flushSync(() => { + setSelectedViewsForCanvasControlsOnly(updatedSelection) + }) // In either case cancel insert mode. if (isInsertMode(editorStoreRef.current.editor.mode)) { @@ -789,7 +796,19 @@ function useSelectOrLiveModeSelectAndHover( } } } - dispatch(editorActions) + + if (event.detail === 1 && isFeatureEnabled('Canvas Fast Selection Hack')) { + // If event.detail is 1 that means this is a first click, where it is safe to delay dispatching actions + // to allow the localSelectedViews to be updated. + // For subsequent clicks, we want to dispatch immediately to avoid out of sync event handlers queueing up + + dispatch(editorActions, 'canvas-fast-selection-hack') // first we dispatch only to update the editor state, but not run the expensive parts + await new Promise((resolve) => requestAnimationFrame(resolve)) // the first requestAnimationFrame fires in the same animation frame we are in, so we need to wait one more + await new Promise((resolve) => requestAnimationFrame(resolve)) // the second requestAnimationFrame is fired in the next actual animation frame, at which point it is safe to run the expensive parts + dispatch([runDOMWalker()], 'resume-canvas-fast-selection-hack') // then we dispatch to run the expensive parts + } else { + dispatch(editorActions) + } }, [ dispatch, diff --git a/editor/src/components/editor/action-types.ts b/editor/src/components/editor/action-types.ts index 9ad3c9a4ac96..94190c524369 100644 --- a/editor/src/components/editor/action-types.ts +++ b/editor/src/components/editor/action-types.ts @@ -1446,6 +1446,9 @@ export type DispatchPriority = | 'topmenu' | 'contextmenu' | 'noone' + | 'canvas-fast-selection-hack' + | 'resume-canvas-fast-selection-hack' + export type EditorDispatch = ( actions: ReadonlyArray, priority?: DispatchPriority, diff --git a/editor/src/components/editor/actions/actions.tsx b/editor/src/components/editor/actions/actions.tsx index 4b02829f691a..dc5a7ed77b80 100644 --- a/editor/src/components/editor/actions/actions.tsx +++ b/editor/src/components/editor/actions/actions.tsx @@ -5767,7 +5767,11 @@ export const UPDATE_FNS = { editor: EditorModel, builtInDependencies: BuiltInDependencies, ): EditorModel => { - const canvasState = pickCanvasStateFromEditorState(editor, builtInDependencies) + const canvasState = pickCanvasStateFromEditorState( + editor.selectedViews, + editor, + builtInDependencies, + ) if (areAllSelectedElementsNonAbsolute(action.targets, editor.jsxMetadata)) { const commands = getEscapeHatchCommands( action.targets, diff --git a/editor/src/components/editor/store/dispatch-strategies.tsx b/editor/src/components/editor/store/dispatch-strategies.tsx index 7801ff49e943..0d902f940f66 100644 --- a/editor/src/components/editor/store/dispatch-strategies.tsx +++ b/editor/src/components/editor/store/dispatch-strategies.tsx @@ -79,6 +79,7 @@ export function interactionFinished( newEditorState.elementPathTree, ) const canvasState: InteractionCanvasState = pickCanvasStateFromEditorState( + newEditorState.selectedViews, newEditorState, result.builtInDependencies, ) @@ -156,6 +157,7 @@ export function interactionHardReset( startingMetadata: storedState.unpatchedEditor.jsxMetadata, } const canvasState: InteractionCanvasState = pickCanvasStateFromEditorState( + newEditorState.selectedViews, newEditorState, result.builtInDependencies, ) @@ -244,6 +246,7 @@ export function interactionUpdate( ): HandleStrategiesResult { const newEditorState = result.unpatchedEditor const canvasState: InteractionCanvasState = pickCanvasStateFromEditorState( + newEditorState.selectedViews, newEditorState, result.builtInDependencies, ) @@ -326,6 +329,7 @@ export function interactionStart( newEditorState.elementPathTree, ) const canvasState: InteractionCanvasState = pickCanvasStateFromEditorState( + newEditorState.selectedViews, newEditorState, result.builtInDependencies, ) @@ -437,6 +441,7 @@ function handleUserChangedStrategy( sortedApplicableStrategies: Array, ): HandleStrategiesResult { const canvasState: InteractionCanvasState = pickCanvasStateFromEditorState( + newEditorState.selectedViews, newEditorState, builtInDependencies, ) @@ -517,6 +522,7 @@ function handleAccumulatingKeypresses( sortedApplicableStrategies: Array, ): HandleStrategiesResult { const canvasState: InteractionCanvasState = pickCanvasStateFromEditorState( + newEditorState.selectedViews, newEditorState, builtInDependencies, ) @@ -602,6 +608,7 @@ function handleUpdate( sortedApplicableStrategies: Array, ): HandleStrategiesResult { const canvasState: InteractionCanvasState = pickCanvasStateFromEditorState( + newEditorState.selectedViews, newEditorState, builtInDependencies, ) diff --git a/editor/src/templates/editor.tsx b/editor/src/templates/editor.tsx index da7f5d0b2c6c..0d2aa892c21d 100644 --- a/editor/src/templates/editor.tsx +++ b/editor/src/templates/editor.tsx @@ -424,12 +424,24 @@ export class Editor { ) } + // This is used to temporarily disable updates to the store, for example when we are in the middle of a fast selection hack + temporarilyDisableStoreUpdates = false + boundDispatch = ( dispatchedActions: readonly EditorAction[], priority?: DispatchPriority, ): { entireUpdateFinished: Promise } => { + if ( + priority === 'canvas-fast-selection-hack' && + isFeatureEnabled('Canvas Fast Selection Hack') + ) { + this.temporarilyDisableStoreUpdates = true + } else if (priority === 'resume-canvas-fast-selection-hack') { + this.temporarilyDisableStoreUpdates = false + } + resetDomSamplerExecutionCounts() const Measure = createPerformanceMeasure() Measure.logActions(dispatchedActions) @@ -463,7 +475,8 @@ export class Editor { const shouldUpdateCanvasStore = !dispatchResult.nothingChanged && - !anyCodeAhead(dispatchResult.unpatchedEditor.projectContents) + !anyCodeAhead(dispatchResult.unpatchedEditor.projectContents) && + !this.temporarilyDisableStoreUpdates const updateId = canvasUpdateId++ if (shouldUpdateCanvasStore) { @@ -482,7 +495,9 @@ export class Editor { }) } - const runDomWalker = shouldRunDOMWalker(dispatchedActions, oldEditorState, this.storedState) + const runDomWalker = + shouldRunDOMWalker(dispatchedActions, oldEditorState, this.storedState) && + !this.temporarilyDisableStoreUpdates // run the dom-walker if (runDomWalker) { @@ -603,7 +618,8 @@ export class Editor { shouldUpdateLowPriorityUI( this.storedState.strategyState, ElementsToRerenderGLOBAL.current, - ) + ) && + !this.temporarilyDisableStoreUpdates ) { Measure.taskTime(`Update Low Prio Store ${updateId}`, () => { this.lowPriorityStore.setState( diff --git a/editor/src/utils/feature-switches.ts b/editor/src/utils/feature-switches.ts index 4d48a1772df5..cce2962ef6c7 100644 --- a/editor/src/utils/feature-switches.ts +++ b/editor/src/utils/feature-switches.ts @@ -15,6 +15,7 @@ export type FeatureName = | 'Debug - Print UIDs' | 'Debug – Connections' | 'Condensed Navigator Entries' + | 'Canvas Fast Selection Hack' | 'Roll Your Own' export const AllFeatureNames: FeatureName[] = [ @@ -31,6 +32,7 @@ export const AllFeatureNames: FeatureName[] = [ 'Debug - Print UIDs', 'Debug – Connections', 'Condensed Navigator Entries', + 'Canvas Fast Selection Hack', 'Roll Your Own', ] @@ -47,6 +49,7 @@ let FeatureSwitches: { [feature in FeatureName]: boolean } = { 'Debug - Print UIDs': false, 'Debug – Connections': false, 'Condensed Navigator Entries': !IS_TEST_ENVIRONMENT, + 'Canvas Fast Selection Hack': true, 'Roll Your Own': false, } From 9ba600dc61179f927dba58a5c9a2a1b9c2ba10df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20K=C3=B6rmendy?= Date: Mon, 30 Sep 2024 17:13:48 +0200 Subject: [PATCH 060/272] Tailwind class compilation (#6401) image ## [Example project](https://utopia.fish/p/5c03b0e5-glorious-coconut/?branch_name=feature-tailwind-class-compilation&Tailwind=true) ## Description This PR removes twind (as it's not maintained anymore), and replaces it with https://github.com/mhsdesign/jit-browser-tailwindcss/, which builds on tailwindcss to compile tailwind classes. ### Details - The code wrapping `twind` is removed - Wrapper code is added for https://github.com/mhsdesign/jit-browser-tailwindcss/ (`useTailwindCompilation`) - A Karma test is added to check whether some tailwind classes are compiled correctly (`tailwind.spec.browser2.tsx`). The test is intentionally coarse-grained, because exhaustively testing every tailwind feature is out of scope, and the example store heavily uses tailwind anyway - Generating the tailwind styles depends on whether the project has a tailwind.config.js file or not. Down the line we'll change this to checking in a flag in the `"utopia"` section of `package.json`, the current implementation is there to keep the PR self-contained - `isTailwindEnabled` and `TAILWIND_INSTANCE.current`: `isTailwindEnabled` should be a pure function of `projectContents`. However, that implementation caused a lot of re-renders, so instead I mirrored the original implementation that checked whether a module-private variable was set or not - Stubbed `@mhsdesign/jit-browser-tailwindcss` in Jest --- editor/jest.config.js | 2 + editor/package.json | 4 +- editor/pnpm-lock.yaml | 357 +++++++++++++----- .../src/components/canvas/ui-jsx-canvas.tsx | 4 +- editor/src/components/inspector/inspector.tsx | 5 +- .../src/core/tailwind/tailwind-compilation.ts | 106 ++++++ editor/src/core/tailwind/tailwind-options.tsx | 4 +- .../core/tailwind/tailwind.spec.browser2.tsx | 218 +++++++++++ editor/src/core/tailwind/tailwind.spec.ts | 55 --- editor/src/core/tailwind/tailwind.ts | 291 -------------- editor/src/templates/preview/preview.tsx | 3 - .../__mocks__/jit-browser-tailwindcss.js | 5 + editor/src/utils/feature-switches.ts | 3 + 13 files changed, 602 insertions(+), 455 deletions(-) create mode 100644 editor/src/core/tailwind/tailwind-compilation.ts create mode 100644 editor/src/core/tailwind/tailwind.spec.browser2.tsx delete mode 100644 editor/src/core/tailwind/tailwind.spec.ts delete mode 100644 editor/src/core/tailwind/tailwind.ts create mode 100644 editor/src/utils/__mocks__/jit-browser-tailwindcss.js diff --git a/editor/jest.config.js b/editor/jest.config.js index bc651b6d6b29..0a99d49a3e88 100644 --- a/editor/jest.config.js +++ b/editor/jest.config.js @@ -112,6 +112,8 @@ module.exports = { 'react-dnd-html5-backend': '/test/jest/__mocks__/react-dnd-html5-backend.js', '^react$': '/node_modules/react/index.js', '^react-dom$': '/node_modules/react-dom/index.js', + '^@mhsdesign/jit-browser-tailwindcss$': + '/src/utils/__mocks__/jit-browser-tailwindcss.js', '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/test/jest/__mocks__/styleMock.js', }, diff --git a/editor/package.json b/editor/package.json index 91b7e6b6f694..9da259561b23 100644 --- a/editor/package.json +++ b/editor/package.json @@ -152,6 +152,7 @@ "@liveblocks/react": "1.10.0", "@liveblocks/react-comments": "1.10.0", "@liveblocks/yjs": "1.10.0", + "@mhsdesign/jit-browser-tailwindcss": "0.4.1", "@popperjs/core": "2.4.4", "@radix-ui/react-dropdown-menu": "2.1.1", "@radix-ui/react-select": "2.1.1", @@ -164,9 +165,6 @@ "@svgr/plugin-jsx": "5.5.0", "@testing-library/user-event": "14.5.2", "@tippyjs/react": "4.1.0", - "@twind/core": "1.1.3", - "@twind/preset-autoprefix": "1.0.7", - "@twind/preset-tailwind": "1.1.4", "@types/fontfaceobserver": "0.0.6", "@types/lodash.findlastindex": "4.6.7", "@types/react-syntax-highlighter": "11.0.4", diff --git a/editor/pnpm-lock.yaml b/editor/pnpm-lock.yaml index a624524d7631..9c062e509ccd 100644 --- a/editor/pnpm-lock.yaml +++ b/editor/pnpm-lock.yaml @@ -65,6 +65,7 @@ specifiers: '@liveblocks/react': 1.10.0 '@liveblocks/react-comments': 1.10.0 '@liveblocks/yjs': 1.10.0 + '@mhsdesign/jit-browser-tailwindcss': 0.4.1 '@originjs/vite-plugin-commonjs': 1.0.3 '@peculiar/webcrypto': 1.4.3 '@popperjs/core': 2.4.4 @@ -84,9 +85,6 @@ specifiers: '@testing-library/react': 14.0.0 '@testing-library/user-event': 14.5.2 '@tippyjs/react': 4.1.0 - '@twind/core': 1.1.3 - '@twind/preset-autoprefix': 1.0.7 - '@twind/preset-tailwind': 1.1.4 '@types/babel__traverse': 7.18.3 '@types/chai': 3.5.1 '@types/chroma-js': 2.0.0 @@ -370,6 +368,7 @@ dependencies: '@liveblocks/react': 1.10.0_react@18.1.0 '@liveblocks/react-comments': 1.10.0_wgqxz3kjpz4ixw4iz4mbg2tk4i '@liveblocks/yjs': 1.10.0_yjs@13.6.8 + '@mhsdesign/jit-browser-tailwindcss': 0.4.1 '@popperjs/core': 2.4.4 '@radix-ui/react-dropdown-menu': 2.1.1_wgqxz3kjpz4ixw4iz4mbg2tk4i '@radix-ui/react-select': 2.1.1_wgqxz3kjpz4ixw4iz4mbg2tk4i @@ -382,9 +381,6 @@ dependencies: '@svgr/plugin-jsx': 5.5.0 '@testing-library/user-event': 14.5.2 '@tippyjs/react': 4.1.0_ef5jwxihqo6n7gxfmzogljlgcm - '@twind/core': 1.1.3_typescript@5.5.4 - '@twind/preset-autoprefix': 1.0.7_gmrgfak3invo7trrvnu65or3fu - '@twind/preset-tailwind': 1.1.4_gmrgfak3invo7trrvnu65or3fu '@types/fontfaceobserver': 0.0.6 '@types/lodash.findlastindex': 4.6.7 '@types/react-syntax-highlighter': 11.0.4 @@ -670,6 +666,11 @@ packages: resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} engines: {node: '>=0.10.0'} + /@alloc/quick-lru/5.2.0: + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + dev: false + /@alloc/types/1.3.0: resolution: {integrity: sha512-mH7LiFiq9g6rX2tvt1LtwsclfG5hnsmtIfkZiauAGrm1AwXhoRS0sF2WrN9JGN7eV5vFXqNaB0eXZ3IvMsVi9g==} dev: false @@ -2716,7 +2717,6 @@ packages: strip-ansi-cjs: /strip-ansi/6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: /wrap-ansi/7.0.0 - dev: true /@istanbuljs/load-nyc-config/1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} @@ -3166,6 +3166,23 @@ packages: react: 18.1.0_47cciibm4ysmleigs33s763fqu dev: false + /@mhsdesign/jit-browser-tailwindcss/0.4.1: + resolution: {integrity: sha512-n08EkCXPP6XADdXtZ+zLRyF5qkEsoC37FrC7pAceREQRCT+SB9oI7qXMS2hNPwTXdBwUdR3d2TSk9R7imMyMRQ==} + dependencies: + color-name: 1.1.4 + didyoumean: 1.2.2 + dlv: 1.1.3 + postcss: 8.4.27 + postcss-js: 4.0.1_postcss@8.4.27 + postcss-nested: 5.0.6_postcss@8.4.27 + postcss-selector-parser: 6.1.2 + postcss-value-parser: 4.2.0 + quick-lru: 5.1.1 + tailwindcss: 3.4.13 + transitivePeerDependencies: + - ts-node + dev: false + /@nicolo-ribaudo/chokidar-2/2.1.8-no-fsevents.3: resolution: {integrity: sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==} requiresBuild: true @@ -3226,7 +3243,6 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} requiresBuild: true - dev: true optional: true /@polka/url/1.0.0-next.20: @@ -4918,48 +4934,6 @@ packages: resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} dev: false - /@twind/core/1.1.3_typescript@5.5.4: - resolution: {integrity: sha512-/B/aNFerMb2IeyjSJy3SJxqVxhrT77gBDknLMiZqXIRr4vNJqiuhx7KqUSRzDCwUmyGuogkamz+aOLzN6MeSLw==} - engines: {node: '>=14.15.0'} - peerDependencies: - typescript: ^4.8.4 - peerDependenciesMeta: - typescript: - optional: true - dependencies: - csstype: 3.1.2 - typescript: 5.5.4 - dev: false - - /@twind/preset-autoprefix/1.0.7_gmrgfak3invo7trrvnu65or3fu: - resolution: {integrity: sha512-3wmHO0pG/CVxYBNZUV0tWcL7CP0wD5KpyWAQE/KOalWmOVBj+nH6j3v6Y3I3pRuMFaG5DC78qbYbhA1O11uG3w==} - engines: {node: '>=14.15.0'} - peerDependencies: - '@twind/core': ^1.1.0 - typescript: ^4.8.4 - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@twind/core': 1.1.3_typescript@5.5.4 - style-vendorizer: 2.2.3 - typescript: 5.5.4 - dev: false - - /@twind/preset-tailwind/1.1.4_gmrgfak3invo7trrvnu65or3fu: - resolution: {integrity: sha512-zv85wrP/DW4AxgWrLfH7kyGn/KJF3K04FMLVl2AjoxZGYdCaoZDkL8ma3hzaKQ+WGgBFRubuB/Ku2Rtv/wjzVw==} - engines: {node: '>=14.15.0'} - peerDependencies: - '@twind/core': ^1.1.0 - typescript: ^4.8.4 - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@twind/core': 1.1.3_typescript@5.5.4 - typescript: 5.5.4 - dev: false - /@types/aria-query/5.0.1: resolution: {integrity: sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==} dev: true @@ -6342,7 +6316,6 @@ packages: /ansi-regex/6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: true /ansi-styles/1.1.0: resolution: {integrity: sha512-f2PKUkN5QngiSemowa6Mrk9MPCdtFiOSmibjZ+j1qhLGHHYsqZwmBMRF3IRMVXo8sybDqx2fJl2d/8OphBoWkA==} @@ -6374,7 +6347,6 @@ packages: /ansi-styles/6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - dev: true /antd/4.3.5_ef5jwxihqo6n7gxfmzogljlgcm: resolution: {integrity: sha512-C1qILCKh+G7q06wtm4uqmyvqzAzAaDKKzuTO0BO+rtUbSATjzbUg2Bp5byDEw0ThUGTWfJEQ0J7HZHh0FgiaJA==} @@ -6445,8 +6417,7 @@ packages: dev: true /any-promise/1.3.0: - resolution: {integrity: sha1-q8av7tzqUugJzcA3au0845Y10X8=} - dev: true + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} /anymatch/3.1.2: resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} @@ -6454,7 +6425,10 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true + + /arg/5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: false /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -7047,7 +7021,6 @@ packages: /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - dev: true /binaryextensions/4.18.0: resolution: {integrity: sha512-PQu3Kyv9dM4FnwB7XGj1+HucW+ShvJzJqjuw1JkKVs1mWdwOKVcRjOi+pV9X52A0tNvrPCsPkbFFQb+wE1EAXw==} @@ -7137,7 +7110,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: true /braces/2.3.2: resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} @@ -7484,6 +7456,11 @@ packages: tslib: 2.6.2 dev: true + /camelcase-css/2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + dev: false + /camelcase/5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -7662,7 +7639,6 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true /chownr/2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} @@ -7973,7 +7949,6 @@ packages: /commander/4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - dev: true /commander/6.2.1: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} @@ -8402,7 +8377,6 @@ packages: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true - dev: true /cssnano/3.10.0: resolution: {integrity: sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=} @@ -8855,6 +8829,10 @@ packages: resolution: {integrity: sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==} dev: true + /didyoumean/1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: false + /diff-match-patch/1.0.5: resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} dev: false @@ -8907,6 +8885,10 @@ packages: resolution: {integrity: sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=} dev: true + /dlv/1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dev: false + /dnd-core/16.0.1: resolution: {integrity: sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==} dependencies: @@ -9081,7 +9063,6 @@ packages: /eastasianwidth/0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true /editions/4.2.0: resolution: {integrity: sha512-pmUkYpyeF6LY1tXXPaVr902upCeSAisp7vtY5udlSSj31emhRTNKBxEJk30sD6CJHbYSPAh+B3GDR4aJvXi/FQ==} @@ -10099,7 +10080,7 @@ packages: is-stream: 1.1.0 npm-run-path: 2.0.2 p-finally: 1.0.0 - signal-exit: 3.0.5 + signal-exit: 3.0.7 strip-eof: 1.0.0 dev: true @@ -10580,7 +10561,6 @@ packages: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 - dev: true /fork-ts-checker-async-overlay-webpack-plugin/0.4.0_sjzsq4ndqjvzfirlvtns5daumi: resolution: {integrity: sha512-PdmEymfvFsPsZ3o0b72rtcIOvl3QAUiVXIdV4uzuV/+AH0zjHYy9Mo8qN5wJSLYYzkHnDte+5rGf4mKhuONqJA==} @@ -10890,6 +10870,13 @@ packages: dependencies: is-glob: 4.0.3 + /glob-parent/6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: false + /glob-to-regexp/0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} @@ -10900,13 +10887,26 @@ packages: dependencies: foreground-child: 3.1.1 jackspeak: 2.3.6 - minimatch: 9.0.3 - minipass: 7.0.4 - path-scurry: 1.10.1 + minimatch: 9.0.5 + minipass: 7.1.2 + path-scurry: 1.11.1 dev: true + /glob/10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + dev: false + /glob/3.1.21: resolution: {integrity: sha512-ANhy2V2+tFpRajE3wN4DhkNQ08KDr0Ir1qL12/cUe5+a7STEK8jkW4onUYuY8/06qAFuT5je7mjAqzx0eKI2tQ==} + deprecated: Glob versions prior to v9 are no longer supported dependencies: graceful-fs: 1.2.3 inherits: 1.0.2 @@ -11785,7 +11785,6 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - dev: true /is-boolean-object/1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} @@ -12329,6 +12328,14 @@ packages: '@pkgjs/parseargs': 0.11.0 dev: true + /jackspeak/3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: false + /jake/10.8.2: resolution: {integrity: sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==} hasBin: true @@ -12962,6 +12969,11 @@ packages: - utf-8-validate dev: true + /jiti/1.21.6: + resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + hasBin: true + dev: false + /jotai-devtools/0.6.2_hgjqizhc26gc665cnflpub44vy: resolution: {integrity: sha512-iHKYt8V2T2Gh2DtGRpvpv2daVoFoHRJXqk5/LHnhFkJy9rMQuIGo4XgVu/v1ZMSvMzwDXdU3hDOQkfQWlDErUQ==} engines: {node: '>=14.0.0'} @@ -13462,6 +13474,16 @@ packages: immediate: 3.0.6 dev: false + /lilconfig/2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: false + + /lilconfig/3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} + dev: false + /lines-and-columns/1.1.6: resolution: {integrity: sha512-8ZmlJFVK9iCmtLz19HpSsR8HaAMWBT284VMNednLwlIMDP2hJDCIhUp0IZ2xUcZ+Ob6BM0VvCSJwzASDM45NLQ==} @@ -13793,7 +13815,6 @@ packages: /lru-cache/10.2.0: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} - dev: true /lru-cache/2.7.3: resolution: {integrity: sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==} @@ -14077,12 +14098,11 @@ packages: dependencies: brace-expansion: 1.1.11 - /minimatch/9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + /minimatch/9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: true /minimist/1.2.0: resolution: {integrity: sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=} @@ -14102,10 +14122,9 @@ packages: yallist: 4.0.0 dev: true - /minipass/7.0.4: - resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + /minipass/7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - dev: true /minizlib/2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -14230,6 +14249,14 @@ packages: engines: {node: '>=0.10.0'} dev: false + /mz/2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: false + /nanoid/3.1.20: resolution: {integrity: sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -14402,7 +14429,6 @@ packages: /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - dev: true /normalize-range/0.1.2: resolution: {integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=} @@ -14508,6 +14534,11 @@ packages: kind-of: 3.2.2 dev: true + /object-hash/3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: false + /object-inspect/1.11.0: resolution: {integrity: sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==} dev: true @@ -14818,6 +14849,10 @@ packages: netmask: 2.0.2 dev: false + /package-json-from-dist/1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + dev: false + /pako/0.2.9: resolution: {integrity: sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=} dev: true @@ -14971,13 +15006,12 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /path-scurry/1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} + /path-scurry/1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} dependencies: lru-cache: 10.2.0 - minipass: 7.0.4 - dev: true + minipass: 7.1.2 /path-to-regexp/0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} @@ -15043,7 +15077,6 @@ packages: /pify/2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - dev: true /pify/3.0.0: resolution: {integrity: sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=} @@ -15070,7 +15103,6 @@ packages: /pirates/4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - dev: true /pkg-dir/4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} @@ -15165,6 +15197,45 @@ packages: postcss: 5.2.18 dev: true + /postcss-import/15.1.0_postcss@8.4.27: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.27 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.2 + dev: false + + /postcss-js/4.0.1_postcss@8.4.27: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.27 + dev: false + + /postcss-load-config/4.0.2_postcss@8.4.27: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.1.2 + postcss: 8.4.27 + yaml: 2.5.1 + dev: false + /postcss-merge-idents/2.1.7: resolution: {integrity: sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=} dependencies: @@ -15253,6 +15324,26 @@ packages: postcss: 6.0.23 dev: true + /postcss-nested/5.0.6_postcss@8.4.27: + resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.27 + postcss-selector-parser: 6.1.2 + dev: false + + /postcss-nested/6.2.0_postcss@8.4.27: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.27 + postcss-selector-parser: 6.1.2 + dev: false + /postcss-normalize-charset/1.1.1: resolution: {integrity: sha1-757nEhLX/nWceO0WL2HtYrXLk/E=} dependencies: @@ -15297,13 +15388,21 @@ packages: dev: true /postcss-selector-parser/2.2.3: - resolution: {integrity: sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=} + resolution: {integrity: sha512-3pqyakeGhrO0BQ5+/tGTfvi5IAUAhHRayGK8WFSu06aEv2BmHoXw/Mhb+w7VY5HERIuC+QoUI7wgrCcq2hqCVA==} dependencies: flatten: 1.0.3 indexes-of: 1.0.1 uniq: 1.0.1 dev: true + /postcss-selector-parser/6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: false + /postcss-svgo/2.1.6: resolution: {integrity: sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=} dependencies: @@ -15325,6 +15424,10 @@ packages: resolution: {integrity: sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==} dev: true + /postcss-value-parser/4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: false + /postcss-zindex/2.2.0: resolution: {integrity: sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=} dependencies: @@ -15688,7 +15791,6 @@ packages: /quick-lru/5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} - dev: true /raf/3.4.1: resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} @@ -16891,6 +16993,12 @@ packages: loose-envify: 1.4.0 patched: true + /read-cache/1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + dev: false + /read-only-stream/2.0.0: resolution: {integrity: sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=} dependencies: @@ -16939,7 +17047,6 @@ packages: engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - dev: true /rechoir/0.8.0: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} @@ -17678,10 +17785,6 @@ packages: resolution: {integrity: sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=} dev: true - /signal-exit/3.0.5: - resolution: {integrity: sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==} - dev: true - /signal-exit/3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true @@ -17689,7 +17792,6 @@ packages: /signal-exit/4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - dev: true /simple-concat/1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -18188,7 +18290,6 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 - dev: true /string.prototype.matchall/4.0.5: resolution: {integrity: sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==} @@ -18302,7 +18403,6 @@ packages: engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 - dev: true /strip-bom/2.0.0: resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} @@ -18353,10 +18453,6 @@ packages: inline-style-parser: 0.1.1 dev: false - /style-vendorizer/2.2.3: - resolution: {integrity: sha512-/VDRsWvQAgspVy9eATN3z6itKTuyg+jW1q6UoTCQCFRqPDw8bi3E1hXIKnGw5LvXS2AQPuJ7Af4auTLYeBOLEg==} - dev: false - /stylis/4.0.10: resolution: {integrity: sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg==} dev: false @@ -18367,6 +18463,20 @@ packages: minimist: 1.2.8 dev: true + /sucrase/3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.1.6 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: false + /superstruct/0.8.4: resolution: {integrity: sha512-48Ors8IVWZm/tMr8r0Si6+mJiB7mkD7jqvIzktjJ4+EnP5tBp0qOpiM1J8sCUorKx+TXWrfb3i1UcjdD1YK/wA==} dependencies: @@ -18482,6 +18592,37 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 + /tailwindcss/3.4.13: + resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.5.3 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.1 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.27 + postcss-import: 15.1.0_postcss@8.4.27 + postcss-js: 4.0.1_postcss@8.4.27 + postcss-load-config: 4.0.2_postcss@8.4.27 + postcss-nested: 6.2.0_postcss@8.4.27 + postcss-selector-parser: 6.1.2 + resolve: 1.22.2 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + dev: false + /tapable/1.1.3: resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} engines: {node: '>=6'} @@ -18591,6 +18732,19 @@ packages: engines: {node: '>=0.8'} dev: false + /thenify-all/1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: false + + /thenify/3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: false + /three/0.139.2: resolution: {integrity: sha512-gV7q7QY8rogu7HLFZR9cWnOQAUedUhu2WXAnpr2kdXZP9YDKsG/0ychwQvWkZN5PlNw9mv5MoCTin6zNTXoONg==} dev: false @@ -18782,6 +18936,10 @@ packages: dependencies: typescript: 5.5.4 + /ts-interface-checker/0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: false + /ts-loader/5.3.3_typescript@5.5.4: resolution: {integrity: sha512-KwF1SplmOJepnoZ4eRIloH/zXL195F51skt7reEsS6jvDqzgc/YSbz9b8E07GxIUwLXdcD4ssrJu6v8CwaTafA==} engines: {node: '>=6.11.5'} @@ -19839,7 +19997,6 @@ packages: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 - dev: true /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -19978,6 +20135,12 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + /yaml/2.5.1: + resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} + engines: {node: '>= 14'} + hasBin: true + dev: false + /yargs-parser/20.2.4: resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} engines: {node: '>=10'} diff --git a/editor/src/components/canvas/ui-jsx-canvas.tsx b/editor/src/components/canvas/ui-jsx-canvas.tsx index 03b2215fd10e..85239c3dce47 100644 --- a/editor/src/components/canvas/ui-jsx-canvas.tsx +++ b/editor/src/components/canvas/ui-jsx-canvas.tsx @@ -77,7 +77,6 @@ import { applyUIDMonkeyPatch } from '../../utils/canvas-react-utils' import type { RemixValidPathsGenerationContext } from './canvas-utils' import { getParseSuccessForFilePath, getValidElementPaths } from './canvas-utils' import { arrayEqualsByValue, fastForEach, NO_OP } from '../../core/shared/utils' -import { useTwind } from '../../core/tailwind/tailwind' import { AlwaysFalse, atomWithPubSub, @@ -98,6 +97,7 @@ import { IS_TEST_ENVIRONMENT } from '../../common/env-vars' import { listenForReactRouterErrors } from '../../core/shared/runtime-report-logs' import { getFilePathMappings } from '../../core/model/project-file-utils' import { useInvalidatedCanvasRemount } from './canvas-component-entry' +import { useTailwindCompilation } from '../../core/tailwind/tailwind-compilation' applyUIDMonkeyPatch() @@ -498,7 +498,7 @@ export const UiJsxCanvas = React.memo((props) const executionScope = scope - useTwind(projectContentsForRequireFn, customRequire, '#canvas-container') + useTailwindCompilation(customRequire) const topLevelElementsMap = useKeepReferenceEqualityIfPossible(new Map(topLevelJsxComponents)) diff --git a/editor/src/components/inspector/inspector.tsx b/editor/src/components/inspector/inspector.tsx index e4ea5d8d688c..2b6686ec0e4a 100644 --- a/editor/src/components/inspector/inspector.tsx +++ b/editor/src/components/inspector/inspector.tsx @@ -48,7 +48,6 @@ import { import { getElementsToTarget } from './common/inspector-utils' import type { ElementPath, PropertyPath } from '../../core/shared/project-file-types' import { unless, when } from '../../utils/react-conditionals' -import { isTwindEnabled } from '../../core/tailwind/tailwind' import { isKeyboardAbsoluteStrategy, isKeyboardReorderStrategy, @@ -90,6 +89,7 @@ import { import { InspectorSectionHeader } from './section-header' import { GridPlacementSubsection } from './sections/style-section/container-subsection/grid-cell-subsection' import { ContainerSubsection } from './sections/style-section/container-subsection/container-subsection' +import { isTailwindEnabled } from '../../core/tailwind/tailwind-compilation' export interface ElementPathElement { name?: string @@ -286,7 +286,8 @@ export const Inspector = React.memo((props: InspectorProps) => { const shouldShowStyleSectionContents = styleSectionOpen && !shouldHideInspectorSections const shouldShowAdvancedSectionContents = advancedSectionOpen && !shouldHideInspectorSections - const shouldShowClassNameSubsection = isTwindEnabled() && inspectorPreferences.includes('visual') + const shouldShowClassNameSubsection = + isTailwindEnabled() && inspectorPreferences.includes('visual') const shouldShowTargetSelectorSection = canEdit && inspectorPreferences.includes('visual') const shouldShowFlexSection = multiselectedContract === 'frame' && diff --git a/editor/src/core/tailwind/tailwind-compilation.ts b/editor/src/core/tailwind/tailwind-compilation.ts new file mode 100644 index 000000000000..9e030e1b83ad --- /dev/null +++ b/editor/src/core/tailwind/tailwind-compilation.ts @@ -0,0 +1,106 @@ +import React from 'react' +import type { TailwindConfig, Tailwindcss } from '@mhsdesign/jit-browser-tailwindcss' +import { createTailwindcss } from '@mhsdesign/jit-browser-tailwindcss' +import type { ProjectContentTreeRoot } from 'utopia-shared/src/types' +import { getProjectFileByFilePath, walkContentsTree } from '../../components/assets' +import { interactionSessionIsActive } from '../../components/canvas/canvas-strategies/interaction-state' +import { CanvasContainerID } from '../../components/canvas/canvas-types' +import { + Substores, + useEditorState, + useRefEditorState, +} from '../../components/editor/store/store-hook' +import { importDefault } from '../es-modules/commonjs-interop' +import { rescopeCSSToTargetCanvasOnly } from '../shared/css-utils' +import type { RequireFn } from '../shared/npm-dependency-types' +import { TailwindConfigPath } from './tailwind-config' +import { ElementsToRerenderGLOBAL } from '../../components/canvas/ui-jsx-canvas' +import { isFeatureEnabled } from '../../utils/feature-switches' + +const TAILWIND_INSTANCE: { current: Tailwindcss | null } = { current: null } + +export function isTailwindEnabled(): boolean { + return TAILWIND_INSTANCE.current != null +} + +function ensureElementExists({ type, id }: { type: string; id: string }) { + let tag = document.getElementById(id) + if (tag == null) { + tag = document.createElement(type) + tag.id = id + document.head.appendChild(tag) + } + return tag +} + +async function generateTailwindStyles(tailwindCss: Tailwindcss, allCSSFiles: string) { + const contentElement = document.getElementById(CanvasContainerID) + if (contentElement == null) { + return + } + const content = contentElement.outerHTML + const styleString = await tailwindCss.generateStylesFromContent(allCSSFiles, [content]) + const style = ensureElementExists({ type: 'style', id: 'utopia-tailwind-jit-styles' }) + style.textContent = rescopeCSSToTargetCanvasOnly(styleString) +} + +function getCssFilesFromProjectContents(projectContents: ProjectContentTreeRoot) { + let files: string[] = [] + walkContentsTree(projectContents, (path, file) => { + if (file.type === 'TEXT_FILE' && path.endsWith('.css')) { + files.push(file.fileContents.code) + } + }) + return files +} + +function generateTailwindClasses(projectContents: ProjectContentTreeRoot, requireFn: RequireFn) { + const allCSSFiles = getCssFilesFromProjectContents(projectContents).join('\n') + const rawConfig = importDefault(requireFn('/', TailwindConfigPath)) + const tailwindCss = createTailwindcss({ tailwindConfig: rawConfig as TailwindConfig }) + TAILWIND_INSTANCE.current = tailwindCss + void generateTailwindStyles(tailwindCss, allCSSFiles) +} + +export const useTailwindCompilation = (requireFn: RequireFn) => { + const projectContents = useEditorState( + Substores.projectContents, + (store) => store.editor.projectContents, + 'useTailwindCompilation projectContents', + ) + + const isInteractionActiveRef = useRefEditorState((store) => + interactionSessionIsActive(store.editor.canvas.interactionSession), + ) + + const observerCallback = React.useCallback(() => { + if ( + isInteractionActiveRef.current || + ElementsToRerenderGLOBAL.current !== 'rerender-all-elements' || // implies that an interaction is in progress + !isFeatureEnabled('Tailwind') + ) { + return + } + generateTailwindClasses(projectContents, requireFn) + }, [isInteractionActiveRef, projectContents, requireFn]) + + React.useEffect(() => { + const tailwindConfigFile = getProjectFileByFilePath(projectContents, TailwindConfigPath) + if (tailwindConfigFile == null || tailwindConfigFile.type !== 'TEXT_FILE') { + return // we consider tailwind to be enabled if there's a tailwind config file in the project + } + const observer = new MutationObserver(observerCallback) + + observer.observe(document.getElementById(CanvasContainerID)!, { + attributes: true, + childList: true, + subtree: true, + }) + + observerCallback() + + return () => { + observer.disconnect() + } + }, [isInteractionActiveRef, observerCallback, projectContents, requireFn]) +} diff --git a/editor/src/core/tailwind/tailwind-options.tsx b/editor/src/core/tailwind/tailwind-options.tsx index e0a0dc6140d2..93710dce45f0 100644 --- a/editor/src/core/tailwind/tailwind-options.tsx +++ b/editor/src/core/tailwind/tailwind-options.tsx @@ -28,9 +28,9 @@ import { } from '../shared/jsx-attribute-utils' import * as PP from '../shared/property-path' import * as EP from '../shared/element-path' -import { isTwindEnabled } from './tailwind' import type { AttributeCategory } from './attribute-categories' import { AttributeCategories } from './attribute-categories' +import { isTailwindEnabled } from './tailwind-compilation' export interface TailWindOption { label: string @@ -165,7 +165,7 @@ export function useFilteredOptions( onEmptyResults: () => void = NO_OP, ): Array { return React.useMemo(() => { - if (isTwindEnabled()) { + if (isTailwindEnabled()) { const sanitisedFilter = filter.trim().toLowerCase() const searchTerms = searchStringToIndividualTerms(sanitisedFilter) let results: Array diff --git a/editor/src/core/tailwind/tailwind.spec.browser2.tsx b/editor/src/core/tailwind/tailwind.spec.browser2.tsx new file mode 100644 index 000000000000..8040db905fdc --- /dev/null +++ b/editor/src/core/tailwind/tailwind.spec.browser2.tsx @@ -0,0 +1,218 @@ +import { renderTestEditorWithModel } from '../../components/canvas/ui-jsx.test-utils' +import { createModifiedProject } from '../../sample-projects/sample-project-utils.test-utils' +import { setFeatureForBrowserTestsUseInDescribeBlockOnly } from '../../utils/utils.test-utils' +import { wait } from '../model/performance-scripts' + +const Project = createModifiedProject({ + '/utopia/storyboard.js': `import { Scene, Storyboard } from 'utopia-api' + +export var storyboard = ( + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Text Shadow + This is a medium text shadow example + This is a large text shadow example + This has no text shadow +
+ + +) +`, + '/src/app.css': ` +@tailwind base; +@tailwind components; +@tailwind utilities; +`, + 'tailwind.config.js': ` +const Tailwind = { + theme: { + colors: { + transparent: 'transparent', + current: 'currentColor', + white: '#ffffff', + purple: '#3f3cbb', + midnight: '#121063', + metal: '#565584', + tahiti: '#3ab7bf', + silver: '#ecebff', + 'bubble-gum': '#ff77e9', + bermuda: '#78dcca', + }, + }, + plugins: [ + function ({ addUtilities }) { + const newUtilities = { + '.text-shadow': { + textShadow: '2px 2px 4px rgba(0, 0, 0, 0.1)', + }, + '.text-shadow-md': { + textShadow: '3px 3px 6px rgba(0, 0, 0, 0.2)', + }, + '.text-shadow-lg': { + textShadow: '4px 4px 8px rgba(0, 0, 0, 0.3)', + }, + '.text-shadow-none': { + textShadow: 'none', + }, + } + + addUtilities(newUtilities, ['responsive', 'hover']) + }, + ], +} +export default Tailwind +`, +}) + +describe('rendering tailwind projects in the editor', () => { + setFeatureForBrowserTestsUseInDescribeBlockOnly('Tailwind', true) + it('can render absolute positioning classes', async () => { + const editor = await renderTestEditorWithModel(Project, 'await-first-dom-report') + + { + const absolute = editor.renderedDOM.getByTestId('absolute') + const { position, top, left, width, height, backgroundColor } = getComputedStyle(absolute) + expect({ position, top, left, width, height, backgroundColor }).toEqual({ + backgroundColor: 'rgb(58, 183, 191)', + height: '177px', + left: '40px', + position: 'absolute', + top: '33px', + width: '620px', + }) + } + { + const absoluteChild = editor.renderedDOM.getByTestId('absolute-child') + const { position, top, left, width, height, backgroundColor } = + getComputedStyle(absoluteChild) + expect({ position, top, left, width, height, backgroundColor }).toEqual({ + backgroundColor: 'rgb(18, 16, 99)', + height: '40px', + left: '16px', + position: 'absolute', + top: '16px', + width: '40px', + }) + } + }) + + it('can render flex positioning classes', async () => { + const editor = await renderTestEditorWithModel(Project, 'await-first-dom-report') + + const flex = editor.renderedDOM.getByTestId('flex') + const { display, flexDirection, justifyContent, alignItems, gap, padding } = + getComputedStyle(flex) + expect({ display, flexDirection, justifyContent, alignItems, gap, padding }).toEqual({ + alignItems: 'center', + display: 'flex', + flexDirection: 'row', + gap: '40px', + justifyContent: 'flex-start', + padding: '30px 20px', + }) + }) + + it('can render grid positioning classes', async () => { + const editor = await renderTestEditorWithModel(Project, 'await-first-dom-report') + + const grid = editor.renderedDOM.getByTestId('grid') + const { display, gridTemplateColumns, gridTemplateRows, gap } = getComputedStyle(grid) + expect({ display, gridTemplateColumns, gridTemplateRows, gap }).toEqual({ + display: 'grid', + gap: '16px', + gridTemplateColumns: '138px 138px 138px 138px', + gridTemplateRows: '50.5px 50.5px 50.5px 50.5px', + }) + + { + const gridChild2 = editor.renderedDOM.getByTestId('grid-child-2') + const { gridColumnStart, gridColumnEnd, gridRowStart, gridRowEnd, backgroundColor } = + getComputedStyle(gridChild2) + expect({ gridColumnStart, gridColumnEnd, gridRowStart, gridRowEnd, backgroundColor }).toEqual( + { + backgroundColor: 'rgb(255, 119, 233)', + gridColumnEnd: 'span 3', + gridColumnStart: 'span 3', + gridRowEnd: 'auto', + gridRowStart: '2', + }, + ) + } + + { + const gridChild3 = editor.renderedDOM.getByTestId('grid-child-3') + const { gridColumnStart, gridColumnEnd, gridRowStart, gridRowEnd, backgroundColor } = + getComputedStyle(gridChild3) + expect({ gridColumnStart, gridColumnEnd, gridRowStart, gridRowEnd, backgroundColor }).toEqual( + { + backgroundColor: 'rgb(255, 119, 233)', + gridColumnEnd: 'auto', + gridColumnStart: '4', + gridRowEnd: 'auto', + gridRowStart: '3', + }, + ) + } + }) + + it('can render classes added from custom plugins', async () => { + const editor = await renderTestEditorWithModel(Project, 'await-first-dom-report') + + { + const textShadow1 = editor.renderedDOM.getByTestId('text-shadow-1') + const { textShadow, fontSize, lineHeight } = getComputedStyle(textShadow1) + expect({ textShadow, fontSize, lineHeight }).toEqual({ + fontSize: '36px', + lineHeight: '40px', + textShadow: 'rgba(0, 0, 0, 0.1) 2px 2px 4px', + }) + } + { + const textShadow2 = editor.renderedDOM.getByTestId('text-shadow-2') + const { textShadow, fontSize, lineHeight } = getComputedStyle(textShadow2) + expect({ textShadow, fontSize, lineHeight }).toEqual({ + fontSize: '30px', + lineHeight: '36px', + textShadow: 'rgba(0, 0, 0, 0.2) 3px 3px 6px', + }) + } + { + const textShadow3 = editor.renderedDOM.getByTestId('text-shadow-3') + const { textShadow, fontSize, lineHeight } = getComputedStyle(textShadow3) + expect({ textShadow, fontSize, lineHeight }).toEqual({ + fontSize: '24px', + lineHeight: '32px', + textShadow: 'rgba(0, 0, 0, 0.3) 4px 4px 8px', + }) + } + { + const textShadow4 = editor.renderedDOM.getByTestId('text-shadow-4') + const { textShadow, fontSize, lineHeight } = getComputedStyle(textShadow4) + expect({ textShadow, fontSize, lineHeight }).toEqual({ + fontSize: '20px', + lineHeight: '28px', + textShadow: 'none', + }) + } + }) +}) diff --git a/editor/src/core/tailwind/tailwind.spec.ts b/editor/src/core/tailwind/tailwind.spec.ts deleted file mode 100644 index ce4e4b35ed3e..000000000000 --- a/editor/src/core/tailwind/tailwind.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { adjustRuleScopeImpl } from './tailwind' - -describe('adjustRuleScope', () => { - it('Returns a rule unchanged if no prefix is provided', () => { - const input = '.container{width:100%}' - const output = adjustRuleScopeImpl(input, null) - const expected = input - expect(output).toEqual(expected) - }) - - it('Returns a rule unchanged if it is an at-rule but not a media query', () => { - const input = '@keyframes spin{to{transform:rotate(360deg)}}' - const output = adjustRuleScopeImpl(input, '#canvas-container') - const expected = input - expect(output).toEqual(expected) - }) - - it('Prefixes a regular selector', () => { - const input = '.container{width:100%}' - const output = adjustRuleScopeImpl(input, '#canvas-container') - const expected = '#canvas-container .container{width:100%}' - expect(output).toEqual(expected) - }) - - it('Handles comma separated selectors', () => { - const input = '.container,.other-container{width:100%}' - const output = adjustRuleScopeImpl(input, '#canvas-container') - const expected = '#canvas-container .container,#canvas-container .other-container{width:100%}' - expect(output).toEqual(expected) - }) - - it('Replaces :root, html, or head with the provided prefix', () => { - const rootOutput = adjustRuleScopeImpl(':root{width:100%}', '#canvas-container') - const htmlOutput = adjustRuleScopeImpl('html{width:100%}', '#canvas-container') - const headOutput = adjustRuleScopeImpl('head{width:100%}', '#canvas-container') - const expected = '#canvas-container{width:100%}' - expect(rootOutput).toEqual(expected) - expect(htmlOutput).toEqual(expected) - expect(headOutput).toEqual(expected) - }) - - it('Replaces body with a selector for children of the provided prefix', () => { - const input = 'body{width:100%}' - const output = adjustRuleScopeImpl(input, '#canvas-container') - const expected = '#canvas-container > *{width:100%}' - expect(output).toEqual(expected) - }) - - it('Handles a media query', () => { - const input = '@media (min-width:640px){.container{max-width:640px}}' - const output = adjustRuleScopeImpl(input, '#canvas-container') - const expected = '@media (min-width:640px){#canvas-container .container{max-width:640px}}' - expect(output).toEqual(expected) - }) -}) diff --git a/editor/src/core/tailwind/tailwind.ts b/editor/src/core/tailwind/tailwind.ts deleted file mode 100644 index e6f348483c79..000000000000 --- a/editor/src/core/tailwind/tailwind.ts +++ /dev/null @@ -1,291 +0,0 @@ -import type { ProjectContentTreeRoot } from '../../components/assets' -import { packageJsonFileFromProjectContents } from '../../components/assets' -import { getProjectFileByFilePath } from '../../components/assets' -import type { Either } from '../shared/either' -import { isRight, left, right } from '../shared/either' -import type { RequireFn } from '../shared/npm-dependency-types' -import type { ProjectFile } from '../shared/project-file-types' -import { isTextFile } from '../shared/project-file-types' -import type { Sheet, Twind } from '@twind/core' -import { cssom, observe, defineConfig, tw } from '@twind/core' -import presetAutoprefix from '@twind/preset-autoprefix' -import presetTailwind from '@twind/preset-tailwind' -import React from 'react' -import { includesDependency } from '../../components/editor/npm-dependency/npm-dependency' -import { propOrNull } from '../shared/object-utils' -import { memoize } from '../shared/memoize' -import { importDefault } from '../es-modules/commonjs-interop' -import { PostCSSPath, TailwindConfigPath } from './tailwind-config' -import { useKeepReferenceEqualityIfPossible } from '../../utils/react-performance' -import { twind } from '@twind/core' - -type TwindConfigType = ReturnType - -function hasRequiredDependenciesForTailwind(packageJsonFile: ProjectFile): boolean { - const hasTailwindDependency = includesDependency(packageJsonFile, 'tailwindcss') - const hasPostCSSDependency = includesDependency(packageJsonFile, 'postcss') - - return hasTailwindDependency && hasPostCSSDependency -} - -function useGetPackageJson(projectContents: ProjectContentTreeRoot): ProjectFile | null { - return React.useMemo(() => packageJsonFileFromProjectContents(projectContents), [projectContents]) -} - -function useHasRequiredDependenciesForTailwind(projectContents: ProjectContentTreeRoot): boolean { - const packageJsonFile = useGetPackageJson(projectContents) - return React.useMemo(() => { - return packageJsonFile != null && hasRequiredDependenciesForTailwind(packageJsonFile) - }, [packageJsonFile]) -} - -function postCSSIncludesTailwindPlugin(postCSSFile: ProjectFile, requireFn: RequireFn): boolean { - if (isTextFile(postCSSFile)) { - try { - const requireResult = requireFn('/', PostCSSPath) - const rawConfig = importDefault(requireResult) - const plugins = (rawConfig as any)?.plugins - return plugins?.tailwindcss != null - } catch (e) { - /* Do nothing */ - } - } - - return false -} - -function useGetPostCSSConfigFile(projectContents: ProjectContentTreeRoot): ProjectFile | null { - return React.useMemo( - () => getProjectFileByFilePath(projectContents, PostCSSPath), - [projectContents], - ) -} - -function usePostCSSIncludesTailwindPlugin( - projectContents: ProjectContentTreeRoot, - requireFn: RequireFn, -): boolean { - const postCSSFile = useGetPostCSSConfigFile(projectContents) - return React.useMemo(() => { - return postCSSFile != null && postCSSIncludesTailwindPlugin(postCSSFile, requireFn) - }, [postCSSFile, requireFn]) -} - -const PreflightKey = 'preflight' - -function enablesPreflight(tailwindConfig: any): boolean { - const corePlugins = propOrNull('corePlugins', tailwindConfig) - if (corePlugins != null && typeof corePlugins === 'object') { - if (Array.isArray(corePlugins)) { - // This means we have an explicit list of all allowed core plugins - return corePlugins.includes(PreflightKey) - } else { - // We have an object that enables or disables specific plugins - all unlisted plugins are enabled - const explicitDisabled = corePlugins[PreflightKey] === false // Tailwind doesn't use truthiness here - return !explicitDisabled - } - } - - return true -} - -function convertTailwindToTwindConfig(tailwindConfig: any): TwindConfigType { - const preflightEnabled = enablesPreflight(tailwindConfig) - - const twindConfig = defineConfig({ - presets: [ - presetTailwind({ - disablePreflight: !preflightEnabled, - }), - presetAutoprefix(), - ], - // force pushing tailwind's config to twind - theme: tailwindConfig.theme, - darkMode: tailwindConfig.darkMode, - variants: tailwindConfig.variants, - preflight: tailwindConfig.preflight, - }) - - return twindConfig -} - -function getTailwindConfig( - tailwindFile: ProjectFile | null, - requireFn: RequireFn, -): Either { - if (tailwindFile != null && isTextFile(tailwindFile)) { - try { - const requireResult = requireFn('/', TailwindConfigPath) - const rawConfig = importDefault(requireResult) - if (rawConfig != null) { - const twindConfig = convertTailwindToTwindConfig(rawConfig) - return right(twindConfig) - } else { - return left('Tailwind config contains no default export') - } - } catch (error) { - console.error('Error loading tailwind config', error) - return left(error) - } - } - - return left('Invalid or missing tailwind config file type') -} - -function useGetTailwindConfigFile(projectContents: ProjectContentTreeRoot): ProjectFile | null { - return React.useMemo( - () => getProjectFileByFilePath(projectContents, TailwindConfigPath), - [projectContents], - ) -} - -function useGetTailwindConfig( - projectContents: ProjectContentTreeRoot, - requireFn: RequireFn, -): TwindConfigType { - const tailwindConfigFile = useGetTailwindConfigFile(projectContents) - const tailwindConfig = React.useMemo(() => { - const maybeConfig = getTailwindConfig(tailwindConfigFile, requireFn) - if (isRight(maybeConfig)) { - return maybeConfig.value - } else { - return defineConfig({}) - } - }, [tailwindConfigFile, requireFn]) - return useKeepReferenceEqualityIfPossible(tailwindConfig) -} - -interface TwindInstance { - element: HTMLStyleElement - instance: Twind -} - -let twindInstance: TwindInstance | null = null - -export function isTwindEnabled(): boolean { - return twindInstance != null -} - -function clearTwind() { - if (twindInstance != null) { - twindInstance.instance.clear() - twindInstance.instance.destroy() - twindInstance.element.parentNode?.removeChild(twindInstance.element) - } -} - -export function adjustRuleScopeImpl(rule: string, prefixSelector: string | null): string { - // TODO Use css-tree to handle more complex cases. That doesn't seem necessary right now since Tailwind - // as at 2.2.4 only uses @media and @keyframes - const isMediaQuery = rule.startsWith('@media') - const isOtherAtRule = rule.startsWith('@') && !isMediaQuery - if (prefixSelector == null || isOtherAtRule) { - return rule - } else { - const splitOnBrace = rule.split('{') - const selectorIndex = isMediaQuery ? 1 : 0 - const splitSelectors = splitOnBrace[selectorIndex].split(',') - const scopedSelectors = splitSelectors.map((s) => { - const lowerCaseSelector = s.toLowerCase().trim() - - if ( - lowerCaseSelector === ':root' || - lowerCaseSelector === 'html' || - lowerCaseSelector === 'head' - ) { - return prefixSelector - } else if (lowerCaseSelector === 'body') { - return `${prefixSelector} > *` - } else { - return `${prefixSelector} ${s}` - } - }) - const joinedSelectors = scopedSelectors.join(',') - const theRest = splitOnBrace.slice(selectorIndex + 1) - const front = splitOnBrace.slice(0, selectorIndex) - const finalRule = [...front, joinedSelectors, ...theRest].join('{') - return finalRule - } -} - -const adjustRuleScope = memoize(adjustRuleScopeImpl, { - maxSize: 100, - matchesArg: (a, b) => a === b, -}) - -function updateTwind(config: TwindConfigType, prefixSelector: string | null) { - const element = document.head.appendChild(document.createElement('style')) - element.appendChild(document.createTextNode('')) // Avoid Edge bug where empty style elements doesn't create sheets - element.setAttribute('id', `twind-styles-${Math.random().toString(36).slice(2)}`) - - const sheet = cssom(element) - const customSheet: Sheet = { - ...sheet, - target: sheet.target, - insert: (rule, index, sheetRule) => { - const scopedRule = adjustRuleScope(rule, prefixSelector) - sheet.insert(scopedRule, index, sheetRule) - }, - } - - clearTwind() - - if (twindInstance == null) { - const prefixes = ['TWIND_', 'TAILWIND_'] - window.addEventListener('warning', (event: any | { detail: { code: string } }) => { - const isTwindWarning: boolean = prefixes.some((prefix) => - event?.detail?.code?.startsWith?.(prefix), - ) - if (isTwindWarning) { - event.preventDefault() - } - }) - } - - const instance = observe(twind(config, customSheet), document.documentElement) - - twindInstance = { - element: element, - instance: instance, - } -} - -export function useTwind( - projectContents: ProjectContentTreeRoot, - requireFn: RequireFn, - prefixSelector: string | null = null, -): void { - const hasDependencies = useHasRequiredDependenciesForTailwind(projectContents) - const hasPostCSSPlugin = usePostCSSIncludesTailwindPlugin(projectContents, requireFn) - const shouldUseTwind = hasDependencies && hasPostCSSPlugin - const tailwindConfig = useGetTailwindConfig(projectContents, requireFn) - React.useEffect(() => { - if (shouldUseTwind) { - updateTwind(tailwindConfig, prefixSelector) - } else { - clearTwind() - } - }, [prefixSelector, shouldUseTwind, tailwindConfig]) -} - -export function injectTwind( - projectContents: ProjectContentTreeRoot, - requireFn: RequireFn, - prefixSelector: string | null = null, -): void { - const packageJsonFile = packageJsonFileFromProjectContents(projectContents) - const hasDependencies = - packageJsonFile != null && hasRequiredDependenciesForTailwind(packageJsonFile) - const postCSSFile = getProjectFileByFilePath(projectContents, PostCSSPath) - const hasPostCSSPlugin = - postCSSFile != null && postCSSIncludesTailwindPlugin(postCSSFile, requireFn) - const shouldUseTwind = hasDependencies && hasPostCSSPlugin - const tailwindConfigFile = getProjectFileByFilePath(projectContents, TailwindConfigPath) - const maybeTailwindConfig = getTailwindConfig(tailwindConfigFile, requireFn) - const tailwindConfig = isRight(maybeTailwindConfig) ? maybeTailwindConfig.value : defineConfig({}) - if (shouldUseTwind) { - updateTwind(tailwindConfig, prefixSelector) - } else { - clearTwind() - } -} diff --git a/editor/src/templates/preview/preview.tsx b/editor/src/templates/preview/preview.tsx index 3379822ff2ea..c2db43f38fb9 100644 --- a/editor/src/templates/preview/preview.tsx +++ b/editor/src/templates/preview/preview.tsx @@ -21,7 +21,6 @@ import { pluck } from '../../core/shared/array-utils' import { getMainHTMLFilename, getMainJSFilename } from '../../core/shared/project-contents-utils' import type { NodeModules } from '../../core/shared/project-file-types' import { isTextFile } from '../../core/shared/project-file-types' -import { injectTwind } from '../../core/tailwind/tailwind' import { NewBundlerWorker, RealBundlerWorker } from '../../core/workers/bundler-bridge' import { createBundle } from '../../core/workers/bundler-promise' import Utils from '../../utils/utils' @@ -280,8 +279,6 @@ const initPreview = () => { } } - injectTwind(projectContents, requireFn) - const previewJSFileName = getMainJSFilename(projectContents) const previewJSFilePath = `/${previewJSFileName}` const previewJSFile = getProjectFileByFilePath(projectContents, previewJSFilePath) diff --git a/editor/src/utils/__mocks__/jit-browser-tailwindcss.js b/editor/src/utils/__mocks__/jit-browser-tailwindcss.js new file mode 100644 index 000000000000..54cc6d0eb188 --- /dev/null +++ b/editor/src/utils/__mocks__/jit-browser-tailwindcss.js @@ -0,0 +1,5 @@ +module.exports = { + createTailwindcss: () => ({ + generateStylesFromContent: () => '', + }), +} diff --git a/editor/src/utils/feature-switches.ts b/editor/src/utils/feature-switches.ts index cce2962ef6c7..9fa1a0064189 100644 --- a/editor/src/utils/feature-switches.ts +++ b/editor/src/utils/feature-switches.ts @@ -17,6 +17,7 @@ export type FeatureName = | 'Condensed Navigator Entries' | 'Canvas Fast Selection Hack' | 'Roll Your Own' + | 'Tailwind' export const AllFeatureNames: FeatureName[] = [ // 'Dragging Reparents By Default', // Removing this option so that we can experiment on this later @@ -34,6 +35,7 @@ export const AllFeatureNames: FeatureName[] = [ 'Condensed Navigator Entries', 'Canvas Fast Selection Hack', 'Roll Your Own', + 'Tailwind', ] let FeatureSwitches: { [feature in FeatureName]: boolean } = { @@ -48,6 +50,7 @@ let FeatureSwitches: { [feature in FeatureName]: boolean } = { 'Project Thumbnail Generation': false, 'Debug - Print UIDs': false, 'Debug – Connections': false, + Tailwind: false, 'Condensed Navigator Entries': !IS_TEST_ENVIRONMENT, 'Canvas Fast Selection Hack': true, 'Roll Your Own': false, From 0e797f8632d82d6dc6967e18d8c1cfc798c0113b Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:38:37 +0200 Subject: [PATCH 061/272] Hide crowded grid resize controls (#6430) **Problem:** Grid resize controls should be hidden when they get too crowded, for example when zooming out. Screenshot 2024-09-30 at 17 32 08 **Fix:** Hide the controls for an axis if any of the control areas would become smaller than the control size. Fixes #6429 --- .../canvas/controls/grid-controls.tsx | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index a72f25fbb4b5..bbdba72e9a10 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -405,12 +405,25 @@ export const GridResizing = React.memo((props: GridResizingProps) => { }) }, [props.fromPropsAxisValues, resizingIndex]) + const scale = useEditorState( + Substores.canvas, + (store) => store.editor.canvas.scale, + 'GridResizing scale', + ) + if (props.axisValues == null) { return null } switch (props.axisValues.type) { case 'DIMENSIONS': const size = GRID_RESIZE_HANDLE_CONTAINER_SIZE / canvasScale + const dimensions = props.axisValues.dimensions + + const hideControls = dimensions.some((dim) => { + const scaledSize = (dim.type === 'NUMBER' ? dim.value.value : 0) * scale + return scaledSize < GRID_RESIZE_HANDLE_SIZE + }) + return (
{ display: 'grid', gridTemplateColumns: props.axis === 'column' - ? props.axisValues.dimensions.map((dim) => printGridCSSNumber(dim)).join(' ') + ? dimensions.map((dim) => printGridCSSNumber(dim)).join(' ') : undefined, gridTemplateRows: props.axis === 'row' - ? props.axisValues.dimensions.map((dim) => printGridCSSNumber(dim)).join(' ') + ? dimensions.map((dim) => printGridCSSNumber(dim)).join(' ') : undefined, gap: props.gap ?? 0, paddingLeft: @@ -435,9 +448,10 @@ export const GridResizing = React.memo((props: GridResizingProps) => { : undefined, paddingTop: props.axis === 'row' && props.padding != null ? `${props.padding.top}px` : undefined, + visibility: hideControls ? 'hidden' : 'visible', }} > - {props.axisValues.dimensions.flatMap((dimension, dimensionIndex) => { + {dimensions.flatMap((dimension, dimensionIndex) => { return ( MetadataUtils.findElementByElementPath(store.editor.jsxMetadata, target), - 'GridResizeShadow element', + 'GridResizeControls element', ) const dispatch = useDispatch() @@ -1560,7 +1574,7 @@ export const GridResizeControls = controlForStrategyMemoized store.editor.canvas.scale, - 'GridResizingControl scale', + 'GridResizeControls scale', ) const resizeControlRef = useRefEditorState((store) => From aa7955e3817c4a50c5eac859f44c8ddccba6a248 Mon Sep 17 00:00:00 2001 From: Balazs Bajorics <2226774+balazsbajorics@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:46:17 +0200 Subject: [PATCH 062/272] fixing setPaddingStrategy elementsToRerender (#6427) This PR sets the elementsToRerender value in the setPaddingStrategy --- .../strategies/set-padding-strategy.tsx | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/set-padding-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/set-padding-strategy.tsx index 01f65b4b22c2..bb69d4fc2a7c 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/set-padding-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/set-padding-strategy.tsx @@ -270,10 +270,7 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti })), ), ], - // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 - // This was to maintain the existing behaviour, but it should be replaced with a more specific value - // appropriate to this particular case. - 'rerender-all-elements', + selectedElements, ) } @@ -301,10 +298,7 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti })), ), ], - // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 - // This was to maintain the existing behaviour, but it should be replaced with a more specific value - // appropriate to this particular case. - 'rerender-all-elements', + selectedElements, ) } @@ -334,10 +328,7 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti })), ), ], - // FIXME: This was added as a default value in https://github.com/concrete-utopia/utopia/pull/6408 - // This was to maintain the existing behaviour, but it should be replaced with a more specific value - // appropriate to this particular case. - 'rerender-all-elements', + selectedElements, ) }, } From 9ac163c9259361b2349c73c64c5fd74e6908353c Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:20:47 +0200 Subject: [PATCH 063/272] Fix duplicate key in inspector background section (#6438) **Problem:** The inspector background section causes duplicate keys errors. image **Fix:** Rename the keys for solid/gradient <> string background inputs so they are unique. Fixes #6437 --- .../background-subsection/solid-background-layer.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/editor/src/components/inspector/sections/style-section/background-subsection/solid-background-layer.tsx b/editor/src/components/inspector/sections/style-section/background-subsection/solid-background-layer.tsx index 2eb227918cdb..d5f9381117f5 100644 --- a/editor/src/components/inspector/sections/style-section/background-subsection/solid-background-layer.tsx +++ b/editor/src/components/inspector/sections/style-section/background-subsection/solid-background-layer.tsx @@ -117,9 +117,9 @@ export const SolidBackgroundLayer = React.memo((props onMouseDown={stopPropagation} /> ((props setOpenPopup={props.setOpenPopup} /> Date: Tue, 1 Oct 2024 12:21:10 +0200 Subject: [PATCH 064/272] Detect stretch when resizing grid cell (#6436) **Problem:** The grid cell resize handles should be shown when the child is stretching as well as filling the cell. **Fix:** Do that. Fixes #6435 --- ...-resize-element-strategy.spec.browser2.tsx | 31 +++++++++++++++++++ .../grid-resize-element-strategy.ts | 10 +++--- .../components/inspector/inspector-common.ts | 13 ++++++-- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx index 0ba50510b128..7b39be3806b6 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx @@ -340,6 +340,26 @@ export var storyboard = ( } }) }) + + it('also works for stretching cells', async () => { + const editor = await renderTestEditorWithCode(ProjectCode, 'await-first-dom-report') + + await runCellResizeTest( + editor, + 'column-end', + gridCellTargetId(EP.fromString('sb/scene/grid'), 2, 10), + EP.fromString('sb/scene/grid/eee'), + ) + + const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd } = + editor.renderedDOM.getByTestId('grid-child-stretch').style + expect({ gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd }).toEqual({ + gridColumnEnd: '11', + gridColumnStart: '4', + gridRowStart: '4', + gridRowEnd: 'auto', + }) + }) }) const ProjectCode = `import * as React from 'react' @@ -425,6 +445,17 @@ export var storyboard = ( data-uid='ddd' data-testid='grid-child' /> +
diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts index 2f47003ac5ce..daa9996bc207 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.ts @@ -38,12 +38,10 @@ export const gridResizeElementStrategy: CanvasStrategyFactory = ( return null } - const isFillContainer = isFixedHugFillModeApplied( - canvasState.startingMetadata, - selectedElement, - 'fill', - ) - if (!isFillContainer) { + const isFillOrStretchContainer = + isFixedHugFillModeApplied(canvasState.startingMetadata, selectedElement, 'fill') || + isFixedHugFillModeApplied(canvasState.startingMetadata, selectedElement, 'stretch') + if (!isFillOrStretchContainer) { return null } diff --git a/editor/src/components/inspector/inspector-common.ts b/editor/src/components/inspector/inspector-common.ts index 7f0b03ef28a1..06588173c38b 100644 --- a/editor/src/components/inspector/inspector-common.ts +++ b/editor/src/components/inspector/inspector-common.ts @@ -679,14 +679,23 @@ export function detectFillHugFixedState( ) if (MetadataUtils.isGridCell(metadata, elementPath)) { - if ( + const isStretchingExplicitly = (element.specialSizeMeasurements.alignSelf === 'stretch' && axis === 'horizontal' && width == null) || (element.specialSizeMeasurements.justifySelf === 'stretch' && axis === 'vertical' && height == null) - ) { + + const isStretchingImplicitly = + width == null && + height == null && + (element.specialSizeMeasurements.alignSelf == null || + element.specialSizeMeasurements.alignSelf === 'auto') && + (element.specialSizeMeasurements.justifySelf == null || + element.specialSizeMeasurements.justifySelf === 'auto') + + if (isStretchingExplicitly || isStretchingImplicitly) { return { fixedHugFill: { type: 'stretch' }, controlStatus: 'detected' } } } From 161179c924bd0c7f3e6317155e388be625db654a Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:32:58 +0200 Subject: [PATCH 065/272] Clamp minimum gap for flex/grid elements (#6441) **Problem:** The grid and flex gap inspector controls can go negative, either by scrubbing as well as direct input. **Fix:** 1. Add `minimum={0}` to those number inputs so the scrubbing cannot go lower than 0 2. Clamp the value calculated in the number input so it stays between the min/max bounds. Fixes #6440 --- editor/src/components/inspector/flex-section.tsx | 6 ++++++ .../flex-container-controls.tsx | 2 ++ editor/src/uuiui/inputs/number-input.tsx | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/editor/src/components/inspector/flex-section.tsx b/editor/src/components/inspector/flex-section.tsx index 3ff686593e13..b32f4da14128 100644 --- a/editor/src/components/inspector/flex-section.tsx +++ b/editor/src/components/inspector/flex-section.tsx @@ -887,6 +887,8 @@ const GapRowColumnControl = React.memo(() => { { { { testId='flex.container.gap' key='flex.container.gap' value={value} + minimum={0} + clampOnSubmitValue={true} onSubmitValue={wrappedOnSubmitValue} onTransientSubmitValue={wrappedOnTransientSubmitValue} onForcedSubmitValue={wrappedOnSubmitValue} diff --git a/editor/src/uuiui/inputs/number-input.tsx b/editor/src/uuiui/inputs/number-input.tsx index 41db6078d683..aeb9d054fee5 100644 --- a/editor/src/uuiui/inputs/number-input.tsx +++ b/editor/src/uuiui/inputs/number-input.tsx @@ -36,11 +36,10 @@ import type { } from '../../components/inspector/controls/control' import type { Either } from '../../core/shared/either' import { isLeft, mapEither } from '../../core/shared/either' -import { clampValue, point } from '../../core/shared/math-utils' +import { clampValue } from '../../core/shared/math-utils' import { memoize } from '../../core/shared/memoize' import type { ControlStyles } from '../../uuiui-deps' import { getControlStyles, CSSCursor } from '../../uuiui-deps' -import type { IcnProps } from '../icn' import { Icn } from '../icn' import { useColorTheme, UtopiaTheme } from '../styles/theme' import { FlexRow } from '../widgets/layout/flex-row' @@ -141,6 +140,7 @@ export interface NumberInputOptions { pasteHandler?: boolean descriptionLabel?: string disableScrubbing?: boolean + clampOnSubmitValue?: boolean } export interface AbstractNumberInputProps @@ -190,6 +190,7 @@ export const NumberInput = React.memo( invalid, pasteHandler, disableScrubbing = false, + clampOnSubmitValue, }) => { const ref = React.useRef(null) const colorTheme = useColorTheme() @@ -511,7 +512,12 @@ export const NumberInput = React.memo( if (isLeft(parsed)) { return unknownInputValue(displayValue) } - return parsed.value + return clampOnSubmitValue + ? { + ...parsed.value, + value: clampValue(parsed.value.value, minimum, maximum), + } + : parsed.value } const newValue = getNewValue() @@ -540,6 +546,9 @@ export const NumberInput = React.memo( updateValue, value, displayValue, + minimum, + maximum, + clampOnSubmitValue, ], ) From 76631a682c7952a6e558d16dfce0a91a6ccfdd1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20K=C3=B6rmendy?= Date: Tue, 1 Oct 2024 16:18:51 +0200 Subject: [PATCH 066/272] Remove the code related to the Preview pane (#6426) ## Description This PR removes a lot of code related to the preview pane. No guarantees for exhaustiveness --- .github/pull_request_template.md | 2 +- editor/src/components/canvas/stored-layout.ts | 7 +- editor/src/components/common/actions/index.ts | 7 +- editor/src/components/editor/action-types.ts | 11 - .../editor/actions/action-creators.ts | 15 - .../components/editor/actions/action-utils.ts | 2 - .../src/components/editor/actions/actions.tsx | 35 -- .../components/editor/editor-component.tsx | 43 -- .../editor/preview-report-handler.ts | 31 -- .../src/components/editor/store/dispatch.tsx | 31 +- .../components/editor/store/editor-state.ts | 23 - .../editor/store/editor-update.spec.tsx | 32 -- .../components/editor/store/editor-update.tsx | 4 - .../store/store-deep-equality-instances.ts | 14 - .../store/store-hook-substore-helpers.ts | 4 - .../src/components/preview/preview-pane.tsx | 407 ------------------ editor/src/core/shared/redux-devtools.ts | 3 - editor/src/templates/editor.tsx | 19 +- editor/src/templates/preview/index.html | 89 ---- editor/src/templates/preview/preview.tsx | 338 --------------- editor/webpack.config.js | 13 - .../components/common/preview-devices.tsx | 151 ------- .../preview/preview-page-component.tsx | 335 -------------- website-next/pages/preview/[id].tsx | 12 - 24 files changed, 5 insertions(+), 1623 deletions(-) delete mode 100644 editor/src/components/editor/preview-report-handler.ts delete mode 100644 editor/src/components/preview/preview-pane.tsx delete mode 100644 editor/src/templates/preview/index.html delete mode 100644 editor/src/templates/preview/preview.tsx delete mode 100644 website-next/components/common/preview-devices.tsx delete mode 100644 website-next/components/preview/preview-page-component.tsx delete mode 100644 website-next/pages/preview/[id].tsx diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 2816a36f4fa5..0652827a898c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -14,6 +14,6 @@ Describe the fix you have made as succinctly as possible. I hereby swear that: - [ ] I opened a hydrogen project and it loaded -- [ ] I could navigate to various routes in Preview mode +- [ ] I could navigate to various routes in Play mode Fixes #[ticket_number] (<< pls delete this line if it's not relevant) diff --git a/editor/src/components/canvas/stored-layout.ts b/editor/src/components/canvas/stored-layout.ts index 595716a5efd2..bb2426034158 100644 --- a/editor/src/components/canvas/stored-layout.ts +++ b/editor/src/components/canvas/stored-layout.ts @@ -24,12 +24,7 @@ export const GridPanelsNumberOfRows = 12 export type Menu = 'inspector' | 'navigator' export type Pane = 'code-editor' -export const allMenusAndPanels: Array = [ - 'navigator', - 'code-editor', - 'inspector', - // 'preview', // Does this exist? -] +export const allMenusAndPanels: Array = ['navigator', 'code-editor', 'inspector'] export interface GridPanelData { panel: StoredPanel diff --git a/editor/src/components/common/actions/index.ts b/editor/src/components/common/actions/index.ts index b58160a0e349..9272ebc26903 100644 --- a/editor/src/components/common/actions/index.ts +++ b/editor/src/components/common/actions/index.ts @@ -1,5 +1,3 @@ -export type PreviewPanel = 'preview' - export type LeftMenuPanel = | 'filebrowser' | 'dependencylist' @@ -22,10 +20,9 @@ export type EditorPanel = | CenterPanel | CodeEditorPanel | InspectorPanel - | PreviewPanel | NavigatorPanel -export type EditorPane = 'leftmenu' | 'center' | 'inspector' | 'preview' | 'rightmenu' +export type EditorPane = 'leftmenu' | 'center' | 'inspector' | 'rightmenu' export function paneForPanel(panel: EditorPanel | null): EditorPane | null { switch (panel) { @@ -55,8 +52,6 @@ export function paneForPanel(panel: EditorPanel | null): EditorPane | null { return 'rightmenu' case 'codeEditor': return 'center' - case 'preview': - return 'preview' default: const _exhaustiveCheck: never = panel throw new Error(`Unhandled panel ${panel}`) diff --git a/editor/src/components/editor/action-types.ts b/editor/src/components/editor/action-types.ts index 94190c524369..757fa6769497 100644 --- a/editor/src/components/editor/action-types.ts +++ b/editor/src/components/editor/action-types.ts @@ -602,11 +602,6 @@ export interface SetProjectDescription { description: string } -export interface UpdatePreviewConnected { - action: 'UPDATE_PREVIEW_CONNECTED' - connected: boolean -} - export interface AlignSelectedViews { action: 'ALIGN_SELECTED_VIEWS' alignment: Alignment @@ -628,10 +623,6 @@ export interface SetCursorOverlay { cursor: CSSCursor | null } -export interface SendPreviewModel { - action: 'SEND_PREVIEW_MODEL' -} - export interface UpdateFilePath { action: 'UPDATE_FILE_PATH' oldPath: string @@ -1278,13 +1269,11 @@ export type EditorAction = | OpenCodeEditor | SetProjectName | SetProjectDescription - | UpdatePreviewConnected | AlignSelectedViews | DistributeSelectedViews | SetCursorOverlay | DuplicateSpecificElements | UpdateDuplicationState - | SendPreviewModel | UpdateFilePath | UpdateRemixRoute | OpenCodeEditorFile diff --git a/editor/src/components/editor/actions/action-creators.ts b/editor/src/components/editor/actions/action-creators.ts index fa9ad247a85b..723c48306606 100644 --- a/editor/src/components/editor/actions/action-creators.ts +++ b/editor/src/components/editor/actions/action-creators.ts @@ -92,7 +92,6 @@ import type { SaveImageSwitchMode, SelectAllSiblings, SelectComponents, - SendPreviewModel, SetAspectRatioLock, SetCanvasFrames, SetCodeEditorBuildErrors, @@ -144,7 +143,6 @@ import type { UpdateKeysPressed, UpdateNodeModulesContents, UpdatePackageJson, - UpdatePreviewConnected, UpdatePropertyControlsInfo, CloseDesignerFile, SetFocusedElement, @@ -974,13 +972,6 @@ export function setProjectDescription(projectDescription: string): SetProjectDes } } -export function updatePreviewConnected(connected: boolean): UpdatePreviewConnected { - return { - action: 'UPDATE_PREVIEW_CONNECTED', - connected: connected, - } -} - export function alignSelectedViews(alignment: Alignment): AlignSelectedViews { return { action: 'ALIGN_SELECTED_VIEWS', @@ -1006,12 +997,6 @@ export function showContextMenu( } } -export function sendPreviewModel(): SendPreviewModel { - return { - action: 'SEND_PREVIEW_MODEL', - } -} - export function updateFilePath(oldPath: string, newPath: string): UpdateFilePath { return { action: 'UPDATE_FILE_PATH', diff --git a/editor/src/components/editor/actions/action-utils.ts b/editor/src/components/editor/actions/action-utils.ts index 6b4e6b7c33ec..a695b30ad16a 100644 --- a/editor/src/components/editor/actions/action-utils.ts +++ b/editor/src/components/editor/actions/action-utils.ts @@ -62,8 +62,6 @@ export function isTransientAction(action: EditorAction): boolean { case 'SET_PROJECT_ID': case 'SET_CODE_EDITOR_VISIBILITY': case 'OPEN_CODE_EDITOR': - case 'UPDATE_PREVIEW_CONNECTED': - case 'SEND_PREVIEW_MODEL': case 'CLOSE_DESIGNER_FILE': case 'UPDATE_CODE_RESULT_CACHE': case 'SET_CODE_EDITOR_BUILD_ERRORS': diff --git a/editor/src/components/editor/actions/actions.tsx b/editor/src/components/editor/actions/actions.tsx index dc5a7ed77b80..7baaa1b2848c 100644 --- a/editor/src/components/editor/actions/actions.tsx +++ b/editor/src/components/editor/actions/actions.tsx @@ -239,7 +239,6 @@ import type { ScrollToElement, SelectAllSiblings, SelectComponents, - SendPreviewModel, SetAspectRatioLock, SetCanvasFrames, SetCodeEditorBuildErrors, @@ -304,7 +303,6 @@ import type { UpdateMouseButtonsPressed, UpdateNodeModulesContents, UpdatePackageJson, - UpdatePreviewConnected, UpdateProjectContents, UpdatePropertyControlsInfo, WrapInElement, @@ -1000,10 +998,6 @@ export function restoreEditorState( formulaBarMode: desiredEditor.topmenu.formulaBarMode, formulaBarFocusCounter: currentEditor.topmenu.formulaBarFocusCounter, }, - preview: { - visible: currentEditor.preview.visible, - connected: currentEditor.preview.connected, - }, home: { visible: currentEditor.home.visible, }, @@ -2966,14 +2960,6 @@ export const UPDATE_FNS = { visible: action.visible, }, } - case 'preview': - return { - ...editor, - preview: { - ...editor.preview, - visible: action.visible, - }, - } case 'codeEditor': return { ...editor, @@ -3069,14 +3055,6 @@ export const UPDATE_FNS = { visible: !editor.inspector.visible, }, } - case 'preview': - return { - ...editor, - preview: { - ...editor.preview, - visible: !editor.preview.visible, - }, - } case 'projectsettings': return { ...editor, @@ -3743,12 +3721,6 @@ export const UPDATE_FNS = { projectDescription: action.description, } }, - - UPDATE_PREVIEW_CONNECTED: (action: UpdatePreviewConnected, editor: EditorModel): EditorModel => { - return produce(editor, (editorState) => { - editorState.preview.connected = action.connected - }) - }, ALIGN_SELECTED_VIEWS: (action: AlignSelectedViews, editor: EditorModel): EditorModel => { return alignOrDistributeSelectedViews(editor, action.alignment) }, @@ -3763,9 +3735,6 @@ export const UPDATE_FNS = { openMenu(action.menuName, action.event) return editor }, - SEND_PREVIEW_MODEL: (action: SendPreviewModel, editor: EditorModel): EditorModel => { - return editor - }, UPDATE_FILE_PATH: ( action: UpdateFilePath, editor: EditorModel, @@ -6398,10 +6367,6 @@ export async function load( ) } -export function isSendPreviewModel(action: any): action is SendPreviewModel { - return action != null && (action as SendPreviewModel).action === 'SEND_PREVIEW_MODEL' -} - function saveFileInProjectContents( projectContents: ProjectContentTreeRoot, filePath: string, diff --git a/editor/src/components/editor/editor-component.tsx b/editor/src/components/editor/editor-component.tsx index c87d105ed4d7..e4d1cfacfe0b 100644 --- a/editor/src/components/editor/editor-component.tsx +++ b/editor/src/components/editor/editor-component.tsx @@ -39,7 +39,6 @@ import { ConfirmDeleteDialog } from '../filebrowser/confirm-delete-dialog' import { ConfirmOverwriteDialog } from '../filebrowser/confirm-overwrite-dialog' import { ConfirmRevertDialog } from '../filebrowser/confirm-revert-dialog' import { ConfirmRevertAllDialog } from '../filebrowser/confirm-revert-all-dialog' -import { PreviewColumn } from '../preview/preview-pane' import * as EditorActions from './actions/action-creators' import { FatalIndexedDBErrorComponent } from './fatal-indexeddb-error-component' import { editorIsTarget, handleKeyDown, handleKeyUp } from './global-shortcuts' @@ -377,12 +376,6 @@ export const EditorComponentInner = React.memo((props: EditorProps) => { (store) => store.editor.id, 'EditorComponentInner projectId', ) - const previewVisible = useEditorState( - Substores.restOfEditor, - (store) => store.editor.preview.visible, - 'EditorComponentInner previewVisible', - ) - const yDoc = useEditorState( Substores.restOfStore, (store) => store.collaborativeEditingSupport.session?.mergeDoc, @@ -417,11 +410,6 @@ export const EditorComponentInner = React.memo((props: EditorProps) => { } }, [projectName, projectId, forking]) - const onClosePreview = React.useCallback( - () => dispatch([EditorActions.setPanelVisibility('preview', false)]), - [dispatch], - ) - const startDragInsertion = React.useCallback( (event: React.DragEvent) => { const draggedTypes = event.nativeEvent?.dataTransfer?.types @@ -524,37 +512,6 @@ export const EditorComponentInner = React.memo((props: EditorProps) => { {/* insert more columns here */} - - {previewVisible ? ( - - - } - onClose={onClosePreview} - /> - - - - ) : null} diff --git a/editor/src/components/editor/preview-report-handler.ts b/editor/src/components/editor/preview-report-handler.ts deleted file mode 100644 index f7bfd86fa05b..000000000000 --- a/editor/src/components/editor/preview-report-handler.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { EditorDispatch } from './action-types' -import { updatePreviewConnected } from './actions/action-creators' - -export const InternalPreviewTimeout = 500 - -let lastReportFromPreviewTS = 0 -let timeout = 0 -let intervalId: number - -export function previewIsAlive(newTimeout: number) { - timeout = newTimeout - lastReportFromPreviewTS = Date.now() -} - -export function handlePreviewDisconnected() { - lastReportFromPreviewTS = 0 -} - -export function startPreviewConnectedMonitoring(dispatch: EditorDispatch) { - let previousPreviewConnected: boolean - - window.clearInterval(intervalId) - intervalId = window.setInterval(() => { - const stillConnected = - lastReportFromPreviewTS > 0 && Date.now() - lastReportFromPreviewTS < timeout - if (stillConnected !== previousPreviewConnected) { - dispatch([updatePreviewConnected(stillConnected)], 'everyone') - } - previousPreviewConnected = stillConnected - }, 200) -} diff --git a/editor/src/components/editor/store/dispatch.tsx b/editor/src/components/editor/store/dispatch.tsx index b4c4b2153a6d..c0e1a99e29a6 100644 --- a/editor/src/components/editor/store/dispatch.tsx +++ b/editor/src/components/editor/store/dispatch.tsx @@ -6,7 +6,6 @@ import { runLocalNavigatorAction } from '../../../templates/editor-navigator' import { optionalDeepFreeze } from '../../../utils/deep-freeze' import type { CanvasAction } from '../../canvas/canvas-types' import type { LocalNavigatorAction } from '../../navigator/actions' -import { PreviewIframeId, projectContentsUpdateMessage } from '../../preview/preview-pane' import type { EditorAction, EditorDispatch, UpdateMetadataInEditorState } from '../action-types' import { isLoggedIn } from '../action-types' import { @@ -46,7 +45,7 @@ import { isBrowserEnvironment } from '../../../core/shared/utils' import type { UiJsxCanvasContextData } from '../../canvas/ui-jsx-canvas' import type { ProjectContentTreeRoot } from '../../assets' import { treeToContents } from '../../assets' -import { isSendPreviewModel, restoreDerivedState, UPDATE_FNS } from '../actions/actions' +import { restoreDerivedState, UPDATE_FNS } from '../actions/actions' import { getTransitiveReverseDependencies } from '../../../core/shared/project-contents-dependencies' import { reduxDevtoolsSendActions, @@ -309,26 +308,6 @@ function processActions( }, working) } -export function updateEmbeddedPreview( - modelId: string | null, - projectContents: ProjectContentTreeRoot, -): void { - const embeddedPreviewElement = document.getElementById(PreviewIframeId) - if (embeddedPreviewElement != null) { - const embeddedPreviewIframe = embeddedPreviewElement as any as HTMLIFrameElement - const contentWindow = embeddedPreviewIframe.contentWindow - if (contentWindow != null) { - try { - contentWindow.postMessage(projectContentsUpdateMessage(projectContents), '*') - } catch (exception) { - // Don't nuke the editor if there's an exception posting the message. - // This can happen if a value can't be cloned when posted. - console.error('Error updating preview.', exception) - } - } - } -} - function maybeRequestModelUpdate( projectContents: ProjectContentTreeRoot, workers: UtopiaTsWorkers, @@ -525,7 +504,6 @@ export function editorDispatchClosingOut( }) const anyWorkerUpdates = checkAnyWorkerUpdates(dispatchedActions) const anyUndoOrRedo = dispatchedActions.some(isUndoOrRedo) - const anySendPreviewModel = dispatchedActions.some(isSendPreviewModel) // The FINISH_CHECKPOINT_TIMER action effectively overrides the case where nothing changed, // as it's likely that action on it's own didn't change anything, but the actions that paired with @@ -723,13 +701,6 @@ export function editorDispatchClosingOut( } } - const shouldUpdatePreview = - anySendPreviewModel || - frozenEditorState.projectContents !== storedState.unpatchedEditor.projectContents - if (shouldUpdatePreview) { - updateEmbeddedPreview(frozenEditorState.id, frozenEditorState.projectContents) - } - if (frozenEditorState.id != null && frozenEditorState.id != storedState.unpatchedEditor.id) { storedState.workers.initWatchdogWorker(frozenEditorState.id) } diff --git a/editor/src/components/editor/store/editor-state.ts b/editor/src/components/editor/store/editor-state.ts index d6090a49e8bb..633fe15505e7 100644 --- a/editor/src/components/editor/store/editor-state.ts +++ b/editor/src/components/editor/store/editor-state.ts @@ -1089,18 +1089,6 @@ export function editorStateTopMenu( } } -export interface EditorStatePreview { - visible: boolean - connected: boolean -} - -export function editorStatePreview(visible: boolean, connected: boolean): EditorStatePreview { - return { - visible: visible, - connected: connected, - } -} - export interface EditorStateHome { visible: boolean } @@ -1446,7 +1434,6 @@ export interface EditorState { projectSettings: EditorStateProjectSettings navigator: NavigatorState topmenu: EditorStateTopMenu - preview: EditorStatePreview home: EditorStateHome lastUsedFont: FontSettings | null modal: ModalDialog | null @@ -1530,7 +1517,6 @@ export function editorState( projectSettings: EditorStateProjectSettings, editorStateNavigator: NavigatorState, topmenu: EditorStateTopMenu, - preview: EditorStatePreview, home: EditorStateHome, lastUsedFont: FontSettings | null, modal: ModalDialog | null, @@ -1615,7 +1601,6 @@ export function editorState( projectSettings: projectSettings, navigator: editorStateNavigator, topmenu: topmenu, - preview: preview, home: home, lastUsedFont: lastUsedFont, modal: modal, @@ -2687,10 +2672,6 @@ export function createEditorState(dispatch: EditorDispatch): EditorState { formulaBarMode: 'content', formulaBarFocusCounter: 0, }, - preview: { - visible: false, - connected: false, - }, home: { visible: false, }, @@ -3049,10 +3030,6 @@ export function editorModelFromPersistentModel( formulaBarMode: 'content', formulaBarFocusCounter: 0, }, - preview: { - visible: false, - connected: false, - }, home: { visible: false, }, diff --git a/editor/src/components/editor/store/editor-update.spec.tsx b/editor/src/components/editor/store/editor-update.spec.tsx index 855542efe4d1..fe59fde9219a 100644 --- a/editor/src/components/editor/store/editor-update.spec.tsx +++ b/editor/src/components/editor/store/editor-update.spec.tsx @@ -308,38 +308,6 @@ describe('action TOGGLE_PANE', () => { ) chaiExpect(updatedEditor2.inspector.visible).to.not.equal(updatedEditor.inspector.visible) }) - - it('can toggle preview visibility', () => { - const { editor, derivedState, dispatch } = createEditorStates() - const action = togglePanel('preview') - const updatedEditor = runLocalEditorAction( - editor, - derivedState, - defaultUserState, - workers, - action, - History.init(editor, derivedState), - dispatch, - emptyUiJsxCanvasContextData(), - builtInDependencies, - emptyCollaborativeEditingSupport(), - emptyProjectServerState(), - ) - const updatedEditor2 = runLocalEditorAction( - updatedEditor, - derivedState, - defaultUserState, - workers, - action, - History.init(editor, derivedState), - dispatch, - emptyUiJsxCanvasContextData(), - builtInDependencies, - emptyCollaborativeEditingSupport(), - emptyProjectServerState(), - ) - chaiExpect(updatedEditor2.preview.visible).to.not.equal(updatedEditor.preview.visible) - }) }) describe('action DUPLICATE_SPECIFIC_ELEMENTS', () => { diff --git a/editor/src/components/editor/store/editor-update.tsx b/editor/src/components/editor/store/editor-update.tsx index f2b5e82c80d0..e663daa121e8 100644 --- a/editor/src/components/editor/store/editor-update.tsx +++ b/editor/src/components/editor/store/editor-update.tsx @@ -262,14 +262,10 @@ export function runSimpleLocalEditorAction( return UPDATE_FNS.SET_PROJECT_NAME(action, state) case 'SET_PROJECT_DESCRIPTION': return UPDATE_FNS.SET_PROJECT_DESCRIPTION(action, state) - case 'UPDATE_PREVIEW_CONNECTED': - return UPDATE_FNS.UPDATE_PREVIEW_CONNECTED(action, state) case 'SHOW_CONTEXT_MENU': return UPDATE_FNS.SHOW_CONTEXT_MENU(action, state) case 'DUPLICATE_SPECIFIC_ELEMENTS': return UPDATE_FNS.DUPLICATE_SPECIFIC_ELEMENTS(action, state, dispatch) - case 'SEND_PREVIEW_MODEL': - return UPDATE_FNS.SEND_PREVIEW_MODEL(action, state) case 'UPDATE_FILE_PATH': return UPDATE_FNS.UPDATE_FILE_PATH(action, state, userState) case 'UPDATE_REMIX_ROUTE': diff --git a/editor/src/components/editor/store/store-deep-equality-instances.ts b/editor/src/components/editor/store/store-deep-equality-instances.ts index f379de57390f..06e57d5b3d14 100644 --- a/editor/src/components/editor/store/store-deep-equality-instances.ts +++ b/editor/src/components/editor/store/store-deep-equality-instances.ts @@ -313,7 +313,6 @@ import type { EditorStateGoogleFontsResources, EditorStateProjectSettings, EditorStateTopMenu, - EditorStatePreview, EditorStateHome, FileDeleteModal, ModalDialog, @@ -398,7 +397,6 @@ import { editorStateGoogleFontsResources, editorStateProjectSettings, editorStateTopMenu, - editorStatePreview, editorStateHome, fileDeleteModal, fileOverwriteModal, @@ -4397,15 +4395,6 @@ export const EditorStateTopMenuKeepDeepEquality: KeepDeepEqualityCall = - combine2EqualityCalls( - (preview) => preview.visible, - BooleanKeepDeepEquality, - (preview) => preview.connected, - BooleanKeepDeepEquality, - editorStatePreview, - ) - export const EditorStateHomeKeepDeepEquality: KeepDeepEqualityCall = combine1EqualityCall((preview) => preview.visible, BooleanKeepDeepEquality, editorStateHome) @@ -5241,7 +5230,6 @@ export const EditorStateKeepDeepEquality: KeepDeepEqualityCall = ( ) const navigatorResults = NavigatorStateKeepDeepEquality(oldValue.navigator, newValue.navigator) const topmenuResults = EditorStateTopMenuKeepDeepEquality(oldValue.topmenu, newValue.topmenu) - const previewResults = EditorStatePreviewKeepDeepEquality(oldValue.preview, newValue.preview) const homeResults = EditorStateHomeKeepDeepEquality(oldValue.home, newValue.home) const lastUsedFontResults = nullableDeepEquality(FontSettingsKeepDeepEquality)( oldValue.lastUsedFont, @@ -5436,7 +5424,6 @@ export const EditorStateKeepDeepEquality: KeepDeepEqualityCall = ( projectSettingsResults.areEqual && navigatorResults.areEqual && topmenuResults.areEqual && - previewResults.areEqual && homeResults.areEqual && lastUsedFontResults.areEqual && modalResults.areEqual && @@ -5522,7 +5509,6 @@ export const EditorStateKeepDeepEquality: KeepDeepEqualityCall = ( projectSettingsResults.value, navigatorResults.value, topmenuResults.value, - previewResults.value, homeResults.value, lastUsedFontResults.value, modalResults.value, diff --git a/editor/src/components/editor/store/store-hook-substore-helpers.ts b/editor/src/components/editor/store/store-hook-substore-helpers.ts index 7e41cf6cc104..bd45ce5dd768 100644 --- a/editor/src/components/editor/store/store-hook-substore-helpers.ts +++ b/editor/src/components/editor/store/store-hook-substore-helpers.ts @@ -124,10 +124,6 @@ export const EmptyEditorStateForKeysOnly: EditorState = { formulaBarMode: 'content', formulaBarFocusCounter: 0, }, - preview: { - visible: false, - connected: false, - }, home: { visible: false, }, diff --git a/editor/src/components/preview/preview-pane.tsx b/editor/src/components/preview/preview-pane.tsx deleted file mode 100644 index 18668969db60..000000000000 --- a/editor/src/components/preview/preview-pane.tsx +++ /dev/null @@ -1,407 +0,0 @@ -/** @jsxRuntime classic */ -/** @jsx jsx */ -import { jsx } from '@emotion/react' -import React from 'react' -import type { DeviceInfo } from '../../common/devices' -import { deviceInfoList } from '../../common/devices' -import { BASE_URL, FLOATING_PREVIEW_BASE_URL } from '../../common/env-vars' -import { Substores, useEditorState } from '../editor/store/store-hook' -import type { SelectOption } from '../inspector/controls/select-control' -import type { TextFile } from '../../core/shared/project-file-types' -import { isTextFile, ProjectContents } from '../../core/shared/project-file-types' -import { objectKeyParser, parseString } from '../../utils/value-parser-utils' -import { eitherToMaybe } from '../../core/shared/either' -import { shareURLForProject } from '../../core/shared/utils' -import { getMainJSFilename } from '../../core/shared/project-contents-utils' -import type { ProjectContentTreeRoot } from '../assets' -import { - FlexRow, - Button, - //TODO: switch to functional component and make use of 'useColorTheme': - colorTheme, - FlexColumn, - UtopiaTheme, - SquareButton, - LargerIcons, - Subdued, - PopupList, - Icn, - UIRow, -} from '../../uuiui' -import { setBranchNameFromURL } from '../../utils/branches' - -export const PreviewIframeId = 'preview-column-container' - -export interface ProjectContentsUpdateMessage { - type: 'PROJECT_CONTENTS_UPDATE' - projectContents: ProjectContentTreeRoot -} - -export function projectContentsUpdateMessage( - projectContents: ProjectContentTreeRoot, -): ProjectContentsUpdateMessage { - return { - type: 'PROJECT_CONTENTS_UPDATE', - projectContents: projectContents, - } -} - -export function isProjectContentsUpdateMessage( - data: unknown, -): data is ProjectContentsUpdateMessage { - return ( - data != null && - typeof data === 'object' && - !Array.isArray(data) && - (data as ProjectContentsUpdateMessage).type === 'PROJECT_CONTENTS_UPDATE' - ) -} - -interface IntermediatePreviewColumnProps { - id: string | null - projectName: string - connected: boolean - packageJSONFile: TextFile | null -} - -export interface PreviewColumnProps { - id: string | null - projectName: string - connected: boolean - editedFilename: string | null -} - -export interface PreviewColumnState { - selectedBackgroundOptionIndex: number - running: boolean - useDevice: boolean - scale: number - selectedScaleOption: number - deviceInfo: DeviceInfo - rotated: boolean - refreshCount: number - width: number - height: number -} - -export const PreviewColumn = React.memo(() => { - const mainJSFilename = useEditorState( - Substores.projectContents, - (store) => getMainJSFilename(store.editor.projectContents), - 'PreviewColumn mainJSFilename', - ) - const { id, projectName, connected } = useEditorState( - Substores.restOfEditor, - (store) => { - return { - id: store.editor.id, - projectName: store.editor.projectName, - connected: store.editor.preview.connected, - } - }, - 'PreviewColumn', - ) - return ( - - ) -}) -PreviewColumn.displayName = 'PreviewColumn' - -class PreviewColumnContent extends React.Component { - scaleOptions: number[] - scaleDropdownOptions: any - backgroundOptions: any - constructor(props: PreviewColumnProps) { - super(props) - - this.scaleOptions = [0.25, 0.5, 0.67, 1, 1.25, 1.5, 2, 3, 4] - this.backgroundOptions = [ - { - label: 'White', - value: { backgroundColor: '#ffffff' }, - }, - { - label: 'Checkerboard (light)', - value: { - backgroundImage: - 'linear-gradient(45deg, #d4d4d4 25%, transparent 25%), linear-gradient(-45deg, #d4d4d4 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #d4d4d4 75%), linear-gradient(-45deg, transparent 75%, #d4d4d4 75%)', - backgroundSize: '10px 10px', - backgroundPosition: '0 0, 0 5px, 5px -5px, -5px 0px', - }, - }, - { - label: 'Light Grey', - value: { backgroundColor: '#f4f4f4' }, - }, - { - label: 'Mid Grey', - value: { backgroundColor: '#888888' }, - }, - { label: 'Dark Grey', value: { backgroundColor: '#333' } }, - { label: 'Black', value: { backgroundColor: '#000' } }, - ] - - this.scaleDropdownOptions = this.scaleOptions.map((s) => ({ - value: s, - label: `${Math.round(s * 100)}%`, - })) - - this.state = { - selectedBackgroundOptionIndex: 0, - running: true, - useDevice: false, - scale: 1, - selectedScaleOption: 4, - deviceInfo: deviceInfoList.iPhoneXS, - rotated: false, - refreshCount: 0, - width: deviceInfoList.iPhoneXS.width as number, - height: deviceInfoList.iPhoneXS.height as number, - } - } - - scaleDown = () => { - this.setState((prevState) => ({ scale: Math.max(0.25, prevState.scale * 0.5) })) - } - - scaleUp = () => { - this.setState((prevState) => ({ scale: Math.min(8, prevState.scale * 2) })) - } - - setSelectedValue = (selectedValue: SelectOption) => this.setState({ scale: selectedValue.value }) - - onRestartClick = () => { - this.setState((prevState) => ({ - refreshCount: prevState.refreshCount + 1, - })) - } - - handleKeyPress = (e: React.KeyboardEvent) => { - if (e.key === 'Enter') { - e.stopPropagation() - this.onRestartClick() - } - } - - toggleRunning = () => { - this.setState((prevState) => ({ running: !prevState.running })) - } - - render() { - const ColorButtonGroup = () => ( - *': { - marginRight: 8, - }, - }} - > - {this.backgroundOptions.map((background: any, i: number) => ( - - ))} - - ) - - function addInBranchNames(url: string): string { - if (url === '') { - return url - } else { - const parsedURL = new URL(url) - setBranchNameFromURL(parsedURL.searchParams) - return parsedURL.toString() - } - } - let floatingPreviewURL = - this.props.id == null - ? '' - : shareURLForProject(FLOATING_PREVIEW_BASE_URL, this.props.id, this.props.projectName) - floatingPreviewURL = addInBranchNames(floatingPreviewURL) - let iframePreviewURL = - this.props.id == null - ? '' - : `${floatingPreviewURL}?embedded=true&refreshCount=${this.state.refreshCount}` - iframePreviewURL = addInBranchNames(iframePreviewURL) - let popoutPreviewURL = - this.props.id == null - ? '' - : shareURLForProject(BASE_URL, this.props.id, this.props.projectName) - popoutPreviewURL = addInBranchNames(popoutPreviewURL) - - const iFrame = ( -