diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index efb144c5ed..f37e4cb4bf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - node: ["14.x", "16.x"] + node: ["16.x"] os: [ubuntu-latest] steps: - name: Checkout repo diff --git a/.github/workflows/vis-reg-tests.yml b/.github/workflows/vis-reg-tests.yml new file mode 100644 index 0000000000..922f2c2e77 --- /dev/null +++ b/.github/workflows/vis-reg-tests.yml @@ -0,0 +1,29 @@ +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: 16.x + cache: 'npm' + + - name: Install dependencies + run: yarn install --frozen-lockfile --ignore-scripts + + - name: Build Storybook for Design System + run: yarn storybook:ds:build + + - name: Lost Pixel + uses: lost-pixel/lost-pixel@v2.20.0 + env: + S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} + S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} + LOST_PIXEL_CONFIG_DIR: packages/design-system diff --git a/.gitignore b/.gitignore index 8fec2a6098..04b912530e 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ yarn-error.log* # builds packages/**/lib generated +storybook-static diff --git a/.lostpixel/baseline/components-combobox--complex.png b/.lostpixel/baseline/components-combobox--complex.png new file mode 100644 index 0000000000..4e21c7d287 Binary files /dev/null and b/.lostpixel/baseline/components-combobox--complex.png differ diff --git a/.lostpixel/baseline/components-combobox--simple.png b/.lostpixel/baseline/components-combobox--simple.png new file mode 100644 index 0000000000..dae0b9a6e9 Binary files /dev/null and b/.lostpixel/baseline/components-combobox--simple.png differ diff --git a/.lostpixel/baseline/components-primitives-create-content-controller--detect-input.png b/.lostpixel/baseline/components-primitives-create-content-controller--detect-input.png new file mode 100644 index 0000000000..baec796150 Binary files /dev/null and b/.lostpixel/baseline/components-primitives-create-content-controller--detect-input.png differ diff --git a/.lostpixel/baseline/components-primitives-dnd-canvas--canvas.png b/.lostpixel/baseline/components-primitives-dnd-canvas--canvas.png new file mode 100644 index 0000000000..dbdec2b55b Binary files /dev/null and b/.lostpixel/baseline/components-primitives-dnd-canvas--canvas.png differ diff --git a/.lostpixel/baseline/components-primitives-dnd-sortable-list--sortable-list.png b/.lostpixel/baseline/components-primitives-dnd-sortable-list--sortable-list.png new file mode 100644 index 0000000000..ec93b82ea9 Binary files /dev/null and b/.lostpixel/baseline/components-primitives-dnd-sortable-list--sortable-list.png differ diff --git a/.lostpixel/baseline/components-select--boundaries.png b/.lostpixel/baseline/components-select--boundaries.png new file mode 100644 index 0000000000..db343c0e62 Binary files /dev/null and b/.lostpixel/baseline/components-select--boundaries.png differ diff --git a/.lostpixel/baseline/components-select--full-width.png b/.lostpixel/baseline/components-select--full-width.png new file mode 100644 index 0000000000..e1f4dae307 Binary files /dev/null and b/.lostpixel/baseline/components-select--full-width.png differ diff --git a/.lostpixel/baseline/components-select--ghost.png b/.lostpixel/baseline/components-select--ghost.png new file mode 100644 index 0000000000..ede0a4853e Binary files /dev/null and b/.lostpixel/baseline/components-select--ghost.png differ diff --git a/.lostpixel/baseline/components-select--simple.png b/.lostpixel/baseline/components-select--simple.png new file mode 100644 index 0000000000..8c0544c377 Binary files /dev/null and b/.lostpixel/baseline/components-select--simple.png differ diff --git a/.lostpixel/baseline/components-select--with-complex-items.png b/.lostpixel/baseline/components-select--with-complex-items.png new file mode 100644 index 0000000000..827ce30464 Binary files /dev/null and b/.lostpixel/baseline/components-select--with-complex-items.png differ diff --git a/.lostpixel/baseline/components-text--label.png b/.lostpixel/baseline/components-text--label.png new file mode 100644 index 0000000000..0c2183aef8 Binary files /dev/null and b/.lostpixel/baseline/components-text--label.png differ diff --git a/.lostpixel/baseline/components-text--mono.png b/.lostpixel/baseline/components-text--mono.png new file mode 100644 index 0000000000..deadaefed4 Binary files /dev/null and b/.lostpixel/baseline/components-text--mono.png differ diff --git a/.lostpixel/baseline/components-text--regular.png b/.lostpixel/baseline/components-text--regular.png new file mode 100644 index 0000000000..1a02bb4ea1 Binary files /dev/null and b/.lostpixel/baseline/components-text--regular.png differ diff --git a/.lostpixel/baseline/components-text--tiny.png b/.lostpixel/baseline/components-text--tiny.png new file mode 100644 index 0000000000..ea4edee218 Binary files /dev/null and b/.lostpixel/baseline/components-text--tiny.png differ diff --git a/.lostpixel/baseline/components-text--title.png b/.lostpixel/baseline/components-text--title.png new file mode 100644 index 0000000000..e7f5e95c06 Binary files /dev/null and b/.lostpixel/baseline/components-text--title.png differ diff --git a/.lostpixel/baseline/components-text--unit.png b/.lostpixel/baseline/components-text--unit.png new file mode 100644 index 0000000000..bbc0b9c84b Binary files /dev/null and b/.lostpixel/baseline/components-text--unit.png differ diff --git a/.lostpixel/baseline/components-text-field--click-capture.png b/.lostpixel/baseline/components-text-field--click-capture.png new file mode 100644 index 0000000000..3511c42f5b Binary files /dev/null and b/.lostpixel/baseline/components-text-field--click-capture.png differ diff --git a/.lostpixel/baseline/components-text-field--default.png b/.lostpixel/baseline/components-text-field--default.png new file mode 100644 index 0000000000..f7db5735a2 Binary files /dev/null and b/.lostpixel/baseline/components-text-field--default.png differ diff --git a/.lostpixel/baseline/components-text-field--focus-events.png b/.lostpixel/baseline/components-text-field--focus-events.png new file mode 100644 index 0000000000..5542e8888a Binary files /dev/null and b/.lostpixel/baseline/components-text-field--focus-events.png differ diff --git a/.lostpixel/baseline/components-text-field--interactive.png b/.lostpixel/baseline/components-text-field--interactive.png new file mode 100644 index 0000000000..ce559ea3f9 Binary files /dev/null and b/.lostpixel/baseline/components-text-field--interactive.png differ diff --git a/.lostpixel/baseline/components-text-field--layout.png b/.lostpixel/baseline/components-text-field--layout.png new file mode 100644 index 0000000000..8dfadf669c Binary files /dev/null and b/.lostpixel/baseline/components-text-field--layout.png differ diff --git a/.lostpixel/baseline/components-text-field--native-props.png b/.lostpixel/baseline/components-text-field--native-props.png new file mode 100644 index 0000000000..6f0764f33b Binary files /dev/null and b/.lostpixel/baseline/components-text-field--native-props.png differ diff --git a/.lostpixel/baseline/components-text-field--prefix-suffix.png b/.lostpixel/baseline/components-text-field--prefix-suffix.png new file mode 100644 index 0000000000..6cbb07805a Binary files /dev/null and b/.lostpixel/baseline/components-text-field--prefix-suffix.png differ diff --git a/.lostpixel/baseline/components-text-field--state.png b/.lostpixel/baseline/components-text-field--state.png new file mode 100644 index 0000000000..c770474c3a Binary files /dev/null and b/.lostpixel/baseline/components-text-field--state.png differ diff --git a/.lostpixel/baseline/components-text-field--variants.png b/.lostpixel/baseline/components-text-field--variants.png new file mode 100644 index 0000000000..f7db5735a2 Binary files /dev/null and b/.lostpixel/baseline/components-text-field--variants.png differ diff --git a/.lostpixel/baseline/components-tree--stress-test.png b/.lostpixel/baseline/components-tree--stress-test.png new file mode 100644 index 0000000000..fc1ba957d5 Binary files /dev/null and b/.lostpixel/baseline/components-tree--stress-test.png differ diff --git a/.lostpixel/baseline/numeric-scrub-control--numeric-input.png b/.lostpixel/baseline/numeric-scrub-control--numeric-input.png new file mode 100644 index 0000000000..22f080c980 Binary files /dev/null and b/.lostpixel/baseline/numeric-scrub-control--numeric-input.png differ diff --git a/apps/designer/app/auth/login.tsx b/apps/designer/app/auth/login.tsx index 0f5dd9a858..ce56a22094 100644 --- a/apps/designer/app/auth/login.tsx +++ b/apps/designer/app/auth/login.tsx @@ -1,7 +1,6 @@ import { LinksFunction, MetaFunction } from "@remix-run/node"; import { Form, useLoaderData } from "@remix-run/react"; import { useState } from "react"; - import { Card, Flex, @@ -11,7 +10,6 @@ import { TextField, } from "@webstudio-is/design-system"; import interStyles from "~/shared/font-faces/inter.css"; - import { GithubIcon, CommitIcon, GoogleIcon } from "@webstudio-is/icons"; import { LoginButton } from "./components/login-button"; import loginStyles from "./login.css"; @@ -86,7 +84,6 @@ export const Login = ({ errorMessage }: { errorMessage: string }) => { }} > { const [editorState, setEditorState] = useState(); - useDebounce( - () => { - if (editorState === undefined) return; - editorState.read(() => { - const updates = toUpdates(editorState.toJSON().root); - onChange(updates); - }); - }, - 500, - [editorState] - ); + const handleChange = useCallback(() => { + if (editorState === undefined) return; + editorState.read(() => { + const updates = toUpdates(editorState.toJSON().root); + onChange(updates); + }); + }, [editorState, onChange]); + + // When we quit editing mode, we need to safe again otherwise it can happen before debounce calls. + useEffect(() => handleChange); + + useDebounce(handleChange, 1000, [handleChange]); return ; }; diff --git a/apps/designer/app/canvas/shared/use-designer-ready.ts b/apps/designer/app/canvas/shared/use-designer-ready.ts index 1a13769ca1..266143e8a0 100644 --- a/apps/designer/app/canvas/shared/use-designer-ready.ts +++ b/apps/designer/app/canvas/shared/use-designer-ready.ts @@ -1,18 +1,30 @@ import { useState } from "react"; +import { useInterval } from "react-use"; import { publish, useSubscribe } from "~/shared/pubsub"; declare module "~/shared/pubsub" { export interface PubsubMap { - designerReady: undefined; - designerReadyAck: undefined; + canvasReady: undefined; + canvasReadyAck: undefined; } } export const useSubscribeDesignerReady = () => { - const [isReady, setIsReady] = useState(false); - useSubscribe("designerReady", () => { - setIsReady(true); - publish({ type: "designerReadyAck" }); + const [isAcknowledged, setIsAcknowledged] = useState(false); + + useInterval( + () => { + // We publish this event to make sure designer is listening to the events, + // otherwise if canvas loads faster than designer, which is possible with SSR, + // we can miss the events and designer will just not connect to the canvas. + publish({ type: "canvasReady" }); + }, + isAcknowledged ? null : 100 + ); + + useSubscribe("canvasReadyAck", () => { + setIsAcknowledged(true); }); - return isReady; + + return isAcknowledged; }; diff --git a/apps/designer/app/config.ts b/apps/designer/app/config.ts index 7bc8840d93..7bcd5c7519 100644 --- a/apps/designer/app/config.ts +++ b/apps/designer/app/config.ts @@ -1,6 +1,4 @@ const config = { - previewPath: "/preview", - canvasPath: "/canvas", designerPath: "/designer", dashboardPath: "/dashboard", loginPath: "/login", diff --git a/apps/designer/app/critical-css.ts b/apps/designer/app/critical-css.ts deleted file mode 100644 index a79e95cd53..0000000000 --- a/apps/designer/app/critical-css.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { - insertCriticalCss as insert, - getCssText as getCanvasCssText, -} from "@webstudio-is/react-sdk"; -import { getCssText as getDesignerCssText } from "@webstudio-is/design-system"; -import config from "./config"; - -const getCssTextFunctions = { - [config.previewPath]: getCanvasCssText, - [config.canvasPath]: getCanvasCssText, - [config.designerPath]: getDesignerCssText, - [config.dashboardPath]: getDesignerCssText, - [config.loginPath]: getDesignerCssText, -}; - -const getCssTextFunction = (url: string) => { - const { pathname } = new URL(url); - let path: keyof typeof getCssTextFunctions; - for (path in getCssTextFunctions) { - if (pathname.indexOf(path) === 0) { - return getCssTextFunctions[path]; - } - } - return getCanvasCssText; -}; - -/** - * This works around the problem with getCssTextfunction being a different one - * depending on createStitches() used in each outlet. - * @todo find a better way - */ -export const insertCriticalCss = (markup: string, url: string): string => { - return insert(markup, getCssTextFunction(url)); -}; diff --git a/apps/designer/app/dashboard/components/card.tsx b/apps/designer/app/dashboard/components/card.tsx index aa1ec752f8..5e4a9f1c58 100644 --- a/apps/designer/app/dashboard/components/card.tsx +++ b/apps/designer/app/dashboard/components/card.tsx @@ -55,7 +55,6 @@ export const SelectProjectCard = ({
{ return [ @@ -73,6 +79,27 @@ const useSetAssets = (assets?: Array) => { }, [assets, setAssets]); }; +const useSetProject = (project: Project) => { + const [, setProject] = useProject(); + useEffect(() => { + setProject(project); + }, [project, setProject]); +}; + +const useSetPages = (pages: Pages) => { + const [, setPages] = usePages(); + useEffect(() => { + setPages(pages); + }, [pages, setPages]); +}; + +const useSetCurrentPageId = (pageId: string) => { + const [, setCurrentPageId] = useCurrentPageId(); + useEffect(() => { + setCurrentPageId(pageId); + }, [pageId, setCurrentPageId]); +}; + const useNavigatorLayout = () => { // We need to render the detached state only once the setting was actually loaded from local storage. // Otherwise we may show the detached state because its the default and then hide it immediately. @@ -80,20 +107,9 @@ const useNavigatorLayout = () => { return isLoaded ? clientSettings.navigatorLayout : "docked"; }; -const usePublishDesignerReady = (publish: Publish) => { - const [isAcknowledged, setIsAcknowledged] = useState(false); - - useInterval( - () => { - // We publish this even to let canvas know that we are now listening to the events, otherwise if canvas loads faster than designer, which is possible with SSR, - // we can miss the events and designer will just not connect to the canvas. - publish({ type: "designerReady" }); - }, - isAcknowledged ? null : 100 - ); - - useSubscribe("designerReadyAck", () => { - setIsAcknowledged(true); +export const useSubscribeCanvasReady = (publish: Publish) => { + useSubscribe("canvasReady", () => { + publish({ type: "canvasReadyAck" }); }); }; @@ -241,23 +257,27 @@ const NavigatorPanel = ({ publish, isPreviewMode }: NavigatorPanelProps) => { type DesignerProps = { config: Config; project: Project; - page: Page; + pages: Pages; + pageId: string; }; -export const Designer = ({ config, project, page }: DesignerProps) => { +export const Designer = ({ config, project, pages, pageId }: DesignerProps) => { useSubscribeSyncStatus(); useSubscribeRootInstance(); useSubscribeSelectedInstanceData(); useSubscribeHoveredInstanceData(); useSubscribeBreakpoints(); useSetAssets(project.assets); + useSetProject(project); + useSetPages(pages); + useSetCurrentPageId(pageId); const [publish, publishRef] = usePublish(); const [isPreviewMode] = useIsPreviewMode(); usePublishShortcuts(publish); const onRefReadCanvasWidth = useUpdateCanvasWidth(); const { onRef: onRefReadCanvas, onTransitionEnd } = useReadCanvasRect(); const [dragAndDropState] = useDragAndDropState(); - usePublishDesignerReady(publish); + useSubscribeCanvasReady(publish); const iframeRefCallback = useCallback( (ref) => { @@ -268,6 +288,14 @@ export const Designer = ({ config, project, page }: DesignerProps) => { [publishRef, onRefReadCanvasWidth, onRefReadCanvas] ); + const page = useMemo(() => { + const page = projectUtils.pages.findById(pages, pageId); + if (page === undefined) { + throw new Error(`Page with id ${pageId} not found`); + } + return page; + }, [pages, pageId]); + return ( { { - + { setCanvasWidth(Math.max(selectedBreakpoint.minWidth, minWidth)); }, [selectedBreakpoint, setCanvasWidth]); - useSubscribe("canvasWidth", setCanvasWidth); + // This fallback is needed for cases when something unexpected loads in the iframe. + // In that case the width remains 0, and user is unable to see what has loaded, + // in particular any error messages. + // The delay is used to make sure we don't set the fallback width too early, + // because when canvas loads normally this will cause a jump in the width. + useEffect(() => { + if (canvasWidth === 0) { + const timeout = setTimeout(() => { + setCanvasWidth(600); + }, 3000); + return () => clearTimeout(timeout); + } + }, [canvasWidth, setCanvasWidth]); // Set the initial canvas width based on the selected breakpoint upper bound, which starts where the next breakpoint begins. return useCallback( diff --git a/apps/designer/app/designer/features/props-panel/props-panel.tsx b/apps/designer/app/designer/features/props-panel/props-panel.tsx index c16157cf18..831b7f3927 100644 --- a/apps/designer/app/designer/features/props-panel/props-panel.tsx +++ b/apps/designer/app/designer/features/props-panel/props-panel.tsx @@ -10,19 +10,100 @@ import type { SelectedInstanceData } from "~/shared/canvas-components"; import { Box, Button, - Combobox, - ComboboxTextField, - ComboboxPopperContent, Grid, + TextField, Tooltip, + useCombobox, + ComboboxPopper, + ComboboxPopperContent, + ComboboxPopperAnchor, + ComboboxListbox, + ComboboxListboxItem, + IconButton, } from "@webstudio-is/design-system"; import { PlusIcon, TrashIcon, ExclamationTriangleIcon, + ChevronDownIcon, } from "@webstudio-is/icons"; import { handleChangePropType, usePropsLogic } from "./use-props-logic"; +type ComboboxProps = { + isReadonly: boolean; + isInvalid: boolean; + items: Array; + value: string; + onItemSelect: (value: string | null) => void; + onSubmit: (value: string) => void; +}; + +const Combobox = ({ + isReadonly, + isInvalid, + items: itemsProp, + value, + onItemSelect, + onSubmit, +}: ComboboxProps) => { + const { + items, + getInputProps, + getComboboxProps, + getToggleButtonProps, + getMenuProps, + getItemProps, + isOpen, + } = useCombobox({ + items: itemsProp, + value, + itemToString: (item) => item ?? "", + onItemSelect, + }); + + return ( + + + + { + if (event.key === "Enter") { + onSubmit(event.currentTarget.value); + } + }, + })} + name="prop" + placeholder="Property" + readOnly={isReadonly} + state={isInvalid ? "invalid" : undefined} + suffix={ + + + + } + /> + + + + {isOpen && + items.map((item, index) => { + return ( + + {item} + + ); + })} + + + + + ); +}; + type PropertyProps = UserProp & { component: Instance["component"]; onChange: handleChangePropType; @@ -33,14 +114,14 @@ const Property = ({ id, prop, value, - required, + required = false, component, onChange, onDelete, }: PropertyProps) => { const meta = componentsMeta[component]; const argType = meta.argTypes?.[prop as keyof typeof meta.argTypes]; - const isInvalidProp = + const isInvalid = prop != null && prop.length > 0 && typeof argType === "undefined" && @@ -56,30 +137,21 @@ const Property = ({ css={{ gridTemplateColumns: "1fr 1fr auto", alignItems: "center" }} > item ?? ""} - onItemSelect={(value) => { - onChange(id, "prop", value as string); + onItemSelect={(value: PropertyProps["value"] | null) => { + if (value !== null) { + onChange(id, "prop", value); + } }} - renderTextField={({ inputProps, toggleProps }) => ( - - )} - renderPopperContent={(props) => ( - - )} + onSubmit={(value) => { + onChange(id, "prop", value); + }} + isInvalid={isInvalid} + isReadonly={required} /> - - {isInvalidProp ? ( + {isInvalid ? ( diff --git a/apps/designer/app/designer/features/sidebar-left/panels/index.ts b/apps/designer/app/designer/features/sidebar-left/panels/index.ts index db4a8af5dd..72410a298c 100644 --- a/apps/designer/app/designer/features/sidebar-left/panels/index.ts +++ b/apps/designer/app/designer/features/sidebar-left/panels/index.ts @@ -1,5 +1,6 @@ import * as components from "./components"; import * as navigator from "./navigator"; import * as assets from "./assets"; +import * as pages from "./pages"; -export const panels = { components, navigator, assets } as const; +export const panels = { components, navigator, assets, pages } as const; diff --git a/apps/designer/app/designer/features/sidebar-left/panels/pages/index.ts b/apps/designer/app/designer/features/sidebar-left/panels/pages/index.ts new file mode 100644 index 0000000000..c4e34b2701 --- /dev/null +++ b/apps/designer/app/designer/features/sidebar-left/panels/pages/index.ts @@ -0,0 +1 @@ +export * from "./pages"; diff --git a/apps/designer/app/designer/features/sidebar-left/panels/pages/pages.tsx b/apps/designer/app/designer/features/sidebar-left/panels/pages/pages.tsx new file mode 100644 index 0000000000..72ce1c953d --- /dev/null +++ b/apps/designer/app/designer/features/sidebar-left/panels/pages/pages.tsx @@ -0,0 +1,126 @@ +import { TreeNodeLabel, TreeNode } from "@webstudio-is/design-system"; +import { type Publish } from "~/shared/pubsub"; +import { PageIcon } from "@webstudio-is/icons"; +import type { TabName } from "../../types"; +import { Header } from "../../lib/header"; +import { type Page, type Pages } from "@webstudio-is/project"; +import { useMemo } from "react"; +import { useNavigate } from "react-router-dom"; +import { type Config } from "~/config"; +import { + useCurrentPageId, + usePages, + useProject, +} from "~/designer/shared/nano-states"; + +type TabContentProps = { + onSetActiveTab: (tabName: TabName) => void; + publish: Publish; + config: Config; +}; + +type PagesTreeNode = + | { + // currently used only for root node + type: "folder"; + id: string; + children: PagesTreeNode[]; + } + | { + type: "page"; + id: string; + data: Page; + }; + +const toTreeData = (pages: Pages): PagesTreeNode => { + return { + type: "folder", + id: "root", + children: [pages.homePage, ...pages.pages].map((data) => ({ + type: "page", + id: data.id, + data, + })), + }; +}; + +const staticTreeProps = { + getItemChildren(node: PagesTreeNode) { + if (node.type === "folder") { + return node.children; + } + return []; + }, + getIsExpanded(_node: PagesTreeNode) { + return true; + }, + renderItem(props: { data: PagesTreeNode; isSelected: boolean }) { + if (props.data.type === "folder") { + return null; + } + + return ( + + ); + }, +}; + +const Pages = ({ + onClose, + onSelect, + selectedPageId, +}: { + onClose: () => void; + onSelect: (pageId: string) => void; + selectedPageId: string; +}) => { + const [pages] = usePages(); + const pagesTree = useMemo(() => pages && toTreeData(pages), [pages]); + + if (pagesTree === undefined) { + return null; + } + + return ( + <> +
+ + + ); +}; + +export const TabContent = (props: TabContentProps) => { + const [currentPageId] = useCurrentPageId(); + const [project] = useProject(); + + const navigate = useNavigate(); + const handleSelect = (pageId: string) => { + if (project === undefined) { + return; + } + navigate(`${props.config.designerPath}/${project.id}?pageId=${pageId}`); + }; + + if (currentPageId === undefined) { + return null; + } + + return ( + props.onSetActiveTab("none")} + onSelect={handleSelect} + selectedPageId={currentPageId} + /> + ); +}; + +export const icon = ; diff --git a/apps/designer/app/designer/features/sidebar-left/sidebar-left.tsx b/apps/designer/app/designer/features/sidebar-left/sidebar-left.tsx index 03f82bd628..f82b138aaf 100644 --- a/apps/designer/app/designer/features/sidebar-left/sidebar-left.tsx +++ b/apps/designer/app/designer/features/sidebar-left/sidebar-left.tsx @@ -13,14 +13,16 @@ import { isFeatureEnabled } from "~/shared/feature-flags"; import { useClientSettings } from "~/designer/shared/client-settings"; import { PANEL_WIDTH } from "~/designer/shared/constants"; import { Flex } from "@webstudio-is/design-system"; +import { Config } from "~/config"; const none = { TabContent: () => null }; type SidebarLeftProps = { publish: Publish; + config: Config; }; -export const SidebarLeft = ({ publish }: SidebarLeftProps) => { +export const SidebarLeft = ({ publish, config }: SidebarLeftProps) => { const [dragAndDropState] = useDragAndDropState(); const [activeTab, setActiveTab] = useState("none"); const { TabContent } = activeTab === "none" ? none : panels[activeTab]; @@ -38,6 +40,8 @@ export const SidebarLeft = ({ publish }: SidebarLeftProps) => { switch (panel) { case "assets": return isFeatureEnabled("assets"); + case "pages": + return isFeatureEnabled("pages"); case "navigator": return clientSettings.navigatorLayout === "docked"; } @@ -76,7 +80,11 @@ export const SidebarLeft = ({ publish }: SidebarLeftProps) => { overflow: "auto", }} > - + diff --git a/apps/designer/app/designer/features/style-panel/search.tsx b/apps/designer/app/designer/features/style-panel/search.tsx index 2dba14e608..299ce19933 100644 --- a/apps/designer/app/designer/features/style-panel/search.tsx +++ b/apps/designer/app/designer/features/style-panel/search.tsx @@ -30,7 +30,11 @@ export const Search = ({ onSearch, selectedInstanceData }: SearchProps) => { type="search" value={search} inputRef={inputRef} - prefix={} + prefix={ + + + + } suffix={ search.length > 0 && ( { +const Content = ({ projectId, pagePath }: ShareButtonProps) => { if (typeof location === "undefined") { return null; } const url = new URL( - `${location.protocol}//${location.host}${path}/${projectId}/${pageId}` + `${location.protocol}//${location.host}${ + pagePath || "/" + }?projectId=${projectId}&mode=preview` ); return ( - + diff --git a/apps/designer/app/designer/shared/nano-states/index.ts b/apps/designer/app/designer/shared/nano-states/index.ts index 667f42f760..f0e0e9a4b2 100644 --- a/apps/designer/app/designer/shared/nano-states/index.ts +++ b/apps/designer/app/designer/shared/nano-states/index.ts @@ -6,6 +6,7 @@ import { } from "~/shared/canvas-components"; import { type SyncStatus } from "~/shared/sync"; import { Asset } from "@webstudio-is/asset-uploader"; +import { type Pages, type Project } from "@webstudio-is/project"; const selectedInstanceDataContainer = createValueContainer< SelectedInstanceData | undefined @@ -49,3 +50,12 @@ export const useSelectionRect = () => useValue(selectionRectContainer); const assetsContainer = createValueContainer>([]); export const useAssets = () => useValue(assetsContainer); + +const pagesContainer = createValueContainer(); +export const usePages = () => useValue(pagesContainer); + +const currentPageIdContainer = createValueContainer(); +export const useCurrentPageId = () => useValue(currentPageIdContainer); + +const projectContainer = createValueContainer(); +export const useProject = () => useValue(projectContainer); diff --git a/apps/designer/app/entry.server.tsx b/apps/designer/app/entry.server.tsx index 0d2bdf0cc2..286acca6ae 100644 --- a/apps/designer/app/entry.server.tsx +++ b/apps/designer/app/entry.server.tsx @@ -1,10 +1,10 @@ -import { renderToString } from "react-dom/server"; -import { RemixServer } from "@remix-run/react"; -import { insertCriticalCss } from "./critical-css"; import type { EntryContext } from "@remix-run/node"; import * as Sentry from "@sentry/remix"; import { initSentry } from "./shared/sentry"; import { prisma } from "@webstudio-is/prisma-client"; +import { handleRequest as handleRequestDesigner } from "./shared/remix"; +import { handleRequest as handleRequestCanvas } from "@webstudio-is/react-sdk"; +import { getCanvasRequestParams } from "./shared/router-utils"; initSentry({ integrations: [new Sentry.Integrations.Prisma({ client: prisma })], @@ -16,17 +16,17 @@ export default function handleRequest( responseHeaders: Headers, remixContext: EntryContext ) { - let markup = renderToString( - - ); + let handle = handleRequestDesigner; - markup = insertCriticalCss(markup, request.url); + if ( + remixContext.matches.some( + (match) => + match.route.id === "routes/$" || match.route.id === "routes/index" + ) && + getCanvasRequestParams(request) !== undefined + ) { + handle = handleRequestCanvas; + } - responseHeaders.set("Content-Type", "text/html"); - responseHeaders.set("Accept-CH", "Sec-CH-Prefers-Color-Scheme"); - - return new Response("" + markup, { - status: responseStatusCode, - headers: responseHeaders, - }); + return handle(request, responseStatusCode, responseHeaders, remixContext); } diff --git a/apps/designer/app/routes/$.tsx b/apps/designer/app/routes/$.tsx new file mode 100644 index 0000000000..21ff6aae15 --- /dev/null +++ b/apps/designer/app/routes/$.tsx @@ -0,0 +1,82 @@ +import { type LoaderFunction, redirect, MetaFunction } from "@remix-run/node"; +import { useLoaderData } from "@remix-run/react"; +import { InstanceRoot, Root } from "@webstudio-is/react-sdk"; +import { loadCanvasData, type CanvasData } from "~/shared/db"; +import config from "~/config"; +import { db } from "@webstudio-is/project/index.server"; +import env, { Env } from "~/env.server"; +import { sentryException } from "~/shared/sentry"; +import { Canvas } from "~/canvas"; +import { ErrorMessage } from "~/shared/error"; +import { + type CanvasRouteMode, + getCanvasRequestParams, +} from "~/shared/router-utils"; + +type Data = + | (CanvasData & { env: Env; mode: CanvasRouteMode }) + | { errors: string; env: Env }; + +export const meta: MetaFunction = ({ data }: { data: Data }) => { + if ("errors" in data) { + return { title: "Error" }; + } + const { page } = data; + return { title: page.title, ...page.meta }; +}; + +export const loader: LoaderFunction = async ({ + request, +}): Promise => { + try { + const canvasRequest = getCanvasRequestParams(request); + + if (canvasRequest === undefined) { + return redirect(config.dashboardPath); + } + + const { mode, pathname } = canvasRequest; + + const project = + "projectId" in canvasRequest + ? await db.project.loadById(canvasRequest.projectId) + : await db.project.loadByDomain(canvasRequest.projectDomain); + + if (project === null) { + throw new Error("Project not found"); + } + + const canvasData = await loadCanvasData( + project.id, + mode === "published" ? "prod" : "dev", + pathname + ); + + return { ...canvasData, env, mode }; + } catch (error) { + sentryException({ error }); + return { + errors: error instanceof Error ? error.message : String(error), + env, + }; + } +}; + +const Content = () => { + const data = useLoaderData(); + + if ("errors" in data) { + return ; + } + + const Outlet = + data.mode === "edit" + ? () => + : () => ; + + // @todo This is non-standard for Remix, is there a better way? + // Maybe there is a way to tell remix to use the right outlet somehow and avoid passing it? + return ; +}; + +export default Content; diff --git a/apps/designer/app/routes/canvas/$projectId.$pageId.tsx b/apps/designer/app/routes/canvas/$projectId.$pageId.tsx deleted file mode 100644 index 673acba501..0000000000 --- a/apps/designer/app/routes/canvas/$projectId.$pageId.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./$projectId"; -export { default } from "./$projectId"; diff --git a/apps/designer/app/routes/canvas/$projectId.tsx b/apps/designer/app/routes/canvas/$projectId.tsx deleted file mode 100644 index 590f5dd1c1..0000000000 --- a/apps/designer/app/routes/canvas/$projectId.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useLoaderData } from "@remix-run/react"; -import type { LoaderFunction, MetaFunction } from "@remix-run/node"; -import { Canvas } from "~/canvas"; -import { loadCanvasData, type CanvasData } from "~/shared/db"; -import { ErrorMessage } from "~/shared/error"; -import { sentryException } from "~/shared/sentry"; -import { Root } from "@webstudio-is/react-sdk"; - -type Data = CanvasData | { errors: string }; - -export const meta: MetaFunction = ({ data }: { data: Data }) => { - if ("errors" in data) { - return { title: "Error" }; - } - const { page } = data; - return { title: page.title, ...page.meta }; -}; - -export const loader: LoaderFunction = async ({ params }): Promise => { - try { - if (params.projectId === undefined) { - throw new Error("Missing projectId"); - } - - return loadCanvasData(params.projectId, params.pageId); - } catch (error) { - sentryException({ error }); - return { errors: error instanceof Error ? error.message : String(error) }; - } -}; - -const Outlet = () => { - const data = useLoaderData(); - return ; -}; - -const CanvasRoute = () => { - const data = useLoaderData(); - if ("errors" in data) { - return ; - } - return ; -}; - -export default CanvasRoute; diff --git a/apps/designer/app/routes/dashboard.tsx b/apps/designer/app/routes/dashboard.tsx index 20bd4e9ce0..4a0cb028ab 100644 --- a/apps/designer/app/routes/dashboard.tsx +++ b/apps/designer/app/routes/dashboard.tsx @@ -1,5 +1,5 @@ import type { LoaderFunction, MetaFunction } from "@remix-run/node"; -import { Designer } from "~/shared/documents/designer"; +import { Root } from "~/shared/remix"; import env from "~/env.server"; import { getThemeData } from "~/shared/theme"; @@ -14,4 +14,4 @@ export const meta: MetaFunction = () => { return { title: "Webstudio Dashboard" }; }; -export default Designer; +export default Root; diff --git a/apps/designer/app/routes/designer.tsx b/apps/designer/app/routes/designer.tsx index 7097e1b5cf..44e8680655 100644 --- a/apps/designer/app/routes/designer.tsx +++ b/apps/designer/app/routes/designer.tsx @@ -1,5 +1,5 @@ import type { LoaderFunction, MetaFunction } from "@remix-run/node"; -import { Designer } from "~/shared/documents/designer"; +import { Root } from "~/shared/remix"; import env from "~/env.server"; import { getThemeData } from "~/shared/theme"; @@ -14,4 +14,4 @@ export const meta: MetaFunction = () => { return { title: "Webstudio" }; }; -export default Designer; +export default Root; diff --git a/apps/designer/app/routes/designer/$projectId.$pageId.tsx b/apps/designer/app/routes/designer/$projectId.$pageId.tsx deleted file mode 100644 index 673acba501..0000000000 --- a/apps/designer/app/routes/designer/$projectId.$pageId.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./$projectId"; -export { default } from "./$projectId"; diff --git a/apps/designer/app/routes/designer/$projectId.tsx b/apps/designer/app/routes/designer/$projectId.tsx index f0dd31fae9..7f15cab11b 100644 --- a/apps/designer/app/routes/designer/$projectId.tsx +++ b/apps/designer/app/routes/designer/$projectId.tsx @@ -2,7 +2,7 @@ import { useLoaderData } from "@remix-run/react"; import { LoaderFunction } from "@remix-run/node"; import { Designer, links } from "~/designer"; import { db } from "@webstudio-is/project/index.server"; -import { type Project, type Page, utils } from "@webstudio-is/project"; +import { type Project, type Pages } from "@webstudio-is/project"; import config from "~/config"; import { ErrorMessage } from "~/shared/error"; import { action, useAction } from "./_assets"; @@ -12,12 +12,16 @@ export { action, links }; export const loader: LoaderFunction = async ({ params, + request, }): Promise => { try { if (params.projectId === undefined) { throw new Error("Project id undefined"); } + const url = new URL(request.url); + const pageIdParam = url.searchParams.get("pageId"); + const project = await db.project.loadById(params.projectId); if (project === null) { @@ -26,16 +30,12 @@ export const loader: LoaderFunction = async ({ const devBuild = await db.build.loadByProjectId(project.id, "dev"); - const page = - params.pageId === undefined - ? devBuild.pages.homePage - : utils.pages.findById(devBuild.pages, params.pageId); - - if (page === undefined) { - throw new Error(`Page "${params.pageId}" not found`); - } - - return { config, project, page }; + return { + config, + project, + pages: devBuild.pages, + pageId: pageIdParam || devBuild.pages.homePage.id, + }; } catch (error) { sentryException({ error }); return { errors: error instanceof Error ? error.message : String(error) }; @@ -45,7 +45,8 @@ export const loader: LoaderFunction = async ({ type Data = { config: typeof config; project: Project; - page: Page; + pages: Pages; + pageId: string; }; type Error = { @@ -55,6 +56,7 @@ type Error = { export const DesignerRoute = () => { const data = useLoaderData(); useAction(); + if ("errors" in data) { return ; } diff --git a/apps/designer/app/routes/index.tsx b/apps/designer/app/routes/index.tsx index 7ef1149563..476a48fc1f 100644 --- a/apps/designer/app/routes/index.tsx +++ b/apps/designer/app/routes/index.tsx @@ -1,87 +1,18 @@ -import { type LoaderFunction, redirect } from "@remix-run/node"; -import { useLoaderData } from "@remix-run/react"; -import { type Data, InstanceRoot, Root } from "@webstudio-is/react-sdk"; -import config from "~/config"; -import { db } from "@webstudio-is/project/index.server"; -import env, { Env } from "~/env.server"; +// We want our catch-all route to also handle `/`. +// Unfortunately, Remix doesn't do this by default, +// see https://github.com/remix-run/remix/issues/2098#issuecomment-1049262218 . +// To solve this, we're re-exporting the $.tsx route API in index.tsx -// @todo all this subdomain logic is very hacky +import { LoaderFunction, MetaFunction } from "@remix-run/node"; +import CatchAllContnet, { + loader as catchAllloader, + meta as catchAllmeta, +} from "./$"; -type Error = { errors: string }; -type LoaderReturnProps = Promise< - (Data & { env: Env }) | (Error & { env: Env }) | Response ->; +// We're wrapping functions in order for them to be distinct from the ones in $.tsx. +// If they are the same, Remix may get confused, and don't load data on page transitions. -export const loader: LoaderFunction = async ({ - request, -}): LoaderReturnProps => { - const host = - request.headers.get("x-forwarded-host") || - request.headers.get("host") || - ""; - - const [userDomain, wstdDomain] = host.split("."); - // We render the site from a subdomain - if ( - typeof userDomain === "string" && - (wstdDomain === "wstd" || wstdDomain?.includes("localhost")) - ) { - try { - const project = await db.project.loadByDomain(userDomain); - if (project === null) { - throw new Error(`Unknown domain "${userDomain}"`); - } - - const prodBuild = await db.build.loadByProjectId(project.id, "prod"); - - if (prodBuild === undefined) { - throw new Error(`Site is not published`); - } - - // @todo: use a correct page rather than homePage - - const [tree, props, breakpoints] = await Promise.all([ - db.tree.loadById(prodBuild.pages.homePage.treeId), - db.props.loadByTreeId(prodBuild.pages.homePage.treeId), - db.breakpoints.load(prodBuild.id), - ]); - if (tree === null) { - throw new Error(`Tree ${prodBuild.pages.homePage.treeId} not found`); - } - if (breakpoints === null) { - throw new Error( - `Breakpoints for tree ${prodBuild.pages.homePage.treeId} not found` - ); - } - return { tree, props, breakpoints: breakpoints.values, env }; - } catch (error) { - if (error instanceof Error) { - return { errors: error.message, env }; - } - } - } - - return redirect(config.dashboardPath); -}; - -const Index = () => { - const data = useLoaderData(); - if ("errors" in data) { - return

{data.errors}

; - } - - // We render the site from a subdomain - if (data.tree && data.props) { - const Outlet = () => ; - - // @todo This is non-standard for Remix, is there a better way? - // We need to render essentially the preview route but from the index, - // so we have to know the layout and the outlet from here. - // Maybe there is a way to tell remix to use the right outlet somehow and avoid passing it? - return ; - } - - return null; -}; - -export default Index; +export const meta: MetaFunction = (args) => catchAllmeta(args); +export const loader: LoaderFunction = (args) => catchAllloader(args); +const Content = () => ; +export default Content; diff --git a/apps/designer/app/routes/login.tsx b/apps/designer/app/routes/login.tsx index 99d9febb01..a76cc559f8 100644 --- a/apps/designer/app/routes/login.tsx +++ b/apps/designer/app/routes/login.tsx @@ -1,5 +1,5 @@ import { LoaderFunction, MetaFunction } from "@remix-run/node"; -import { Designer } from "~/shared/documents/designer"; +import { Root } from "~/shared/remix"; import env from "~/env.server"; import { getThemeData } from "~/shared/theme"; @@ -14,4 +14,4 @@ export const meta: MetaFunction = () => { return { title: "Webstudio Login" }; }; -export default Designer; +export default Root; diff --git a/apps/designer/app/routes/preview/$projectId.$pageId.tsx b/apps/designer/app/routes/preview/$projectId.$pageId.tsx deleted file mode 100644 index 673acba501..0000000000 --- a/apps/designer/app/routes/preview/$projectId.$pageId.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./$projectId"; -export { default } from "./$projectId"; diff --git a/apps/designer/app/routes/preview/$projectId.tsx b/apps/designer/app/routes/preview/$projectId.tsx deleted file mode 100644 index 3299a6d2af..0000000000 --- a/apps/designer/app/routes/preview/$projectId.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useLoaderData } from "@remix-run/react"; -import type { LoaderFunction, MetaFunction } from "@remix-run/node"; -import { loadCanvasData, type CanvasData } from "~/shared/db"; -import { InstanceRoot, Root } from "@webstudio-is/react-sdk"; -import { sentryException } from "~/shared/sentry"; - -type Data = CanvasData | { errors: string }; - -export const meta: MetaFunction = ({ data }: { data: Data }) => { - if ("errors" in data) { - return { title: "Error" }; - } - const { page } = data; - return { title: page.title, ...page.meta }; -}; - -export const loader: LoaderFunction = async ({ params }): Promise => { - try { - if (params.projectId === undefined) { - throw new Error("Missing projectId"); - } - - return loadCanvasData(params.projectId, params.pageId); - } catch (error) { - sentryException({ error }); - return { errors: error instanceof Error ? error.message : String(error) }; - } -}; - -const Outlet = () => { - const data = useLoaderData(); - return ; -}; - -const PreviewRoute = () => { - const data = useLoaderData(); - if ("errors" in data) { - return

{data.errors}

; - } - return ; -}; - -export default PreviewRoute; diff --git a/apps/designer/app/services/auth.server.ts b/apps/designer/app/services/auth.server.ts index d1e9bb4f72..23690cdc09 100644 --- a/apps/designer/app/services/auth.server.ts +++ b/apps/designer/app/services/auth.server.ts @@ -1,8 +1,8 @@ import { User } from "@webstudio-is/prisma-client"; import { Authenticator } from "remix-auth"; import { FormStrategy } from "remix-auth-form"; -import { GitHubStrategy } from "remix-auth-github"; -import { GoogleStrategy } from "remix-auth-google"; +import { GitHubStrategy, type GitHubProfile } from "remix-auth-github"; +import { GoogleStrategy, type GoogleProfile } from "remix-auth-google"; import config from "~/config"; import * as db from "~/shared/db"; import { sessionStorage } from "~/services/session.server"; @@ -15,41 +15,57 @@ const url = `${ : `http://localhost:${process.env.PORT || 3000}` }${config.authPath}`; -const github = new GitHubStrategy( - { - clientID: process.env.GH_CLIENT_ID as string, - clientSecret: process.env.GH_CLIENT_SECRET as string, - callbackURL: `${url}${config.githubCallbackPath}`, - }, - async ({ profile }) => { - const user = await db.user.createOrLoginWithGithub(profile); - +const strategyCallback = async ({ + profile, +}: { + profile: GitHubProfile | GoogleProfile; +}) => { + try { + const user = await db.user.createOrLoginWithOAuth(profile); return user; + } catch (error: unknown) { + if (error instanceof Error) { + sentryException({ + error, + extras: { + loginMethod: AUTH_PROVIDERS.LOGIN_DEV, + }, + }); + } + throw error; } -); - -const google = new GoogleStrategy( - { - clientID: process.env.GOOGLE_CLIENT_ID as string, - clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, - callbackURL: `${url}${config.googleCallbackPath}`, - }, - async ({ profile }) => { - const user = await db.user.createOrLoginWithGoogle(profile); - - return user; - } -); +}; // Create an instance of the authenticator, pass a generic with what // strategies will return and will store in the session -export const authenticator = new Authenticator(sessionStorage); +export const authenticator = new Authenticator(sessionStorage, { + throwOnError: true, +}); + if (process.env.GH_CLIENT_ID && process.env.GH_CLIENT_SECRET) { + const github = new GitHubStrategy( + { + clientID: process.env.GH_CLIENT_ID, + clientSecret: process.env.GH_CLIENT_SECRET, + callbackURL: `${url}${config.githubCallbackPath}`, + }, + strategyCallback + ); authenticator.use(github, "github"); } + if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) { + const google = new GoogleStrategy( + { + clientID: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + callbackURL: `${url}${config.googleCallbackPath}`, + }, + strategyCallback + ); authenticator.use(google, "google"); } + if (process.env.DEV_LOGIN === "true") { authenticator.use( new FormStrategy(async ({ form }) => { @@ -68,6 +84,7 @@ if (process.env.DEV_LOGIN === "true") { }, }); } + throw error; } } diff --git a/apps/designer/app/shared/db/canvas.server.ts b/apps/designer/app/shared/db/canvas.server.ts index 1b05f12c13..9ed4fe0fa5 100644 --- a/apps/designer/app/shared/db/canvas.server.ts +++ b/apps/designer/app/shared/db/canvas.server.ts @@ -7,27 +7,28 @@ export type CanvasData = Data & { buildId: Build["id"]; page: Page }; export const loadCanvasData = async ( projectId: Project["id"], - pageId?: Page["id"] + env: "dev" | "prod", + pagePath = "" ): Promise => { - const project = await db.project.loadById(projectId); + const build = + env === "dev" + ? await db.build.loadByProjectId(projectId, "dev") + : await db.build.loadByProjectId(projectId, "prod"); - if (project === null) throw new Error(`Project "${projectId}" not found`); + if (build === undefined) { + throw new Error("The project is not published"); + } - const devBuild = await db.build.loadByProjectId(projectId, "dev"); - - const page = - pageId === undefined - ? devBuild.pages.homePage - : utils.pages.findById(devBuild.pages, pageId); + const page = utils.pages.findByPath(build.pages, pagePath); if (page === undefined) { - throw new Error(`Page "${pageId}" not found`); + throw new Error(`Page "${pagePath}" not found`); } const [tree, props, breakpoints] = await Promise.all([ db.tree.loadById(page.treeId), db.props.loadByTreeId(page.treeId), - db.breakpoints.load(devBuild.id), + db.breakpoints.load(build.id), ]); if (tree === null) { @@ -42,7 +43,7 @@ export const loadCanvasData = async ( tree, props, breakpoints: breakpoints.values, - buildId: devBuild.id, + buildId: build.id, page, }; }; diff --git a/apps/designer/app/shared/db/user.server.ts b/apps/designer/app/shared/db/user.server.ts index e12dbb1e5e..ca944f2d17 100644 --- a/apps/designer/app/shared/db/user.server.ts +++ b/apps/designer/app/shared/db/user.server.ts @@ -1,5 +1,5 @@ -import { GitHubProfile } from "remix-auth-github"; -import { GoogleProfile } from "remix-auth-google"; +import type { GitHubProfile } from "remix-auth-github"; +import type { GoogleProfile } from "remix-auth-google"; import { prisma, User } from "@webstudio-is/prisma-client"; export const createDemoUser = async (userId: string) => { @@ -73,26 +73,13 @@ const genericCreateAccount = async (userData: { return newTeam.users[0]; }; -export const createOrLoginWithGithub = async ( - profile: GitHubProfile +export const createOrLoginWithOAuth = async ( + profile: GoogleProfile | GitHubProfile ): Promise => { const userData = { - email: profile._json.email, + email: (profile.emails ?? [])[0]?.value, username: profile.displayName, - image: profile._json.avatar_url, - provider: profile.provider, - }; - const newUser = await genericCreateAccount(userData); - return newUser; -}; - -export const createOrLoginWithGoogle = async ( - profile: GoogleProfile -): Promise => { - const userData = { - email: profile._json.email, - username: profile.displayName, - image: profile._json.picture, + image: (profile.photos ?? [])[0]?.value, provider: profile.provider, }; const newUser = await genericCreateAccount(userData); diff --git a/apps/designer/app/shared/error/error-message.tsx b/apps/designer/app/shared/error/error-message.tsx index daebed6b5f..7c6b6ddd07 100644 --- a/apps/designer/app/shared/error/error-message.tsx +++ b/apps/designer/app/shared/error/error-message.tsx @@ -1,16 +1,4 @@ -import { useEffect } from "react"; -import { publish } from "~/shared/pubsub"; - -declare module "~/shared/pubsub" { - export interface PubsubMap { - canvasWidth: number; - } -} - export const ErrorMessage = ({ message }: { message: string }) => { - useEffect(() => { - publish({ type: "canvasWidth", payload: 600 }); - }, []); return (

Error

diff --git a/apps/designer/app/shared/feature-flags/flags.ts b/apps/designer/app/shared/feature-flags/flags.ts index 56e8f1d294..32814f8cb7 100644 --- a/apps/designer/app/shared/feature-flags/flags.ts +++ b/apps/designer/app/shared/feature-flags/flags.ts @@ -1,2 +1,3 @@ export const assets = false; export const example = false; +export const pages = false; diff --git a/apps/designer/app/shared/remix/constants.ts b/apps/designer/app/shared/remix/constants.ts new file mode 100644 index 0000000000..b5ddbd71f5 --- /dev/null +++ b/apps/designer/app/shared/remix/constants.ts @@ -0,0 +1 @@ +export const CRITICAL_CSS_MARKER = "__CRITICAL_CSS__"; diff --git a/apps/designer/app/shared/remix/handle-request.server.tsx b/apps/designer/app/shared/remix/handle-request.server.tsx new file mode 100644 index 0000000000..9b72cb7cc7 --- /dev/null +++ b/apps/designer/app/shared/remix/handle-request.server.tsx @@ -0,0 +1,23 @@ +import { renderToString } from "react-dom/server"; +import { RemixServer } from "@remix-run/react"; +import type { EntryContext } from "@remix-run/node"; +import { insertCriticalCss } from "./insert-critical-css"; + +export const handleRequest = ( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext +) => { + const markup = renderToString( + + ); + + responseHeaders.set("Content-Type", "text/html"); + responseHeaders.set("Accept-CH", "Sec-CH-Prefers-Color-Scheme"); + + return new Response("" + insertCriticalCss(markup), { + status: responseStatusCode, + headers: responseHeaders, + }); +}; diff --git a/apps/designer/app/shared/remix/index.ts b/apps/designer/app/shared/remix/index.ts new file mode 100644 index 0000000000..444dfb6c40 --- /dev/null +++ b/apps/designer/app/shared/remix/index.ts @@ -0,0 +1,2 @@ +export * from "./handle-request.server"; +export * from "./root"; diff --git a/apps/designer/app/shared/remix/insert-critical-css.ts b/apps/designer/app/shared/remix/insert-critical-css.ts new file mode 100644 index 0000000000..fda5504048 --- /dev/null +++ b/apps/designer/app/shared/remix/insert-critical-css.ts @@ -0,0 +1,6 @@ +import { flushCss } from "@webstudio-is/design-system"; +import { CRITICAL_CSS_MARKER } from "./constants"; + +export const insertCriticalCss = (markup: string): string => { + return markup.replace(CRITICAL_CSS_MARKER, ``); +}; diff --git a/apps/designer/app/shared/documents/designer.tsx b/apps/designer/app/shared/remix/root.tsx similarity index 79% rename from apps/designer/app/shared/documents/designer.tsx rename to apps/designer/app/shared/remix/root.tsx index 4638c4919a..38a1e662c6 100644 --- a/apps/designer/app/shared/documents/designer.tsx +++ b/apps/designer/app/shared/remix/root.tsx @@ -1,9 +1,9 @@ import { Links, LiveReload, Meta, Outlet, Scripts } from "@remix-run/react"; -import { CriticalCss } from "@webstudio-is/react-sdk"; import { Env } from "~/shared/env"; import { useThemeProps } from "~/shared/theme"; +import { CRITICAL_CSS_MARKER } from "./constants"; -export const Designer = () => { +export const Root = () => { const themeProps = useThemeProps(); return ( @@ -12,7 +12,7 @@ export const Designer = () => { - + {typeof document === "undefined" ? CRITICAL_CSS_MARKER : null} diff --git a/apps/designer/app/shared/router-utils/canvas-request-params.test.ts b/apps/designer/app/shared/router-utils/canvas-request-params.test.ts new file mode 100644 index 0000000000..c09c7af2e3 --- /dev/null +++ b/apps/designer/app/shared/router-utils/canvas-request-params.test.ts @@ -0,0 +1,94 @@ +import { getCanvasRequestParams } from "./canvas-request-params"; + +const makeRequest = (url: string, headers: { [key: string]: string }) => ({ + url, + headers: { + get: (name: string) => (headers[name] === undefined ? null : headers[name]), + }, +}); + +describe("getCanvasRequestParams", () => { + test("returns undefined if the request is not an canvas request", () => { + expect( + getCanvasRequestParams(makeRequest("https://example.com", {})) + ).toBeUndefined(); + }); + + test("detects project domain on localhost via `x-forwarded-host` header", () => { + expect( + getCanvasRequestParams( + makeRequest("https://foo.localhost", { + "x-forwarded-host": "foo.localhost", + }) + ) + ).toMatchInlineSnapshot(` + Object { + "mode": "published", + "pathname": "/", + "projectDomain": "foo", + } + `); + }); + + test("detects project domain on localhost via `host` header", () => { + expect( + getCanvasRequestParams( + makeRequest("https://foo.localhost", { host: "foo.localhost" }) + ) + ).toMatchInlineSnapshot(` + Object { + "mode": "published", + "pathname": "/", + "projectDomain": "foo", + } + `); + }); + + test("detects projectId parameter", () => { + expect( + getCanvasRequestParams( + makeRequest("https://foo.localhost?projectId=bar", {}) + ) + ).toMatchInlineSnapshot(` + Object { + "mode": "published", + "pathname": "/", + "projectId": "bar", + } + `); + }); + + test("detects path", () => { + expect( + getCanvasRequestParams( + makeRequest("https://foo.localhost/some/path?projectId=bar", {}) + )?.pathname + ).toMatchInlineSnapshot(`"/some/path"`); + }); + + test("detects mode", () => { + expect( + getCanvasRequestParams( + makeRequest( + "https://foo.localhost/some/path?projectId=bar&mode=edit", + {} + ) + )?.mode + ).toMatchInlineSnapshot(`"edit"`); + + expect( + getCanvasRequestParams( + makeRequest( + "https://foo.localhost/some/path?projectId=bar&mode=preview", + {} + ) + )?.mode + ).toMatchInlineSnapshot(`"preview"`); + + expect( + getCanvasRequestParams( + makeRequest("https://foo.localhost/some/path?projectId=bar", {}) + )?.mode + ).toMatchInlineSnapshot(`"published"`); + }); +}); diff --git a/apps/designer/app/shared/router-utils/canvas-request-params.ts b/apps/designer/app/shared/router-utils/canvas-request-params.ts new file mode 100644 index 0000000000..bc10e28443 --- /dev/null +++ b/apps/designer/app/shared/router-utils/canvas-request-params.ts @@ -0,0 +1,63 @@ +export type CanvasRouteMode = "edit" | "preview" | "published"; + +const modes = ["edit", "preview", "published"] as CanvasRouteMode[]; + +export const getCanvasRequestParams = (request: { + url: string; + headers: { get: (name: string) => string | null }; +}): + | { + projectId: string; + mode: CanvasRouteMode; + pathname: string; + } + | { + projectDomain: string; + mode: CanvasRouteMode; + pathname: string; + } + | undefined => { + const url = new URL(request.url); + + const pathname = url.pathname; + + const projectId = url.searchParams.get("projectId"); + + let projectDomain = undefined; + if (projectId === null) { + // @todo all this subdomain logic is very hacky + const host = + request.headers.get("x-forwarded-host") || + request.headers.get("host") || + ""; + const [userDomain, wstdDomain] = host.split("."); + if (wstdDomain === "wstd" || wstdDomain?.includes("localhost")) { + projectDomain = userDomain; + } + } + + const modeParam = url.searchParams.get("mode"); + const mode = + modeParam === null ? "published" : modes.find((mode) => mode === modeParam); + if (mode === undefined) { + throw new Error(`Invalid mode "${modeParam}"`); + } + + if (projectId !== null) { + return { + projectId, + mode, + pathname, + }; + } + + if (projectDomain !== undefined) { + return { + projectDomain, + mode, + pathname, + }; + } + + return; +}; diff --git a/apps/designer/app/shared/router-utils/index.ts b/apps/designer/app/shared/router-utils/index.ts new file mode 100644 index 0000000000..79eef16bfe --- /dev/null +++ b/apps/designer/app/shared/router-utils/index.ts @@ -0,0 +1 @@ +export * from "./canvas-request-params"; diff --git a/package.json b/package.json index cedbfb78f5..6183c444a6 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ "format": "prettier --write \"**/*.{ts,tsx,md}\"", "prepare": "husky install", "storybook": "turbo run storybook:run", + "storybook:build": "npm run build && turbo run storybook:build", + "storybook:ds:build": "turbo run storybook:build --filter=@webstudio-is/design-system", "migrations": "cd apps/designer && migrations --dev" }, "devDependencies": { @@ -27,7 +29,7 @@ }, "engines": { "npm": ">=7.0.0", - "node": ">=14 <=16" + "node": "16" }, "dependencies": {}, "packageManager": "yarn@1.22.19", diff --git a/packages/design-system/lostpixel.config.ts b/packages/design-system/lostpixel.config.ts new file mode 100644 index 0000000000..9214fcc2ae --- /dev/null +++ b/packages/design-system/lostpixel.config.ts @@ -0,0 +1,15 @@ +import type { CustomProjectConfig } from "lost-pixel"; +import * as process from "process"; + +export const config: CustomProjectConfig = { + storybookShots: { + storybookUrl: "packages/design-system/storybook-static", + }, + lostPixelProjectId: "cl8a8xmx714904901m9oce4vhqc", + s3: { + endPoint: "ams3.digitaloceanspaces.com", + accessKey: process.env.S3_ACCESS_KEY, + secretKey: process.env.S3_SECRET_KEY, + bucketName: "beta-seven-turtle-time-blue-narrow", + }, +}; diff --git a/packages/design-system/package.json b/packages/design-system/package.json index af8d3695ff..e42dd3a483 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -17,13 +17,15 @@ "devDependencies": { "@storybook/addon-actions": "^6.5.6", "@storybook/addon-essentials": "^6.5.6", - "@storybook/addon-interactions": "^6.5.6", + "@storybook/addon-interactions": "^6.5.12", "@storybook/addon-links": "^6.5.6", "@storybook/builder-webpack4": "^6.5.6", + "@storybook/jest": "^0.0.10", "@storybook/manager-webpack4": "^6.5.6", "@storybook/react": "^6.5.6", - "@storybook/testing-library": "^0.0.11", + "@storybook/testing-library": "^0.0.13", "@webstudio-is/jest-config": "*", + "lost-pixel": "^2.20.0", "tsup": "^6.1.3", "typescript": "4.7.4" }, @@ -60,6 +62,8 @@ "@radix-ui/react-toggle-group": "^1.0.0", "@radix-ui/react-tooltip": "^1.0.0", "@radix-ui/react-use-layout-effect": "^1.0.0", + "@react-aria/interactions": "^3.11.0", + "@react-aria/utils": "^3.13.3", "@stitches/react": "^1.2.8", "@webstudio-is/icons": "*", "react-hot-toast": "^2.3.0" diff --git a/packages/design-system/src/components/button.tsx b/packages/design-system/src/components/button.tsx index eb0394f82d..edee5f240b 100644 --- a/packages/design-system/src/components/button.tsx +++ b/packages/design-system/src/components/button.tsx @@ -25,7 +25,7 @@ export const Button = styled("button", { // Custom height: "$5", px: "$2", - fontFamily: "$untitled", + fontFamily: "$sans", fontSize: "$2", fontWeight: 500, fontVariantNumeric: "tabular-nums", diff --git a/packages/design-system/src/components/combobox.stories.tsx b/packages/design-system/src/components/combobox.stories.tsx index f4eccfd4f3..622ddea45a 100644 --- a/packages/design-system/src/components/combobox.stories.tsx +++ b/packages/design-system/src/components/combobox.stories.tsx @@ -1,71 +1,101 @@ -import { action } from "@storybook/addon-actions"; import { ComponentStory } from "@storybook/react"; -import React from "react"; -import { Combobox, ComboboxTextField } from "./combobox"; +import { MagnifyingGlassIcon } from "@webstudio-is/icons"; +import { useCombobox as useDownshiftCombobox } from "downshift"; +import React, { useCallback } from "react"; +import { TextField } from "./text-field"; +import { Combobox, ComboboxListboxItem, useCombobox } from "./combobox"; +import { Flex } from "./flex"; export default { component: Combobox, }; export const Simple: ComponentStory = () => { - const items = [ - { label: "Apple" }, - { label: "Banana" }, - { label: "Orange" }, - ] as const; - const [value, setValue] = React.useState(); + const items = [{ label: "Apple" }, { label: "Banana" }, { label: "Orange" }]; + const [value, setValue] = React.useState(null); return ( - ); -}; - -export const CustomInput: ComponentStory = () => { - const items = [ - { label: "Apple", value: "apple", disabled: true }, - { label: "Banana", value: "banana" }, - { label: "Orange", value: "orange" }, - ]; - const [value, setValue] = React.useState( - items[0] - ); - - return ( - { - action("Highlight")(item); + onItemSelect={(value) => { + // If the value is cleared, we revert to previous state + if (value !== null) { + setValue(value); + } }} - renderTextField={({ inputProps, toggleProps }) => ( - { - inputProps.onKeyDown?.(event); - switch (event.key) { - case "Enter": { - action("Enter")(inputProps.value); - break; - } - } - }, - onBlur: (event) => { - inputProps.onBlur?.(event); - action("Blur")(inputProps.value); - }, - }} - /> - )} + itemToString={(item) => item?.label ?? ""} /> ); }; + +export const Complex: ComponentStory = () => { + const [value, setValue] = React.useState(null); + + const stateReducer = useCallback((state, actionAndChanges) => { + const { type, changes } = actionAndChanges; + switch (type) { + // on item selection. + case useDownshiftCombobox.stateChangeTypes.ItemClick: + case useDownshiftCombobox.stateChangeTypes.InputKeyDownEnter: + case useDownshiftCombobox.stateChangeTypes.InputBlur: + case useDownshiftCombobox.stateChangeTypes + .ControlledPropUpdatedSelectedItem: + return { + ...changes, + // if we have a selected item. + ...(changes.selectedItem && { + // we will set the input value to "" (empty string). + inputValue: "", + }), + }; + + // Remove "reset" action + case useDownshiftCombobox.stateChangeTypes.InputKeyDownEscape: { + return { + ...state, + }; + } + + default: + return changes; // otherwise business as usual. + } + }, []); + + const { items, getComboboxProps, getMenuProps, getItemProps, getInputProps } = + useCombobox({ + items: ["Apple", "Banana", "Orange"], + value, + itemToString: (item) => item ?? "", + stateReducer, + onItemSelect: (value) => { + setValue(value); + }, + }); + + return ( + + } + {...getInputProps({})} + /> +
+ Choose an item + + {items.map((item, index) => { + return ( + + {item} + + ); + })} + +
+
+ ); +}; diff --git a/packages/design-system/src/components/combobox.tsx b/packages/design-system/src/components/combobox.tsx index 723d764e0f..e2916240f4 100644 --- a/packages/design-system/src/components/combobox.tsx +++ b/packages/design-system/src/components/combobox.tsx @@ -1,230 +1,146 @@ import { useState, forwardRef, - /* useCallback, -*/ type ComponentProps, type ForwardRefRenderFunction, + useEffect, + useRef, } from "react"; import { CheckIcon, ChevronDownIcon } from "@webstudio-is/icons"; import { Popper, PopperContent, PopperAnchor } from "@radix-ui/react-popper"; -import { useCombobox, type UseComboboxGetItemPropsOptions } from "downshift"; +import { + DownshiftState, + UseComboboxStateChangeOptions, + useCombobox as useDownshiftCombobox, +} from "downshift"; import { matchSorter } from "match-sorter"; import { styled } from "../stitches.config"; import { IconButton } from "./icon-button"; +import { itemCss } from "./menu"; +import { panelStyles } from "./panel"; import { TextField } from "./text-field"; import { Box } from "./box"; import { Grid } from "./grid"; -type Label = string; - -type BaseItem = { label: Label; disabled?: boolean } | Label; - -type ComboboxTextFieldProps = { - inputProps: ComponentProps; - toggleProps: ComponentProps; - highlightedItem?: Item; -}; - -const ComboboxTextFieldBase: ForwardRefRenderFunction< - HTMLDivElement, - ComboboxTextFieldProps -> = ({ inputProps, toggleProps }, ref) => { - return ( - - - - } - {...inputProps} - /> - ); -}; - -export const ComboboxTextField = forwardRef(ComboboxTextFieldBase); - -ComboboxTextField.displayName = "ComboboxTextField"; - -const Listbox = styled("ul", { - margin: 0, +const Listbox = styled("ul", panelStyles, { padding: 0, + margin: 0, overflow: "auto", - minWidth: 124, - maxHeight: 190, - py: "$1", - backgroundColor: "$colors$slate4", - borderRadius: "$1", - boxShadow: - "0px 2px 7px rgba(0, 0, 0, 0.1), 0px 5px 17px rgba(0, 0, 0, 0.15), inset 0 0 1px 1px $colors$slate1, 0 0 0 1px $colors$slate8", - "&:empty": { - display: "none", - }, + // @todo need some non-hardcoded value + maxHeight: 400, + minWidth: 230, }); -const ListboxItem = styled("li", { - all: "unset", - fontSize: "$2", - lineHeight: 1, - color: "$hiContrast", - display: "flex", - alignItems: "center", - height: "$5", - padding: "0 $2", - position: "relative", - "&[aria-selected=true]": { - backgroundColor: "$blue10", - color: "white", - }, +const ListboxItem = styled("li", itemCss, { + padding: 0, + margin: 0, }); -type ListProps = { - containerProps: ComponentProps; - items: ReadonlyArray; - getItemProps: ( - options: UseComboboxGetItemPropsOptions - ) => ComponentProps; - highlightedIndex: number; - selectedItem: Item | null; - itemToString: (item: Item | null) => string; -}; - -export const List = ({ - containerProps, - items, - getItemProps, - highlightedIndex, - selectedItem, - itemToString, -}: ListProps) => { +export const ListboxItemBase: ForwardRefRenderFunction< + HTMLLIElement, + ComponentProps & { + disabled?: boolean; + selected?: boolean; + highlighted?: boolean; + } +> = (props, ref) => { + const { disabled, selected, highlighted, children, ...rest } = props; return ( - - {items.map((item, index) => { - const itemProps: Record = getItemProps({ - item, - index, - key: index, - ...(typeof item === "object" && item.disabled - ? { "data-disabled": true, disabled: true } - : {}), - ...(highlightedIndex === index ? { "data-found": true } : {}), - }); - - return ( - // eslint-disable-next-line react/jsx-key - - - {selectedItem === item && } - {itemToString(item)} - - - ); - })} - + + + {selected && } + {children} + + ); }; +export const ComboboxListbox = Listbox; + +export const ComboboxListboxItem = forwardRef(ListboxItemBase); + +export const ComboboxPopper = Popper; + export const ComboboxPopperContent = PopperContent; -type ComboboxProps = { - name: string; - label?: string; - placeholder?: string; - items: ReadonlyArray; - value?: Item; - onItemSelect?: (value?: Item) => void; - onItemHighlight?: (value?: Item) => void; - itemToString?: (item?: Item | null) => string; - renderTextField?: ( - props: ComponentProps - ) => JSX.Element; - renderList?: (props: ListProps) => JSX.Element; - renderPopperContent?: ( - props: ComponentProps - ) => JSX.Element; +export const ComboboxPopperAnchor = PopperAnchor; + +const useFilter = ({ + items, + itemToString, +}: { + items: Array; + itemToString: (item: Item | null) => string; +}) => { + const [filteredItems, setFilteredItems] = useState>(items); + const cachedItems = useRef(items); + + useEffect(() => { + cachedItems.current = items; + }, [items]); + + const filter = useCallback( + (search?: string) => { + const foundItems: Array = matchSorter(items, search ?? "", { + keys: [(item) => itemToString(item)], + }); + setFilteredItems(foundItems); + }, + [itemToString, items] + ); + + const resetFilter = useCallback(() => { + setFilteredItems(cachedItems.current); + }, []); + + return { + filteredItems, + filter, + resetFilter, + }; }; -export const Combobox = ({ +type useComboboxProps = { + items: Array; + itemToString: (item: Item | null) => string; + value: Item | null; // This is to prevent: "downshift: A component has changed the uncontrolled prop "selectedItem" to be controlled." + onItemSelect?: (value: Item | null) => void; + onItemHighlight?: (value: Item | null) => void; + stateReducer?: ( + state: DownshiftState, + changes: UseComboboxStateChangeOptions + ) => Partial>; +}; + +export const useCombobox = ({ items, value, - name, - placeholder, - itemToString = (item) => - item != null && typeof item == "object" && "label" in item - ? item.label - : item ?? "", + itemToString, onItemSelect, onItemHighlight, - renderTextField = (props) => , - // IMPORTANT! Without Item passed to list typescript is 10x slower! - renderList = (props) => {...props} />, - renderPopperContent = (props) => , -}: ComboboxProps) => { - const [foundItems, setFoundItems] = useState(items); - /* - const stateReducer = useCallback((state, actionAndChanges) => { - const { type, changes } = actionAndChanges; - switch (type) { - // on item selection. - case useCombobox.stateChangeTypes.ItemClick: - case useCombobox.stateChangeTypes.InputKeyDownEnter: - case useCombobox.stateChangeTypes.InputBlur: - case useCombobox.stateChangeTypes.ControlledPropUpdatedSelectedItem: - return { - ...changes, - // if we had an item selected. - ...(changes.selectedItem && { - // we will set the input value to be empty since we display it using prefix - inputValue: "", - }), - }; - // Clear input value on escape - case useCombobox.stateChangeTypes.InputKeyDownEscape: - return { - ...changes, - inputValue: "", - selectedItem: null, - }; - // Reset selectedItem when there is selection and we type something - case useCombobox.stateChangeTypes.InputChange: - return { - ...changes, - selectedItem: null, - }; - default: - return changes; // otherwise business as usual. - } - }, []); -*/ - const { - isOpen, - getToggleButtonProps, - // getLabelProps, - getMenuProps, - getInputProps, - getComboboxProps, - highlightedIndex, - getItemProps, - selectedItem, - } = useCombobox({ - items: foundItems as Item[], - selectedItem: value ?? null, // Avoid downshift warning about switching controlled mode - /* @todo breaks input + stateReducer = (state, { changes }) => changes, +}: useComboboxProps) => { + const { filteredItems, filter, resetFilter } = useFilter({ + items, + itemToString, + }); + + const downshiftProps = useDownshiftCombobox({ + items: filteredItems, + selectedItem: value, // Prevent downshift warning about switching controlled mode stateReducer, - */ itemToString, onInputValueChange({ inputValue }) { - const options = - typeof items[0] === "object" && "label" in items[0] - ? { keys: ["label"] } - : undefined; - const foundItems = matchSorter(items, inputValue ?? "", options); - setFoundItems(foundItems); + filter(inputValue); }, onSelectedItemChange({ selectedItem }) { - onItemSelect?.(selectedItem ?? undefined); + onItemSelect?.(selectedItem ?? null); }, onHighlightedIndexChange({ highlightedIndex }) { if (highlightedIndex !== undefined) { @@ -233,49 +149,97 @@ export const Combobox = ({ }, }); - const inputProps: Record = getInputProps({ - name, - placeholder: selectedItem ? "" : placeholder, // Placeholder should not be visible when we have selected item - prefix: itemToString?.(selectedItem ?? undefined), - /* @todo breaks input - onKeyDown: (event) => { - // When we press Backspace and the input is empty, - // we should to clear the selection - // @todo: it would be much better to handle this in reducer but downshift doesn't handle this event - if (event.key === "Backspace" && selectedItem !== null) { - onItemSelect?.(undefined); - } - }, - */ - }); - const toggleProps: Record = getToggleButtonProps(); - const comboboxProps: Record = getComboboxProps(); - const menuProps: Record = getMenuProps(); - const highlightedItem = foundItems[highlightedIndex]; + const { isOpen, getItemProps, highlightedIndex, selectedItem } = + downshiftProps; + useEffect(() => { + if (isOpen === false) { + resetFilter(); + } + }, [isOpen, resetFilter]); + + const enhancedGetItemProps = useCallback( + (options) => { + return getItemProps({ + highlighted: highlightedIndex === options.index, + // We need to either deep compare objects here or use itemToString to get primitive types + selected: itemToString(selectedItem) === itemToString(options.item), + key: options.id, + ...options, + }); + }, + [getItemProps, highlightedIndex, itemToString, selectedItem] + ); + + return { + ...downshiftProps, + items: filteredItems, + getItemProps: enhancedGetItemProps, + }; +}; + +type ComboboxProps = useComboboxProps & { + name: string; + label?: string; + placeholder?: string; +}; + +export const Combobox = ({ + items, + value = null, + name, + placeholder, + itemToString, + onItemSelect, + onItemHighlight, +}: ComboboxProps) => { + const { + items: foundItems, + getInputProps, + getComboboxProps, + getToggleButtonProps, + getMenuProps, + getItemProps, + isOpen, + } = useCombobox({ + items, + value, + itemToString, + onItemSelect, + onItemHighlight, + }); return ( - + - {renderTextField({ - inputProps, - toggleProps, - highlightedItem, - })} + + + + } + /> - {renderPopperContent({ - style: { zIndex: 1 }, - align: "end", - sideOffset: 8, - children: renderList({ - containerProps: menuProps, - items: isOpen ? foundItems : [], - getItemProps, - highlightedIndex, - selectedItem, - itemToString, - }), - })} + + + {isOpen && + foundItems.map((item, index) => { + return ( + // eslint-disable-next-line react/jsx-key + + {itemToString(item)} + + ); + })} + + ); diff --git a/packages/design-system/src/components/menu.tsx b/packages/design-system/src/components/menu.tsx index 9de5d3b616..a4b7fb09c0 100644 --- a/packages/design-system/src/components/menu.tsx +++ b/packages/design-system/src/components/menu.tsx @@ -9,7 +9,7 @@ export const baseItemCss = css({ display: "flex", alignItems: "center", justifyContent: "space-between", - fontFamily: "$untitled", + fontFamily: "$sans", fontSize: "$1", fontVariantNumeric: "tabular-nums", lineHeight: "1", @@ -23,12 +23,12 @@ export const baseItemCss = css({ export const itemCss = css(baseItemCss, { position: "relative", color: "$hiContrast", - "&:focus, &[data-found]": { + "&:focus, &[data-found], &[aria-selected=true]": { outline: "none", backgroundColor: "$blue10", color: "white", }, - "&[data-disabled]": { + "&[data-disabled], &[aria-disabled]": { color: "$slate9", }, }); diff --git a/packages/design-system/src/components/primitives/dnd/use-drag.ts b/packages/design-system/src/components/primitives/dnd/use-drag.ts index e544e23e07..0d1d1190cf 100644 --- a/packages/design-system/src/components/primitives/dnd/use-drag.ts +++ b/packages/design-system/src/components/primitives/dnd/use-drag.ts @@ -66,6 +66,11 @@ export const useDrag = ( } }; + const handleDragStart = (event: Event) => { + // Prevent default drag behavior. For example, dragging a link. + event.preventDefault(); + }; + const handlePointerDown = (event: PointerEvent) => { if (event.button !== 0 || state.current.status !== "idle") { return; @@ -89,6 +94,7 @@ export const useDrag = ( window.addEventListener("pointermove", handlePointerMove); window.addEventListener("pointerup", handlePointerUp); window.addEventListener("pointercancel", handlePointerCancel); + window.addEventListener("dragstart", handleDragStart); }; const handlePointerMove = (event: PointerEvent) => { @@ -154,6 +160,7 @@ export const useDrag = ( window.removeEventListener("pointermove", handlePointerMove); window.removeEventListener("pointerup", handlePointerUp); window.removeEventListener("pointercancel", handlePointerCancel); + window.removeEventListener("dragstart", handleDragStart); }; const handlePointerUp = (event: PointerEvent) => { diff --git a/packages/design-system/src/components/text-field.stories.tsx b/packages/design-system/src/components/text-field.stories.tsx index 752d5acb2e..f49a1c0adb 100644 --- a/packages/design-system/src/components/text-field.stories.tsx +++ b/packages/design-system/src/components/text-field.stories.tsx @@ -1,6 +1,8 @@ +import { expect } from "@storybook/jest"; +import { userEvent, waitFor, within } from "@storybook/testing-library"; import React from "react"; import { ComponentStory } from "@storybook/react"; -import { BrushIcon, ChevronDownIcon } from "@webstudio-is/icons"; +import { RowGapIcon, ChevronDownIcon } from "@webstudio-is/icons"; import { Button } from "./button"; import { Flex } from "./flex"; import { IconButton } from "./icon-button"; @@ -11,6 +13,10 @@ import { Text } from "./text"; export default { component: TextField, + argTypes: { + onFocus: { action: true }, + onBlur: { action: true }, + }, }; export const Default: ComponentStory = () => { @@ -30,15 +36,6 @@ export const NativeProps: ComponentStory = () => { ); }; -export const Sizes: ComponentStory = () => { - return ( - - - - - ); -}; - export const Variants: ComponentStory = () => { return ( @@ -62,7 +59,7 @@ export const PrefixSuffix: ComponentStory = () => { return ( } + prefix={} suffix={ @@ -71,25 +68,16 @@ export const PrefixSuffix: ComponentStory = () => { /> } + prefix={} suffix={ } /> - } - suffix={ - - - - } - /> } + prefix={} suffix={ @@ -106,7 +94,7 @@ export const Layout: ComponentStory = () => { } + prefix={} suffix={ @@ -141,7 +129,7 @@ export const Layout: ComponentStory = () => { } + prefix={} /> @@ -184,3 +172,55 @@ export const Interactive: ComponentStory = () => { ); }; + +export const FocusEvents: ComponentStory = (args) => { + return ( + + ); +}; +FocusEvents.play = async ({ args, canvasElement }) => { + const canvas = within(canvasElement); + + const el = canvas.getByLabelText("Focus and blur:"); + + await userEvent.tab(); + await waitFor(() => expect(el).toHaveFocus()); + await userEvent.tab(); + await waitFor(() => expect(args.onBlur).not.toHaveBeenCalled()); + await userEvent.tab(); + await waitFor(() => expect(args.onBlur).toHaveBeenCalled()); + + await waitFor(() => expect(args.onFocus).toHaveBeenCalledTimes(1)); + await waitFor(() => expect(args.onBlur).toHaveBeenCalledTimes(1)); +}; + +export const ClickCapture: ComponentStory = (args) => { + return ( + + + + } + suffix={ + + + + } + {...args} + /> + ); +}; +ClickCapture.play = async ({ canvasElement }) => { + const canvas = within(canvasElement); + const input = canvas.getByPlaceholderText("Click on the icon to focus input"); + await userEvent.click(canvas.getByTitle("icon")); + await waitFor(() => expect(input).toHaveFocus()); + await userEvent.click(canvas.getByRole("button")); + await waitFor(() => expect(input).toHaveFocus()); +}; diff --git a/packages/design-system/src/components/text-field.tsx b/packages/design-system/src/components/text-field.tsx index ab2611ca82..ad820e0a11 100644 --- a/packages/design-system/src/components/text-field.tsx +++ b/packages/design-system/src/components/text-field.tsx @@ -1,4 +1,6 @@ +import { mergeRefs } from "@react-aria/utils"; import React from "react"; +import { useFocusWithin } from "@react-aria/interactions"; import { styled } from "../stitches.config"; import { Flex } from "./flex"; @@ -10,6 +12,7 @@ const InputBase = styled("input", { boxSizing: "border-box", fontFamily: "inherit", fontSize: "inherit", + color: "inherit", margin: "0", padding: "0", flexGrow: 1, @@ -41,7 +44,7 @@ const InputBase = styled("input", { }, "&:-webkit-autofill::first-line": { - fontFamily: "$untitled", + fontFamily: "$sans", color: "$hiContrast", }, @@ -67,9 +70,23 @@ const TextFieldBase = styled("div", { color: "$hiContrast", fontVariantNumeric: "tabular-nums", + px: "$2", + borderRadius: "$1", + fontFamily: "$sans", + fontSize: "$1", + height: 28, // @todo waiting for the sizing scale + lineHeight: 1, + "&[data-has-prefix]": { + paddingLeft: 2, + }, + + "&[data-has-suffix]": { + paddingRight: 2, + }, + "&:focus-within": { boxShadow: - "inset 0px 0px 0px 1px $colors$blue8, 0px 0px 0px 1px $colors$blue8", + "inset 0px 0px 0px 1px $colors$blue10, 0px 0px 0px 1px $colors$blue10", }, "&[aria-disabled=true]": { @@ -84,22 +101,6 @@ const TextFieldBase = styled("div", { }, variants: { - size: { - "1": { - px: "$1", - borderRadius: "$1", - fontSize: "$1", - height: "$5", - lineHeight: "$sizes$5", - }, - "2": { - px: "$2", - borderRadius: "$2", - fontSize: "$3", - height: "$6", - lineHeight: "$sizes$6", - }, - }, variant: { ghost: { boxShadow: "none", @@ -112,7 +113,7 @@ const TextFieldBase = styled("div", { "&:focus": { backgroundColor: "$loContrast", boxShadow: - "inset 0px 0px 0px 1px $colors$blue8, 0px 0px 0px 1px $colors$blue8", + "inset 0px 0px 0px 1px $colors$blue8, 0px 0px 0px 1px $colors$blue10", }, "&:disabled": { backgroundColor: "transparent", @@ -139,14 +140,11 @@ const TextFieldBase = styled("div", { }, }, }, - defaultVariants: { - size: "1", - }, }); type TextFieldProps = Pick< React.ComponentProps, - "size" | "variant" | "state" | "css" + "variant" | "state" | "css" > & Omit, "prefix" | "children"> & { inputRef?: React.Ref; @@ -162,23 +160,49 @@ export const TextField = React.forwardRef( css, disabled, inputRef, - size, state, variant, + onFocus, + onBlur, ...textFieldProps } = props; + const internalInputRef = React.useRef(null); + + const focusInnerInput = React.useCallback(() => { + internalInputRef.current?.focus(); + }, [internalInputRef]); + + const { focusWithinProps } = useFocusWithin({ + isDisabled: disabled, + onFocusWithin: (event) => { + // @ts-expect-error Type mismatch from react-aria + onFocus?.(event); + }, + onBlurWithin: (event) => { + // @ts-expect-error Type mismatch from react-aria + onBlur?.(event); + }, + }); + return ( {/* We want input to be the first element in DOM so it receives the focus first */} - + {prefix && ( = { level?: number; animate?: boolean; forceHoverStateAtItem?: string; + + hideRoot?: boolean; }; export const TreeNode = ({ itemData, level = 0, parentIsSelected, + hideRoot, ...commonProps }: TreeNodeProps) => { const { @@ -216,42 +219,44 @@ export const TreeNode = ({ onOpenChange={(isOpen) => setIsExpanded?.(itemData, isOpen)} data-drop-target-id={itemData.id} > - onMouseEnter?.(itemData)} - onMouseLeave={() => onMouseLeave?.(itemData)} - isSelected={isSelected} - parentIsSelected={parentIsSelected} - enableHoverState={forceHoverStateAtItem === undefined} - forceHoverState={forceHoverStateAtItem === itemData.id} - > - {/* We want the main ItemButton to take the entire space, - * and then position the collapsible trigger on top of it using absolute positionning. - * When user clicks anywhere on a tree item, they should either hit the main button or the trigger. - */} - - onMouseEnter?.(itemData)} + onMouseLeave={() => onMouseLeave?.(itemData)} + isSelected={isSelected} + parentIsSelected={parentIsSelected} + enableHoverState={forceHoverStateAtItem === undefined} + forceHoverState={forceHoverStateAtItem === itemData.id} > - - {isAlwaysExpanded === false && } - {renderItem({ data: itemData, isSelected })} - + {/* We want the main ItemButton to take the entire space, + * and then position the collapsible trigger on top of it using absolute positionning. + * When user clicks anywhere on a tree item, they should either hit the main button or the trigger. + */} - {shouldRenderExpandButton && ( - - {isExpanded ? : } - - )} - + + {isAlwaysExpanded === false && } + {renderItem({ data: itemData, isSelected })} + + + {shouldRenderExpandButton && ( + + {isExpanded ? : } + + )} + + )} {isExpandable && ( ({ diff --git a/packages/design-system/src/index.ts b/packages/design-system/src/index.ts index ec369e4873..54bb4137dc 100644 --- a/packages/design-system/src/index.ts +++ b/packages/design-system/src/index.ts @@ -1,16 +1,4 @@ -export { - config, - createTheme, - css, - darkTheme, - getCssText, - globalCss, - keyframes, - reset, - styled, - theme, - type CSS, -} from "./stitches.config"; +export * from "./stitches.config"; export * from "./components/toast"; export * as Collapsible from "@radix-ui/react-collapsible"; diff --git a/packages/design-system/src/stitches.config.ts b/packages/design-system/src/stitches.config.ts index e159c2e7d7..b1906c6d94 100644 --- a/packages/design-system/src/stitches.config.ts +++ b/packages/design-system/src/stitches.config.ts @@ -118,7 +118,7 @@ import { import type * as Stitches from "@stitches/react"; export type { VariantProps } from "@stitches/react"; -export const { +const { styled, css, theme, @@ -414,6 +414,14 @@ export const { export type CSS = Stitches.CSS; +export { styled, css, theme, globalCss, keyframes, config }; + +export const flushCss = () => { + const css = getCssText(); + reset(); + return css; +}; + export const darkTheme = createTheme({ colors: { ...grayDark, diff --git a/packages/http-client/package.json b/packages/http-client/package.json index 13ec25dc5e..1336e98bfb 100644 --- a/packages/http-client/package.json +++ b/packages/http-client/package.json @@ -1,6 +1,6 @@ { "name": "@webstudio-is/http-client", - "version": "0.0.1", + "version": "0.1.1", "description": "Webstudio HTTP Client", "author": "Webstudio ", "homepage": "https://webstudio.is", @@ -13,15 +13,16 @@ "checks": "yarn typecheck && yarn lint" }, "devDependencies": { + "@types/isomorphic-fetch": "^0.0.36", "@webstudio-is/jest-config": "*", - "@webstudio-is/react-sdk": "*", "@webstudio-is/prisma-client": "*", + "@webstudio-is/react-sdk": "*", "tsup": "^6.1.3", "typescript": "4.7.4" }, "peerDependencies": {}, "dependencies": { - "node-fetch": "^3.2.10" + "isomorphic-fetch": "^3.0.0" }, "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/http-client/src/fetch-polyfill.ts b/packages/http-client/src/fetch-polyfill.ts deleted file mode 100644 index a2a7307ea8..0000000000 --- a/packages/http-client/src/fetch-polyfill.ts +++ /dev/null @@ -1,6 +0,0 @@ -import fetch from "node-fetch"; - -if (globalThis.fetch === undefined) { - // @ts-expect-error node-fetch doesn't implement a complete spec - globalThis.fetch = fetch; -} diff --git a/packages/http-client/src/index.test.ts b/packages/http-client/src/index.test.ts index 0381dd59ea..4e1065e9f9 100644 --- a/packages/http-client/src/index.test.ts +++ b/packages/http-client/src/index.test.ts @@ -1,26 +1,24 @@ import { loadProject } from "./index"; -const existingProject = "ab3619d3-831f-46f8-abb6-609558cffd99"; -const notPublishedProject = "7ec397c6-b3d0-4967-9073-9d83623fcf8e"; -const nonExistingProject = "1"; +const existingProjectId = "ab3619d3-831f-46f8-abb6-609558cffd99"; +const notPublishedProjectId = "7ec397c6-b3d0-4967-9073-9d83623fcf8e"; +const apiUrl = "http://localhost:3000"; describe("getProjectDetails", () => { test("loads existing project", async () => { - const response = await loadProject({ projectId: existingProject }); - expect(response.tree.id).toBeTruthy(); - }); - test("loads non-existing project", async () => { const response = await loadProject({ - projectId: nonExistingProject, + apiUrl, + projectId: existingProjectId, }); - expect(response.tree.errors).toBe("Project required"); + expect(response.tree.id).toBeTruthy(); }); test("loads not published project", async () => { const response = await loadProject({ - projectId: notPublishedProject, + apiUrl, + projectId: notPublishedProjectId, }); expect(response.tree.errors).toBe( - "Site needs to be published, production tree ID is null." + "Project 7ec397c6-b3d0-4967-9073-9d83623fcf8e needs to be published first" ); }); }); diff --git a/packages/http-client/src/index.ts b/packages/http-client/src/index.ts index 45ffdbad67..6dec39ec30 100644 --- a/packages/http-client/src/index.ts +++ b/packages/http-client/src/index.ts @@ -1,18 +1,19 @@ -import "./fetch-polyfill"; +import fetch from "isomorphic-fetch"; import type { Includes, Project } from "./index.d"; -const protocol = process.env.NODE_ENV === "production" ? "https" : "http"; - export const loadProject = async ({ + apiUrl, projectId, - host = process.env.DESIGNER_HOST || "localhost:3000", include = { tree: true, props: true, breakpoints: true }, }: { + apiUrl: string; projectId: string; - host?: string; include?: Includes; }): Promise => { - const baseUrl = new URL("/", `${protocol}://${host}`); + if (apiUrl === undefined) { + throw new Error("Webstudio API URL is required."); + } + const baseUrl = new URL(`${apiUrl}`); const treeUrl = new URL(`/rest/tree/${projectId}`, baseUrl); const propsUrl = new URL(`/rest/props/${projectId}`, baseUrl); const breakpointsUrl = new URL(`/rest/breakpoints/${projectId}`, baseUrl); diff --git a/packages/icons/src/index.ts b/packages/icons/src/index.ts index a15ffb67ce..1897831629 100644 --- a/packages/icons/src/index.ts +++ b/packages/icons/src/index.ts @@ -48,3 +48,4 @@ export { TrashIcon } from "./trash"; export { SizeIcon } from "./size"; export { UploadIcon } from "./upload"; export { GearIcon, gearIconCssVars } from "./gear"; +export * from "./page"; diff --git a/packages/icons/src/page.tsx b/packages/icons/src/page.tsx new file mode 100644 index 0000000000..2cd745639b --- /dev/null +++ b/packages/icons/src/page.tsx @@ -0,0 +1,28 @@ +import * as React from "react"; +import { IconProps } from "./types"; + +export const PageIcon = React.forwardRef( + ({ color = "currentColor", ...props }, forwardedRef) => { + return ( + + + + ); + } +); + +PageIcon.displayName = "PageIcon"; diff --git a/packages/project/src/db/build.ts b/packages/project/src/db/build.ts index 0cddcc7c20..523b3a9359 100644 --- a/packages/project/src/db/build.ts +++ b/packages/project/src/db/build.ts @@ -2,7 +2,7 @@ import { prisma, Build as DbBuild } from "@webstudio-is/prisma-client"; import { type Breakpoint } from "@webstudio-is/react-sdk"; import { v4 as uuid } from "uuid"; import * as db from "."; -import { Build, Pages, PagesSchema } from "./types"; +import { Build, Page, Pages, PagesSchema } from "./types"; export const parseBuild = (build: DbBuild): Build => { const pages = PagesSchema.parse(JSON.parse(build.pages)); @@ -78,21 +78,23 @@ const createPages = async (breakpoints: Array) => { }); }; -const clonePages = async (source: Pages) => { - // @todo: clone pages other than home page - - const treeId = source.homePage.treeId; +const clonePage = async (source: Page) => { + const treeId = source.treeId; const tree = await db.tree.clone(treeId); await db.props.clone({ previousTreeId: treeId, nextTreeId: tree.id }); + return { ...source, id: uuid(), treeId: tree.id }; +}; + +const clonePages = async (source: Pages) => { + const clones = []; + for (const page of source.pages) { + clones.push(await clonePage(page)); + } return PagesSchema.parse({ - homePage: { - ...source.homePage, - id: uuid(), - treeId: tree.id, - }, - pages: [], + homePage: await clonePage(source.homePage), + pages: clones, }); }; diff --git a/packages/project/src/shared/pages/find-by-path.ts b/packages/project/src/shared/pages/find-by-path.ts new file mode 100644 index 0000000000..a286071248 --- /dev/null +++ b/packages/project/src/shared/pages/find-by-path.ts @@ -0,0 +1,11 @@ +import { type Pages, type Page } from "../../db/types"; + +export const findByPath = ( + pages: Pages, + pagePath: string +): Page | undefined => { + if (pagePath === "" || pagePath === "/") { + return pages.homePage; + } + return pages.pages.find((page) => page.path === pagePath); +}; diff --git a/packages/project/src/shared/pages/index.ts b/packages/project/src/shared/pages/index.ts index 41138b8354..d4526db190 100644 --- a/packages/project/src/shared/pages/index.ts +++ b/packages/project/src/shared/pages/index.ts @@ -1 +1,2 @@ export * from "./find-by-id"; +export * from "./find-by-path"; diff --git a/packages/react-sdk/package.json b/packages/react-sdk/package.json index 397567ba0d..97423e4f31 100644 --- a/packages/react-sdk/package.json +++ b/packages/react-sdk/package.json @@ -6,7 +6,7 @@ "homepage": "https://webstudio.is", "scripts": { "dev": "tsup src/index.ts --format esm,cjs --watch --out-dir=lib", - "build": "yarn build:mdn-data && yarn build:args && yarn build:lib", + "build": "yarn build:lib", "build:mdn-data": "tsx ./bin/mdn-data.ts ./src/css", "build:args": "tsx ./bin/generate-arg-types.ts './src/components/*.tsx !./src/**/*.stories.tsx !./src/**/*.ws.tsx'", "typecheck": "tsc --noEmit", diff --git a/packages/react-sdk/src/canvas/index.ts b/packages/react-sdk/src/canvas/index.ts deleted file mode 100644 index df456a3704..0000000000 --- a/packages/react-sdk/src/canvas/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./canvas"; diff --git a/packages/react-sdk/src/components/image.props.json b/packages/react-sdk/src/components/image.props.json new file mode 100644 index 0000000000..12e6262e69 --- /dev/null +++ b/packages/react-sdk/src/components/image.props.json @@ -0,0 +1,2533 @@ +{ + "slot": { + "defaultValue": null, + "description": "", + "name": "slot", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "style": { + "defaultValue": null, + "description": "", + "name": "style", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "CSSProperties" + }, + "control": { + "type": "text" + } + }, + "title": { + "defaultValue": null, + "description": "", + "name": "title", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "alt": { + "defaultValue": { + "value": "" + }, + "description": "", + "name": "alt", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "crossOrigin": { + "defaultValue": null, + "description": "", + "name": "crossOrigin", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"\" | \"anonymous\" | \"use-credentials\"", + "value": [ + { + "value": "\"\"" + }, + { + "value": "\"anonymous\"" + }, + { + "value": "\"use-credentials\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["\"\"", "anonymous", "use-credentials"] + }, + "decoding": { + "defaultValue": null, + "description": "", + "name": "decoding", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"async\" | \"auto\" | \"sync\"", + "value": [ + { + "value": "\"async\"" + }, + { + "value": "\"auto\"" + }, + { + "value": "\"sync\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["async", "auto", "sync"] + }, + "height": { + "defaultValue": { + "value": "auto" + }, + "description": "", + "name": "height", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string | number" + }, + "control": { + "type": "text" + } + }, + "loading": { + "defaultValue": { + "value": "lazy" + }, + "description": "", + "name": "loading", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"eager\" | \"lazy\"", + "value": [ + { + "value": "\"eager\"" + }, + { + "value": "\"lazy\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["eager", "lazy"] + }, + "referrerPolicy": { + "defaultValue": null, + "description": "", + "name": "referrerPolicy", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "HTMLAttributeReferrerPolicy", + "value": [ + { + "value": "\"\"" + }, + { + "value": "\"no-referrer\"" + }, + { + "value": "\"no-referrer-when-downgrade\"" + }, + { + "value": "\"origin\"" + }, + { + "value": "\"origin-when-cross-origin\"" + }, + { + "value": "\"same-origin\"" + }, + { + "value": "\"strict-origin\"" + }, + { + "value": "\"strict-origin-when-cross-origin\"" + }, + { + "value": "\"unsafe-url\"" + } + ] + }, + "control": { + "type": "select" + }, + "options": [ + "\"\"", + "no-referrer", + "no-referrer-when-downgrade", + "origin", + "origin-when-cross-origin", + "same-origin", + "strict-origin", + "strict-origin-when-cross-origin", + "unsafe-url" + ] + }, + "sizes": { + "defaultValue": null, + "description": "", + "name": "sizes", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "src": { + "defaultValue": { + "value": "" + }, + "description": "", + "name": "src", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "srcSet": { + "defaultValue": null, + "description": "", + "name": "srcSet", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "useMap": { + "defaultValue": null, + "description": "", + "name": "useMap", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "width": { + "defaultValue": { + "value": "auto" + }, + "description": "", + "name": "width", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "ImgHTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string | number" + }, + "control": { + "type": "text" + } + }, + "defaultChecked": { + "defaultValue": null, + "description": "", + "name": "defaultChecked", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "boolean" + }, + "control": { + "type": "boolean" + } + }, + "defaultValue": { + "defaultValue": null, + "description": "", + "name": "defaultValue", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string | number | readonly string[]" + }, + "control": { + "type": "text" + } + }, + "suppressContentEditableWarning": { + "defaultValue": null, + "description": "", + "name": "suppressContentEditableWarning", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "boolean" + }, + "control": { + "type": "boolean" + } + }, + "suppressHydrationWarning": { + "defaultValue": null, + "description": "", + "name": "suppressHydrationWarning", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "boolean" + }, + "control": { + "type": "boolean" + } + }, + "accessKey": { + "defaultValue": null, + "description": "", + "name": "accessKey", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "className": { + "defaultValue": null, + "description": "", + "name": "className", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "contentEditable": { + "defaultValue": null, + "description": "", + "name": "contentEditable", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish | \"inherit\"" + }, + "control": { + "type": "text" + } + }, + "contextMenu": { + "defaultValue": null, + "description": "", + "name": "contextMenu", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "dir": { + "defaultValue": null, + "description": "", + "name": "dir", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "draggable": { + "defaultValue": null, + "description": "", + "name": "draggable", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "hidden": { + "defaultValue": null, + "description": "", + "name": "hidden", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "boolean" + }, + "control": { + "type": "boolean" + } + }, + "id": { + "defaultValue": null, + "description": "", + "name": "id", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "lang": { + "defaultValue": null, + "description": "", + "name": "lang", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "placeholder": { + "defaultValue": null, + "description": "", + "name": "placeholder", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "spellCheck": { + "defaultValue": null, + "description": "", + "name": "spellCheck", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "tabIndex": { + "defaultValue": null, + "description": "", + "name": "tabIndex", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "translate": { + "defaultValue": null, + "description": "", + "name": "translate", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"yes\" | \"no\"", + "value": [ + { + "value": "\"yes\"" + }, + { + "value": "\"no\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["yes", "no"] + }, + "radioGroup": { + "defaultValue": null, + "description": "", + "name": "radioGroup", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "role": { + "defaultValue": null, + "description": "", + "name": "role", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "AriaRole" + }, + "control": { + "type": "text" + } + }, + "about": { + "defaultValue": null, + "description": "", + "name": "about", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "datatype": { + "defaultValue": null, + "description": "", + "name": "datatype", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "inlist": { + "defaultValue": null, + "description": "", + "name": "inlist", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "any" + }, + "control": { + "type": "text" + } + }, + "prefix": { + "defaultValue": null, + "description": "", + "name": "prefix", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "property": { + "defaultValue": null, + "description": "", + "name": "property", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "resource": { + "defaultValue": null, + "description": "", + "name": "resource", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "typeof": { + "defaultValue": null, + "description": "", + "name": "typeof", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "vocab": { + "defaultValue": null, + "description": "", + "name": "vocab", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "autoCapitalize": { + "defaultValue": null, + "description": "", + "name": "autoCapitalize", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "autoCorrect": { + "defaultValue": null, + "description": "", + "name": "autoCorrect", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "autoSave": { + "defaultValue": null, + "description": "", + "name": "autoSave", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "color": { + "description": "", + "name": "color", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "color" + } + }, + "itemProp": { + "defaultValue": null, + "description": "", + "name": "itemProp", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "itemScope": { + "defaultValue": null, + "description": "", + "name": "itemScope", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "boolean" + }, + "control": { + "type": "boolean" + } + }, + "itemType": { + "defaultValue": null, + "description": "", + "name": "itemType", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "itemID": { + "defaultValue": null, + "description": "", + "name": "itemID", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "itemRef": { + "defaultValue": null, + "description": "", + "name": "itemRef", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "results": { + "defaultValue": null, + "description": "", + "name": "results", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "security": { + "defaultValue": null, + "description": "", + "name": "security", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "unselectable": { + "defaultValue": null, + "description": "", + "name": "unselectable", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"on\" | \"off\"", + "value": [ + { + "value": "\"on\"" + }, + { + "value": "\"off\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["on", "off"] + }, + "inputMode": { + "defaultValue": null, + "description": "Hints at the type of data that might be entered by the user while editing the element or its contents\n@see https://html.spec.whatwg.org/multipage/interaction.html#input-modalities:-the-inputmode-attribute", + "name": "inputMode", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"text\" | \"none\" | \"search\" | \"tel\" | \"url\" | \"email\" | \"numeric\" | \"decimal\"", + "value": [ + { + "value": "\"text\"" + }, + { + "value": "\"none\"" + }, + { + "value": "\"search\"" + }, + { + "value": "\"tel\"" + }, + { + "value": "\"url\"" + }, + { + "value": "\"email\"" + }, + { + "value": "\"numeric\"" + }, + { + "value": "\"decimal\"" + } + ] + }, + "control": { + "type": "select" + }, + "options": [ + "text", + "none", + "search", + "tel", + "url", + "email", + "numeric", + "decimal" + ] + }, + "is": { + "defaultValue": null, + "description": "Specify that a standard HTML element should behave like a defined custom built-in element\n@see https://html.spec.whatwg.org/multipage/custom-elements.html#attr-is", + "name": "is", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "HTMLAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-activedescendant": { + "defaultValue": null, + "description": "Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application.", + "name": "aria-activedescendant", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-atomic": { + "defaultValue": null, + "description": "Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute.", + "name": "aria-atomic", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-autocomplete": { + "defaultValue": null, + "description": "Indicates whether inputting text could trigger display of one or more predictions of the user's intended value for an input and specifies how predictions would be\npresented if they are made.", + "name": "aria-autocomplete", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"list\" | \"none\" | \"inline\" | \"both\"", + "value": [ + { + "value": "\"list\"" + }, + { + "value": "\"none\"" + }, + { + "value": "\"inline\"" + }, + { + "value": "\"both\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["list", "none", "inline", "both"] + }, + "aria-busy": { + "defaultValue": null, + "description": "Indicates an element is being modified and that assistive technologies MAY want to wait until the modifications are complete before exposing them to the user.", + "name": "aria-busy", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-checked": { + "defaultValue": null, + "description": "Indicates the current \"checked\" state of checkboxes, radio buttons, and other widgets.\n@see aria-pressed\n@see aria-selected.", + "name": "aria-checked", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "boolean | \"true\" | \"false\" | \"mixed\"" + }, + "control": { + "type": "text" + } + }, + "aria-colcount": { + "defaultValue": null, + "description": "Defines the total number of columns in a table, grid, or treegrid.\n@see aria-colindex.", + "name": "aria-colcount", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-colindex": { + "defaultValue": null, + "description": "Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid.\n@see aria-colcount\n@see aria-colspan.", + "name": "aria-colindex", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-colspan": { + "defaultValue": null, + "description": "Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid.\n@see aria-colindex\n@see aria-rowspan.", + "name": "aria-colspan", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-controls": { + "defaultValue": null, + "description": "Identifies the element (or elements) whose contents or presence are controlled by the current element.\n@see aria-owns.", + "name": "aria-controls", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-current": { + "defaultValue": null, + "description": "Indicates the element that represents the current item within a container or set of related elements.", + "name": "aria-current", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "boolean | \"time\" | \"true\" | \"false\" | \"page\" | \"step\" | \"location\" | \"date\"" + }, + "control": { + "type": "text" + } + }, + "aria-describedby": { + "defaultValue": null, + "description": "Identifies the element (or elements) that describes the object.\n@see aria-labelledby", + "name": "aria-describedby", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-details": { + "defaultValue": null, + "description": "Identifies the element that provides a detailed, extended description for the object.\n@see aria-describedby.", + "name": "aria-details", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-disabled": { + "defaultValue": null, + "description": "Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable.\n@see aria-hidden\n@see aria-readonly.", + "name": "aria-disabled", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-dropeffect": { + "defaultValue": null, + "description": "Indicates what functions can be performed when a dragged object is released on the drop target.\n@deprecated in ARIA 1.1", + "name": "aria-dropeffect", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"link\" | \"none\" | \"copy\" | \"execute\" | \"move\" | \"popup\"", + "value": [ + { + "value": "\"link\"" + }, + { + "value": "\"none\"" + }, + { + "value": "\"copy\"" + }, + { + "value": "\"execute\"" + }, + { + "value": "\"move\"" + }, + { + "value": "\"popup\"" + } + ] + }, + "control": { + "type": "select" + }, + "options": ["link", "none", "copy", "execute", "move", "popup"] + }, + "aria-errormessage": { + "defaultValue": null, + "description": "Identifies the element that provides an error message for the object.\n@see aria-invalid\n@see aria-describedby.", + "name": "aria-errormessage", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-expanded": { + "defaultValue": null, + "description": "Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed.", + "name": "aria-expanded", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-flowto": { + "defaultValue": null, + "description": "Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion,\nallows assistive technology to override the general default of reading in document source order.", + "name": "aria-flowto", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-grabbed": { + "defaultValue": null, + "description": "Indicates an element's \"grabbed\" state in a drag-and-drop operation.\n@deprecated in ARIA 1.1", + "name": "aria-grabbed", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-haspopup": { + "defaultValue": null, + "description": "Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element.", + "name": "aria-haspopup", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "boolean | \"dialog\" | \"menu\" | \"true\" | \"false\" | \"grid\" | \"listbox\" | \"tree\"" + }, + "control": { + "type": "text" + } + }, + "aria-hidden": { + "defaultValue": null, + "description": "Indicates whether the element is exposed to an accessibility API.\n@see aria-disabled.", + "name": "aria-hidden", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-invalid": { + "defaultValue": null, + "description": "Indicates the entered value does not conform to the format expected by the application.\n@see aria-errormessage.", + "name": "aria-invalid", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "boolean | \"true\" | \"false\" | \"grammar\" | \"spelling\"" + }, + "control": { + "type": "text" + } + }, + "aria-keyshortcuts": { + "defaultValue": null, + "description": "Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element.", + "name": "aria-keyshortcuts", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-label": { + "defaultValue": null, + "description": "Defines a string value that labels the current element.\n@see aria-labelledby.", + "name": "aria-label", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-labelledby": { + "defaultValue": null, + "description": "Identifies the element (or elements) that labels the current element.\n@see aria-describedby.", + "name": "aria-labelledby", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-level": { + "defaultValue": null, + "description": "Defines the hierarchical level of an element within a structure.", + "name": "aria-level", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-live": { + "defaultValue": null, + "description": "Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region.", + "name": "aria-live", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"off\" | \"assertive\" | \"polite\"", + "value": [ + { + "value": "\"off\"" + }, + { + "value": "\"assertive\"" + }, + { + "value": "\"polite\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["off", "assertive", "polite"] + }, + "aria-modal": { + "defaultValue": null, + "description": "Indicates whether an element is modal when displayed.", + "name": "aria-modal", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-multiline": { + "defaultValue": null, + "description": "Indicates whether a text box accepts multiple lines of input or only a single line.", + "name": "aria-multiline", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-multiselectable": { + "defaultValue": null, + "description": "Indicates that the user may select more than one item from the current selectable descendants.", + "name": "aria-multiselectable", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-orientation": { + "defaultValue": null, + "description": "Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous.", + "name": "aria-orientation", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"horizontal\" | \"vertical\"", + "value": [ + { + "value": "\"horizontal\"" + }, + { + "value": "\"vertical\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["horizontal", "vertical"] + }, + "aria-owns": { + "defaultValue": null, + "description": "Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship\nbetween DOM elements where the DOM hierarchy cannot be used to represent the relationship.\n@see aria-controls.", + "name": "aria-owns", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-placeholder": { + "defaultValue": null, + "description": "Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value.\nA hint could be a sample value or a brief description of the expected format.", + "name": "aria-placeholder", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-posinset": { + "defaultValue": null, + "description": "Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM.\n@see aria-setsize.", + "name": "aria-posinset", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-pressed": { + "defaultValue": null, + "description": "Indicates the current \"pressed\" state of toggle buttons.\n@see aria-checked\n@see aria-selected.", + "name": "aria-pressed", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "boolean | \"true\" | \"false\" | \"mixed\"" + }, + "control": { + "type": "text" + } + }, + "aria-readonly": { + "defaultValue": null, + "description": "Indicates that the element is not editable, but is otherwise operable.\n@see aria-disabled.", + "name": "aria-readonly", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-relevant": { + "defaultValue": null, + "description": "Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified.\n@see aria-atomic.", + "name": "aria-relevant", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"text\" | \"additions\" | \"additions removals\" | \"additions text\" | \"all\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\"", + "value": [ + { + "value": "\"text\"" + }, + { + "value": "\"additions\"" + }, + { + "value": "\"additions removals\"" + }, + { + "value": "\"additions text\"" + }, + { + "value": "\"all\"" + }, + { + "value": "\"removals\"" + }, + { + "value": "\"removals additions\"" + }, + { + "value": "\"removals text\"" + }, + { + "value": "\"text additions\"" + }, + { + "value": "\"text removals\"" + } + ] + }, + "control": { + "type": "select" + }, + "options": [ + "text", + "additions", + "additions removals", + "additions text", + "all", + "removals", + "removals additions", + "removals text", + "text additions", + "text removals" + ] + }, + "aria-required": { + "defaultValue": null, + "description": "Indicates that user input is required on the element before a form may be submitted.", + "name": "aria-required", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-roledescription": { + "defaultValue": null, + "description": "Defines a human-readable, author-localized description for the role of an element.", + "name": "aria-roledescription", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + }, + "aria-rowcount": { + "defaultValue": null, + "description": "Defines the total number of rows in a table, grid, or treegrid.\n@see aria-rowindex.", + "name": "aria-rowcount", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-rowindex": { + "defaultValue": null, + "description": "Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid.\n@see aria-rowcount\n@see aria-rowspan.", + "name": "aria-rowindex", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-rowspan": { + "defaultValue": null, + "description": "Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid.\n@see aria-rowindex\n@see aria-colspan.", + "name": "aria-rowspan", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-selected": { + "defaultValue": null, + "description": "Indicates the current \"selected\" state of various widgets.\n@see aria-checked\n@see aria-pressed.", + "name": "aria-selected", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "Booleanish" + }, + "control": { + "type": "boolean" + } + }, + "aria-setsize": { + "defaultValue": null, + "description": "Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM.\n@see aria-posinset.", + "name": "aria-setsize", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-sort": { + "defaultValue": null, + "description": "Indicates if items in a table or grid are sorted in ascending or descending order.", + "name": "aria-sort", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "enum", + "raw": "\"none\" | \"ascending\" | \"descending\" | \"other\"", + "value": [ + { + "value": "\"none\"" + }, + { + "value": "\"ascending\"" + }, + { + "value": "\"descending\"" + }, + { + "value": "\"other\"" + } + ] + }, + "control": { + "type": "radio" + }, + "options": ["none", "ascending", "descending", "other"] + }, + "aria-valuemax": { + "defaultValue": null, + "description": "Defines the maximum allowed value for a range widget.", + "name": "aria-valuemax", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-valuemin": { + "defaultValue": null, + "description": "Defines the minimum allowed value for a range widget.", + "name": "aria-valuemin", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-valuenow": { + "defaultValue": null, + "description": "Defines the current value for a range widget.\n@see aria-valuetext.", + "name": "aria-valuenow", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "number" + }, + "control": { + "type": "number" + } + }, + "aria-valuetext": { + "defaultValue": null, + "description": "Defines the human readable text alternative of aria-valuenow for a range widget.", + "name": "aria-valuetext", + "parent": { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + }, + "declarations": [ + { + "fileName": "webstudio-designer/node_modules/@types/react/index.d.ts", + "name": "AriaAttributes" + } + ], + "required": false, + "type": { + "name": "string" + }, + "control": { + "type": "text" + } + } +} diff --git a/packages/react-sdk/src/components/image.stories.tsx b/packages/react-sdk/src/components/image.stories.tsx new file mode 100644 index 0000000000..d52ca3ad1e --- /dev/null +++ b/packages/react-sdk/src/components/image.stories.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import type { ComponentMeta, ComponentStory } from "@storybook/react"; +import { Image as ImagePrimitive } from "./image"; +import argTypes from "./image.props.json"; + +export default { + title: "Components/Image", + component: ImagePrimitive, + argTypes, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const Image = Template.bind({}); + +Image.args = {}; diff --git a/packages/react-sdk/src/components/image.tsx b/packages/react-sdk/src/components/image.tsx new file mode 100644 index 0000000000..b4011ecb86 --- /dev/null +++ b/packages/react-sdk/src/components/image.tsx @@ -0,0 +1,50 @@ +import React, { forwardRef, type ElementRef, type ComponentProps } from "react"; + +const defaultTag = "img"; + +type ImageProps = ComponentProps; + +export const Image = forwardRef, ImageProps>( + (props, ref) => +); + +Image.defaultProps = { + src: "", + loading: "lazy", + width: "auto", + height: "auto", + alt: "", +}; + +Image.displayName = "Image"; + +const imagePlaceholderSvg = ` + + + + +`; + +// Defining src here prevents analyzer from putting the image into the UI. +// @todo it would be better to have the image hosted like a normal image, +// the problem is inside sdk bundler doesn't know how to do that. +Image.defaultProps.src = `data:image/svg+xml;base64,${btoa( + imagePlaceholderSvg +)}`; diff --git a/packages/react-sdk/src/components/image.ws.tsx b/packages/react-sdk/src/components/image.ws.tsx new file mode 100644 index 0000000000..384d00f272 --- /dev/null +++ b/packages/react-sdk/src/components/image.ws.tsx @@ -0,0 +1,15 @@ +import { ImageIcon } from "@webstudio-is/icons"; +import type { WsComponentMeta } from "./component-type"; +import { Image } from "./image"; + +const meta: WsComponentMeta = { + Icon: ImageIcon, + Component: Image, + canAcceptChildren: false, + isContentEditable: false, + isInlineOnly: false, + isListed: true, + label: "Image", +}; + +export default meta; diff --git a/packages/react-sdk/src/components/index.ts b/packages/react-sdk/src/components/index.ts index 68e139f668..186ff8a309 100644 --- a/packages/react-sdk/src/components/index.ts +++ b/packages/react-sdk/src/components/index.ts @@ -9,3 +9,4 @@ export { default as Italic } from "./italic.ws"; export { default as Button } from "./button.ws"; export { default as Input } from "./input.ws"; export { default as Form } from "./form.ws"; +export { default as Image } from "./image.ws"; diff --git a/packages/react-sdk/src/components/meta.ts b/packages/react-sdk/src/components/meta.ts index 06bda80f11..7a29f4a12c 100644 --- a/packages/react-sdk/src/components/meta.ts +++ b/packages/react-sdk/src/components/meta.ts @@ -9,3 +9,4 @@ export { default as Italic } from "./italic.stories"; export { default as Link } from "./link.stories"; export { default as Paragraph } from "./paragraph.stories"; export { default as TextBlock } from "./text-block.stories"; +export { default as Image } from "./image.stories"; diff --git a/packages/react-sdk/src/index.ts b/packages/react-sdk/src/index.ts index 58ede255ac..7458f83c4d 100644 --- a/packages/react-sdk/src/index.ts +++ b/packages/react-sdk/src/index.ts @@ -6,4 +6,4 @@ export * as componentsMeta from "./components/meta"; export * from "./user-props"; export * from "./pubsub"; export * from "./db"; -export * from "./canvas"; +export * from "./remix"; diff --git a/packages/react-sdk/src/remix/constants.ts b/packages/react-sdk/src/remix/constants.ts new file mode 100644 index 0000000000..b5ddbd71f5 --- /dev/null +++ b/packages/react-sdk/src/remix/constants.ts @@ -0,0 +1 @@ +export const CRITICAL_CSS_MARKER = "__CRITICAL_CSS__"; diff --git a/packages/react-sdk/src/remix/handle-request.server.tsx b/packages/react-sdk/src/remix/handle-request.server.tsx new file mode 100644 index 0000000000..8efe2c9943 --- /dev/null +++ b/packages/react-sdk/src/remix/handle-request.server.tsx @@ -0,0 +1,22 @@ +import { renderToString } from "react-dom/server"; +import { RemixServer } from "@remix-run/react"; +import type { EntryContext } from "@remix-run/node"; +import { insertCriticalCss } from "./insert-critical-css"; + +export const handleRequest = ( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext +) => { + const markup = renderToString( + + ); + + responseHeaders.set("Content-Type", "text/html"); + + return new Response("" + insertCriticalCss(markup), { + status: responseStatusCode, + headers: responseHeaders, + }); +}; diff --git a/packages/react-sdk/src/remix/index.ts b/packages/react-sdk/src/remix/index.ts new file mode 100644 index 0000000000..1287530143 --- /dev/null +++ b/packages/react-sdk/src/remix/index.ts @@ -0,0 +1,2 @@ +export * from "./root"; +export * from "./handle-request.server"; diff --git a/packages/react-sdk/src/remix/insert-critical-css.ts b/packages/react-sdk/src/remix/insert-critical-css.ts new file mode 100644 index 0000000000..9f0bdd20ca --- /dev/null +++ b/packages/react-sdk/src/remix/insert-critical-css.ts @@ -0,0 +1,6 @@ +import { flushCss } from "../stitches"; +import { CRITICAL_CSS_MARKER } from "./constants"; + +export const insertCriticalCss = (markup: string): string => { + return markup.replace(CRITICAL_CSS_MARKER, ``); +}; diff --git a/packages/react-sdk/src/canvas/canvas.tsx b/packages/react-sdk/src/remix/root.tsx similarity index 84% rename from packages/react-sdk/src/canvas/canvas.tsx rename to packages/react-sdk/src/remix/root.tsx index b20e8fb98e..eced0b5951 100644 --- a/packages/react-sdk/src/canvas/canvas.tsx +++ b/packages/react-sdk/src/remix/root.tsx @@ -1,5 +1,5 @@ import { Links, Meta, Outlet as DefaultOutlet } from "@remix-run/react"; -import { CriticalCss } from ".."; +import { CRITICAL_CSS_MARKER } from "./constants"; /** * We are using Outlet prop from index layout when user renders site from a subdomain. @@ -18,7 +18,7 @@ export const Root = ({ - + {typeof document === "undefined" ? CRITICAL_CSS_MARKER : null} diff --git a/packages/react-sdk/src/stitches/critical-css.tsx b/packages/react-sdk/src/stitches/critical-css.tsx deleted file mode 100644 index efd45dda7e..0000000000 --- a/packages/react-sdk/src/stitches/critical-css.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react"; -import { getCssText as getCssTextDefault } from "./css"; - -const criticalCssMarker = "__critical-css__"; - -export const CriticalCss = (): JSX.Element | null => - typeof document === "undefined" ? <>{criticalCssMarker} : null; - -export const insertCriticalCss = ( - markup: string, - getCssText: typeof getCssTextDefault = getCssTextDefault -): string => { - return markup.replace(criticalCssMarker, ``); -}; diff --git a/packages/react-sdk/src/stitches/index.ts b/packages/react-sdk/src/stitches/index.ts index f5c9580245..cba98204fc 100644 --- a/packages/react-sdk/src/stitches/index.ts +++ b/packages/react-sdk/src/stitches/index.ts @@ -1,3 +1,2 @@ export * from "./to-css"; -export * from "./css"; -export * from "./critical-css"; +export * from "./stitches"; diff --git a/packages/react-sdk/src/stitches/css.ts b/packages/react-sdk/src/stitches/stitches.ts similarity index 70% rename from packages/react-sdk/src/stitches/css.ts rename to packages/react-sdk/src/stitches/stitches.ts index 38f559bda1..67662b3eb3 100644 --- a/packages/react-sdk/src/stitches/css.ts +++ b/packages/react-sdk/src/stitches/stitches.ts @@ -1,6 +1,6 @@ import { createStitches, - globalCss, + globalCss as globalCssImport, type CSS, css as createCss, } from "@stitches/core"; @@ -12,7 +12,9 @@ let media = {}; // eslint-disable-next-line @typescript-eslint/no-explicit-any let stitches: any; -export const getCachedConfig = () => { +export { type CSS }; + +const getCachedConfig = () => { if (stitches === undefined) { stitches = createStitches({ media }); } @@ -23,11 +25,15 @@ export const css: typeof createCss = (...args) => { return getCachedConfig().css(...args); }; -export { globalCss }; -export { type CSS }; +export const globalCss: typeof globalCssImport = (...args) => { + return getCachedConfig().globalCss(...args); +}; -export const getCssText = (): string => { - return getCachedConfig().getCssText(); +export const flushCss = () => { + const config = getCachedConfig(); + const css = config.getCssText(); + config.reset(); + return css; }; export const setBreakpoints = (breakpoints: Array) => { diff --git a/packages/react-sdk/src/stitches/to-css.ts b/packages/react-sdk/src/stitches/to-css.ts index 5c4420caa5..4cee92ba01 100644 --- a/packages/react-sdk/src/stitches/to-css.ts +++ b/packages/react-sdk/src/stitches/to-css.ts @@ -1,4 +1,4 @@ -import type { CSS } from "./css"; +import type { CSS } from "./stitches"; import type { StyleProperty, StyleValue, CssRule, Breakpoint } from "../css"; export const toValue = (value: StyleValue): string => { diff --git a/turbo.json b/turbo.json index 7c9bd87ce1..b4ef16d9e1 100644 --- a/turbo.json +++ b/turbo.json @@ -12,6 +12,10 @@ }, "storybook:run": { "cache": false + }, + "storybook:build": { + "dependsOn": ["@webstudio-is/icons#build"], + "cache": false } } } diff --git a/yarn.lock b/yarn.lock index eb1079d87e..100c3d98b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adobe/css-tools@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.0.1.tgz#b38b444ad3aa5fedbb15f2f746dcd934226a12dd" + integrity sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g== + "@ampproject/remapping@^2.1.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" @@ -1979,7 +1984,7 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.17.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.17.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== @@ -2050,6 +2055,13 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + "@design-systems/utils@2.12.0": version "2.12.0" resolved "https://registry.yarnpkg.com/@design-systems/utils/-/utils-2.12.0.tgz#955c108be07cb8f01532207cbfea8f848fa760c9" @@ -2329,6 +2341,13 @@ "@types/node" "*" jest-mock "^27.5.1" +"@jest/expect-utils@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.1.2.tgz#66dbb514d38f7d21456bc774419c9ae5cca3f88d" + integrity sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg== + dependencies: + jest-get-type "^29.0.0" + "@jest/fake-timers@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" @@ -2381,6 +2400,13 @@ terminal-link "^2.0.0" v8-to-istanbul "^8.1.0" +"@jest/schemas@^29.0.0": + version "29.0.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a" + integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== + dependencies: + "@sinclair/typebox" "^0.24.1" + "@jest/source-map@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" @@ -2474,6 +2500,18 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" +"@jest/types@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.1.2.tgz#7442d32b16bcd7592d9614173078b8c334ec730a" + integrity sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg== + dependencies: + "@jest/schemas" "^29.0.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" @@ -2514,6 +2552,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": version "0.3.14" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" @@ -3386,6 +3432,45 @@ dependencies: "@babel/runtime" "^7.13.10" +"@react-aria/interactions@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.11.0.tgz#aa6118af58ff443670152393edab97e403d6d359" + integrity sha512-ZjK4m8u6FlV7Q9/1h9P2Ii6j/NwKR3BmTeGeBQssS2i4dV2pJeOPePnGzVQQGG8FzGQ+TcNRvZPXKaU4AlnBjw== + dependencies: + "@babel/runtime" "^7.6.2" + "@react-aria/utils" "^3.13.3" + "@react-types/shared" "^3.14.1" + +"@react-aria/ssr@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.3.0.tgz#25e81daf0c7a270a4a891159d8d984578e4512d8" + integrity sha512-yNqUDuOVZIUGP81R87BJVi/ZUZp/nYOBXbPsRe7oltJOfErQZD+UezMpw4vM2KRz18cURffvmC8tJ6JTeyDtaQ== + dependencies: + "@babel/runtime" "^7.6.2" + +"@react-aria/utils@^3.13.3": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.13.3.tgz#1b27912e4630f0db6a7b39eb1013f6c4f710075c" + integrity sha512-wqjGNFX4TrXriUU1gvCaoqRhuckdoYogUWN0iyQRkTmzvb7H/NNzQzHou5ggWAdts/NzJUInwKarBWM9hCZZbg== + dependencies: + "@babel/runtime" "^7.6.2" + "@react-aria/ssr" "^3.3.0" + "@react-stately/utils" "^3.5.1" + "@react-types/shared" "^3.14.1" + clsx "^1.1.1" + +"@react-stately/utils@^3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.5.1.tgz#502de762e5d33e892347c5f58053674e06d3bc92" + integrity sha512-INeQ5Er2Jm+db8Py4upKBtgfzp3UYgwXYmbU/XJn49Xw27ktuimH9e37qP3bgHaReb5L3g8IrGs38tJUpnGPHA== + dependencies: + "@babel/runtime" "^7.6.2" + +"@react-types/shared@^3.14.1": + version "3.14.1" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.14.1.tgz#8fe25f729426e8043054e442eb5392364200e028" + integrity sha512-yPPgVRWWanXqbdxFTgJmVwx0JlcnEK3dqkKDIbVk6mxAHvEESI9+oDnHvO8IMHqF+GbrTCzVtAs0zwhYI/uHJA== + "@remix-run/dev@^1.6.4": version "1.6.4" resolved "https://registry.yarnpkg.com/@remix-run/dev/-/dev-1.6.4.tgz#7a2a7fc24e66434c5cf64d6e79a62d35d09b73de" @@ -3686,6 +3771,11 @@ dependencies: "@sentry/cli" "^1.74.4" +"@sinclair/typebox@^0.24.1": + version "0.24.44" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.44.tgz#0a0aa3bf4a155a678418527342a3ee84bd8caa5c" + integrity sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg== + "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" @@ -3832,6 +3922,27 @@ regenerator-runtime "^0.13.7" ts-dedent "^2.0.0" +"@storybook/addon-interactions@^6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/addon-interactions/-/addon-interactions-6.5.12.tgz#b9b7ae50de4c41ea2c9023dcaacf3f318a072ea4" + integrity sha512-wAkKqUX57qZMzgykMIltjDrFfA0II+pKz2SchK4hXHK3/2rtOe+Ah0Sj5nTQo++Ee5oC1PVZWIq/Y1kufCTBJQ== + dependencies: + "@devtools-ds/object-inspector" "^1.1.2" + "@storybook/addons" "6.5.12" + "@storybook/api" "6.5.12" + "@storybook/client-logger" "6.5.12" + "@storybook/components" "6.5.12" + "@storybook/core-common" "6.5.12" + "@storybook/core-events" "6.5.12" + "@storybook/csf" "0.0.2--canary.4566f4d.1" + "@storybook/instrumenter" "6.5.12" + "@storybook/theming" "6.5.12" + core-js "^3.8.2" + global "^4.4.0" + jest-mock "^27.0.6" + polished "^4.2.2" + ts-dedent "^2.2.0" + "@storybook/addon-interactions@^6.5.6", "@storybook/addon-interactions@^6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/addon-interactions/-/addon-interactions-6.5.9.tgz#4356e96beae8f44000955d8870c3acc6c8d1fb3a" @@ -3931,6 +4042,23 @@ prop-types "^15.7.2" regenerator-runtime "^0.13.7" +"@storybook/addons@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.5.12.tgz#891767b5f88ea99b956cf19e9e2893594068adc7" + integrity sha512-y3cgxZq41YGnuIlBJEuJjSFdMsm8wnvlNOGUP9Q+Er2dgfx8rJz4Q22o4hPjpvpaj4XdBtxCJXI2NeFpN59+Cw== + dependencies: + "@storybook/api" "6.5.12" + "@storybook/channels" "6.5.12" + "@storybook/client-logger" "6.5.12" + "@storybook/core-events" "6.5.12" + "@storybook/csf" "0.0.2--canary.4566f4d.1" + "@storybook/router" "6.5.12" + "@storybook/theming" "6.5.12" + "@types/webpack-env" "^1.16.0" + core-js "^3.8.2" + global "^4.4.0" + regenerator-runtime "^0.13.7" + "@storybook/addons@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.5.9.tgz#5a9d7395c579a9cbc44dfc122362fb3c95dfb9d5" @@ -3948,6 +4076,29 @@ global "^4.4.0" regenerator-runtime "^0.13.7" +"@storybook/api@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/api/-/api-6.5.12.tgz#7cc82087fc9298be03f15bf4ab9c4aab294b3bac" + integrity sha512-DuUZmMlQxkFNU9Vgkp9aNfCkAongU76VVmygvCuSpMVDI9HQ2lG0ydL+ppL4XKoSMCCoXTY6+rg4hJANnH+1AQ== + dependencies: + "@storybook/channels" "6.5.12" + "@storybook/client-logger" "6.5.12" + "@storybook/core-events" "6.5.12" + "@storybook/csf" "0.0.2--canary.4566f4d.1" + "@storybook/router" "6.5.12" + "@storybook/semver" "^7.3.2" + "@storybook/theming" "6.5.12" + core-js "^3.8.2" + fast-deep-equal "^3.1.3" + global "^4.4.0" + lodash "^4.17.21" + memoizerific "^1.11.3" + regenerator-runtime "^0.13.7" + store2 "^2.12.0" + telejson "^6.0.8" + ts-dedent "^2.0.0" + util-deprecate "^1.0.2" + "@storybook/api@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/api/-/api-6.5.9.tgz#303733214c9de0422d162f7c54ae05d088b89bf9" @@ -4092,6 +4243,15 @@ global "^4.4.0" telejson "^6.0.8" +"@storybook/channels@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-6.5.12.tgz#98baf01691d263e2ac341853361ec69c1a6621bc" + integrity sha512-X5XaKbe4b7LXJ4sUakBo00x6pXnW78JkOonHoaKoWsccHLlEzwfBZpVVekhVZnqtCoLT23dB8wjKgA71RYWoiw== + dependencies: + core-js "^3.8.2" + ts-dedent "^2.0.0" + util-deprecate "^1.0.2" + "@storybook/channels@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-6.5.9.tgz#abfab89a6587a2688e9926d4aafeb11c9d8b2e79" @@ -4127,6 +4287,14 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" +"@storybook/client-logger@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-6.5.12.tgz#d9809e13dc7939eb61452a5e94b1ccb61c4a022c" + integrity sha512-IrkMr5KZcudX935/C2balFbxLHhkvQnJ78rbVThHDVckQ7l3oIXTh66IMzldeOabVFDZEMiW8AWuGEYof+JtLw== + dependencies: + core-js "^3.8.2" + global "^4.4.0" + "@storybook/client-logger@6.5.9", "@storybook/client-logger@^6.4.0", "@storybook/client-logger@^6.4.0 || >=6.5.0-0": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-6.5.9.tgz#dc1669abe8c45af1cc38f74c6f4b15ff33e63014" @@ -4135,6 +4303,20 @@ core-js "^3.8.2" global "^4.4.0" +"@storybook/components@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-6.5.12.tgz#e137f0683ea92e22de116bfa62cfd65ce4efe01d" + integrity sha512-NAAGl5PDXaHdVLd6hA+ttmLwH3zAVGXeUmEubzKZ9bJzb+duhFKxDa9blM4YEkI+palumvgAMm0UgS7ou680Ig== + dependencies: + "@storybook/client-logger" "6.5.12" + "@storybook/csf" "0.0.2--canary.4566f4d.1" + "@storybook/theming" "6.5.12" + core-js "^3.8.2" + memoizerific "^1.11.3" + qs "^6.10.0" + regenerator-runtime "^0.13.7" + util-deprecate "^1.0.2" + "@storybook/components@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/components/-/components-6.5.9.tgz#97e07ffe11ab76c01ccee380888991bd161f75b2" @@ -4177,6 +4359,62 @@ unfetch "^4.2.0" util-deprecate "^1.0.2" +"@storybook/core-common@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/core-common/-/core-common-6.5.12.tgz#9f8d5cb3812382c49c84dcfb4279a39e228a1b83" + integrity sha512-gG20+eYdIhwQNu6Xs805FLrOCWtkoc8Rt8gJiRt8yXzZh9EZkU4xgCRoCxrrJ03ys/gTiCFbBOfRi749uM3z4w== + dependencies: + "@babel/core" "^7.12.10" + "@babel/plugin-proposal-class-properties" "^7.12.1" + "@babel/plugin-proposal-decorators" "^7.12.12" + "@babel/plugin-proposal-export-default-from" "^7.12.1" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" + "@babel/plugin-proposal-object-rest-spread" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.12.7" + "@babel/plugin-proposal-private-methods" "^7.12.1" + "@babel/plugin-proposal-private-property-in-object" "^7.12.1" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.12.1" + "@babel/plugin-transform-block-scoping" "^7.12.12" + "@babel/plugin-transform-classes" "^7.12.1" + "@babel/plugin-transform-destructuring" "^7.12.1" + "@babel/plugin-transform-for-of" "^7.12.1" + "@babel/plugin-transform-parameters" "^7.12.1" + "@babel/plugin-transform-shorthand-properties" "^7.12.1" + "@babel/plugin-transform-spread" "^7.12.1" + "@babel/preset-env" "^7.12.11" + "@babel/preset-react" "^7.12.10" + "@babel/preset-typescript" "^7.12.7" + "@babel/register" "^7.12.1" + "@storybook/node-logger" "6.5.12" + "@storybook/semver" "^7.3.2" + "@types/node" "^14.0.10 || ^16.0.0" + "@types/pretty-hrtime" "^1.0.0" + babel-loader "^8.0.0" + babel-plugin-macros "^3.0.1" + babel-plugin-polyfill-corejs3 "^0.1.0" + chalk "^4.1.0" + core-js "^3.8.2" + express "^4.17.1" + file-system-cache "^1.0.5" + find-up "^5.0.0" + fork-ts-checker-webpack-plugin "^6.0.4" + fs-extra "^9.0.1" + glob "^7.1.6" + handlebars "^4.7.7" + interpret "^2.2.0" + json5 "^2.1.3" + lazy-universal-dotenv "^3.0.1" + picomatch "^2.3.0" + pkg-dir "^5.0.0" + pretty-hrtime "^1.0.3" + resolve-from "^5.0.0" + slash "^3.0.0" + telejson "^6.0.8" + ts-dedent "^2.0.0" + util-deprecate "^1.0.2" + webpack "4" + "@storybook/core-common@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/core-common/-/core-common-6.5.9.tgz#7ca8258ea2634b1d64695c1e4262f71cc7457989" @@ -4233,6 +4471,13 @@ util-deprecate "^1.0.2" webpack "4" +"@storybook/core-events@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-6.5.12.tgz#28bd727cc4216012409bfac412fcb708346c56bc" + integrity sha512-0AMyMM19R/lHsYRfWqM8zZTXthasTAK2ExkSRzYi2GkIaVMxRKtM33YRwxKIpJ6KmIKIs8Ru3QCXu1mfCmGzNg== + dependencies: + core-js "^3.8.2" + "@storybook/core-events@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-6.5.9.tgz#5b0783c7d22a586c0f5e927a61fe1b1223e19637" @@ -4346,6 +4591,24 @@ lodash "^4.17.21" regenerator-runtime "^0.13.7" +"@storybook/expect@storybook-jest": + version "27.5.2-0" + resolved "https://registry.yarnpkg.com/@storybook/expect/-/expect-27.5.2-0.tgz#131fc4336106805ccd100809a3c2852d31f1da68" + integrity sha512-cP99mhWN/JeCp7VSIiymvj5tmuMY050iFohvp8Zq+kewKsBSZ6/qpTJAGCCZk6pneTcp4S0Fm5BSqyxzbyJ3gw== + dependencies: + "@types/jest" ">=26.0.0" + +"@storybook/instrumenter@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-6.5.12.tgz#acd721c50b65183a53fb5913fe7cdb35b06e2433" + integrity sha512-VMl+Yg6ab79A1VqlhC69sBFI6ySw4Lganqdf9JJf6Y7uNRcZwsjfGpGfYiL4WGH1q72tGiq/25XKGIJV0jgi1Q== + dependencies: + "@storybook/addons" "6.5.12" + "@storybook/client-logger" "6.5.12" + "@storybook/core-events" "6.5.12" + core-js "^3.8.2" + global "^4.4.0" + "@storybook/instrumenter@6.5.9", "@storybook/instrumenter@^6.4.0", "@storybook/instrumenter@^6.4.0 || >=6.5.0-0": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-6.5.9.tgz#885d9dec31b7b7fa6ea29b446105480450e527b8" @@ -4357,6 +4620,16 @@ core-js "^3.8.2" global "^4.4.0" +"@storybook/jest@^0.0.10": + version "0.0.10" + resolved "https://registry.yarnpkg.com/@storybook/jest/-/jest-0.0.10.tgz#4fbc43ebc3ae6cce8232d6bd9b56ef710f481e52" + integrity sha512-qeYLIplpcOUQXboJde5pRCjTvkGmF80jEszRUoNYCNcEPfC2sMK68Wq6Ct8EQj3CoEdJqsK54O2YYh+7D9S+ag== + dependencies: + "@storybook/expect" storybook-jest + "@storybook/instrumenter" "^6.4.0" + "@testing-library/jest-dom" "^5.16.2" + jest-mock "^27.3.0" + "@storybook/manager-webpack4@6.5.9", "@storybook/manager-webpack4@^6.5.6", "@storybook/manager-webpack4@^6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/manager-webpack4/-/manager-webpack4-6.5.9.tgz#c75d2cced4550c8a786f00b0e57b203d613e706c" @@ -4453,6 +4726,17 @@ prettier ">=2.2.1 <=2.3.0" ts-dedent "^2.0.0" +"@storybook/node-logger@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-6.5.12.tgz#0f9efcd1a37c7aae493b22fe33cacca87c135b9b" + integrity sha512-jdLtT3mX5GQKa+0LuX0q0sprKxtCGf6HdXlKZGD5FEuz4MgJUGaaiN0Hgi+U7Z4tVNOtSoIbYBYXHqfUgJrVZw== + dependencies: + "@types/npmlog" "^4.1.2" + chalk "^4.1.0" + core-js "^3.8.2" + npmlog "^5.0.1" + pretty-hrtime "^1.0.3" + "@storybook/node-logger@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-6.5.9.tgz#129cfe0d0f79cab4f6a2ba194d39516680b1626f" @@ -4547,6 +4831,17 @@ util-deprecate "^1.0.2" webpack ">=4.43.0 <6.0.0" +"@storybook/router@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/router/-/router-6.5.12.tgz#58efbc1f2f301c8584802af1c710b2f6f03f948c" + integrity sha512-xHubde9YnBbpkDY5+zGO4Pr6VPxP8H9J2v4OTF3H82uaxCIKR0PKG0utS9pFKIsEiP3aM62Hb9qB8nU+v1nj3w== + dependencies: + "@storybook/client-logger" "6.5.12" + core-js "^3.8.2" + memoizerific "^1.11.3" + qs "^6.10.0" + regenerator-runtime "^0.13.7" + "@storybook/router@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/router/-/router-6.5.9.tgz#4740248f8517425b2056273fb366ace8a17c65e8" @@ -4643,6 +4938,16 @@ "@testing-library/user-event" "^13.2.1" ts-dedent "^2.2.0" +"@storybook/theming@6.5.12": + version "6.5.12" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.5.12.tgz#7df1b52913d49c5e84fc1f2e837c02d9fa8cc639" + integrity sha512-uWOo84qMQ2R6c1C0faZ4Q0nY01uNaX7nXoJKieoiJ6ZqY9PSYxJl1kZLi3uPYnrxLZjzjVyXX8MgdxzbppYItA== + dependencies: + "@storybook/client-logger" "6.5.12" + core-js "^3.8.2" + memoizerific "^1.11.3" + regenerator-runtime "^0.13.7" + "@storybook/theming@6.5.9": version "6.5.9" resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.5.9.tgz#13f60a3a3cd73ceb5caf9f188e1627e79f1891aa" @@ -4701,6 +5006,21 @@ lz-string "^1.4.4" pretty-format "^27.0.2" +"@testing-library/jest-dom@^5.16.2": + version "5.16.5" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e" + integrity sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA== + dependencies: + "@adobe/css-tools" "^4.0.1" + "@babel/runtime" "^7.9.2" + "@types/testing-library__jest-dom" "^5.9.1" + aria-query "^5.0.0" + chalk "^3.0.0" + css.escape "^1.5.1" + dom-accessibility-api "^0.5.6" + lodash "^4.17.15" + redent "^3.0.0" + "@testing-library/react-hooks@^8.0.1": version "8.0.1" resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12" @@ -4740,6 +5060,26 @@ mkdirp "^1.0.4" path-browserify "^1.0.1" +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + "@types/acorn@^4.0.0": version "4.0.6" resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.6.tgz#d61ca5480300ac41a7d973dd5b84d0a591154a22" @@ -4924,6 +5264,11 @@ resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.1.tgz#2d024eace950c836d9e3335a66b97960ae41d022" integrity sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q== +"@types/isomorphic-fetch@^0.0.36": + version "0.0.36" + resolved "https://registry.yarnpkg.com/@types/isomorphic-fetch/-/isomorphic-fetch-0.0.36.tgz#3a6d8f63974baf26b10fd1314db910633108a769" + integrity sha512-ulw4d+vW1HKn4oErSmNN2HYEcHGq0N1C5exlrMM0CRqX1UUpFhGb5lwiom5j9KN3LBJJDLRmYIZz1ghm7FIzZw== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" @@ -4943,6 +5288,14 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/jest@*", "@types/jest@>=26.0.0": + version "29.1.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.1.1.tgz#cf21a0835a1ba9a30ea1966019f1261c6a114c92" + integrity sha512-U9Ey07dGWl6fUFaIaUQUKWG5NoKi/zizeVQCGV8s4nSU0jPgqphVZvS64+8BtWYvrc3ZGw6wo943NSYPxkrp/g== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + "@types/jest@^27.4.0", "@types/jest@^27.4.1": version "27.5.2" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c" @@ -5196,6 +5549,13 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.8.tgz#b94a4391c85666c7b73299fd3ad79d4faa435310" integrity sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ== +"@types/testing-library__jest-dom@^5.9.1": + version "5.14.5" + resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz#d113709c90b3c75fdb127ec338dad7d5f86c974f" + integrity sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ== + dependencies: + "@types/jest" "*" + "@types/uglify-js@*": version "3.16.0" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.16.0.tgz#2cf74a0e6ebb6cd54c0d48e509d5bd91160a9602" @@ -5263,6 +5623,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^17.0.8": + version "17.0.13" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.13.tgz#34cced675ca1b1d51fcf4d34c3c6f0fa142a5c76" + integrity sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@^5.36.2": version "5.36.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.2.tgz#6df092a20e0f9ec748b27f293a12cb39d0c1fe4d" @@ -5773,6 +6140,11 @@ acorn-walk@^7.1.1, acorn-walk@^7.2.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + acorn@^6.4.1: version "6.4.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" @@ -6192,6 +6564,11 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== +async@3.2.4, async@^3.1.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -6225,6 +6602,14 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== +axios@0.27.2, axios@^0.27.0: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + babel-core@^7.0.0-bridge.0: version "7.0.0-bridge.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" @@ -6498,6 +6883,13 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +block-stream2@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/block-stream2/-/block-stream2-2.1.0.tgz#ac0c5ef4298b3857796e05be8ebed72196fa054b" + integrity sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg== + dependencies: + readable-stream "^3.4.0" + bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -6633,6 +7025,11 @@ browser-assert@^1.2.1: resolved "https://registry.yarnpkg.com/browser-assert/-/browser-assert-1.2.1.tgz#9aaa5a2a8c74685c2ae05bfe46efd606f068c200" integrity sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ== +browser-or-node@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-or-node/-/browser-or-node-1.3.0.tgz#f2a4e8568f60263050a6714b2cc236bb976647a7" + integrity sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg== + browser-process-hrtime@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" @@ -6728,6 +7125,11 @@ bson-objectid@^2.0.2, bson-objectid@^2.0.3: resolved "https://registry.yarnpkg.com/bson-objectid/-/bson-objectid-2.0.3.tgz#d840185172846b2f10c42ce2bcdb4a50956a9db5" integrity sha512-WYwVtY9yqk179EPMNuF3vcxufdrGLEo2XwqdRVbfLVe9X6jLt7WKZQgP+ObOcprakBGbHxzl76tgTaieqsH29g== +buffer-crc32@^0.2.13: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -6976,6 +7378,14 @@ chalk@^2.0.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -7255,7 +7665,7 @@ clsx@1.1.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.0.tgz#62937c6adfea771247c34b54d320fb99624f5702" integrity sha512-3avwM37fSK5oP6M5rQ9CNe99lwxhXDOeSWVPAOYF6OazUTgZCMb0yWlJpmdD74REy1gkEaFiub2ULv4fq9GUhA== -clsx@^1.0.4: +clsx@^1.0.4, clsx@^1.1.1: version "1.2.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== @@ -7473,6 +7883,11 @@ constants-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ== +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA== + content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -7642,6 +8057,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -7662,7 +8082,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypto-browserify@^3.11.0: +crypto-browserify@^3.11.0, crypto-browserify@^3.12.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== @@ -7754,6 +8174,11 @@ css-what@^6.0.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -7798,11 +8223,6 @@ data-uri-to-buffer@^3.0.1: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== -data-uri-to-buffer@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b" - integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA== - data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -8041,6 +8461,11 @@ diff-sequences@^27.5.1: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== +diff-sequences@^29.0.0: + version "29.0.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.0.0.tgz#bae49972ef3933556bcb0800b72e8579d19d9e4f" + integrity sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -8088,7 +8513,7 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-accessibility-api@^0.5.9: +dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9: version "0.5.14" resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56" integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg== @@ -8397,6 +8822,11 @@ es5-shim@^4.5.13: resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.6.7.tgz#bc67ae0fc3dd520636e0a1601cc73b450ad3e955" integrity sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ== +es6-error@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== + es6-shim@^0.35.5: version "0.35.6" resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.6.tgz#d10578301a83af2de58b9eadb7c2c9945f7388a0" @@ -9312,6 +9742,17 @@ expect@^27.5.1: jest-matcher-utils "^27.5.1" jest-message-util "^27.5.1" +expect@^29.0.0: + version "29.1.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.1.2.tgz#82f8f28d7d408c7c68da3a386a490ee683e1eced" + integrity sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw== + dependencies: + "@jest/expect-utils" "^29.1.2" + jest-get-type "^29.0.0" + jest-matcher-utils "^29.1.2" + jest-message-util "^29.1.2" + jest-util "^29.1.2" + express@4.17.3: version "4.17.3" resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1" @@ -9476,11 +9917,25 @@ fast-shallow-equal@^1.0.0: resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== +fast-url-parser@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== + dependencies: + punycode "^1.3.2" + fast-xml-parser@3.19.0: version "3.19.0" resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz#cb637ec3f3999f51406dd8ff0e6fc4d83e520d01" integrity sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg== +fast-xml-parser@^3.17.5: + version "3.21.1" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.21.1.tgz#152a1d51d445380f7046b304672dd55d15c9e736" + integrity sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg== + dependencies: + strnum "^1.0.4" + fastest-stable-stringify@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76" @@ -9514,14 +9969,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fetch-blob@^3.1.2, fetch-blob@^3.1.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" - integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== - dependencies: - node-domexception "^1.0.0" - web-streams-polyfill "^3.0.3" - fetch-retry@^5.0.2: version "5.0.3" resolved "https://registry.yarnpkg.com/fetch-retry/-/fetch-retry-5.0.3.tgz#edfa3641892995f9afee94f25b168827aa97fe3d" @@ -9584,6 +10031,11 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +filter-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== + finalhandler@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" @@ -9692,6 +10144,11 @@ focus-lock@^0.8.0: dependencies: tslib "^1.9.3" +follow-redirects@^1.14.9: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + fontkit@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/fontkit/-/fontkit-2.0.2.tgz#ac5384f3ecab8327c6d2ea2e4d384afc544b48fd" @@ -9768,18 +10225,20 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + format@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== -formdata-polyfill@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" - integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== - dependencies: - fetch-blob "^3.1.2" - forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -9837,6 +10296,11 @@ fs-jetpack@^4.3.1: minimatch "^3.0.2" rimraf "^2.6.3" +fs-memo@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fs-memo/-/fs-memo-1.2.0.tgz#a2ec3be606b902077adbb37ec529c5ec5fb2e037" + integrity sha512-YEexkCpL4j03jn5SxaMHqcO6IuWuqm8JFUYhyCep7Ao89JIYmB8xoKhK7zXXJ9cCaNXpyNH5L3QtAmoxjoHW2w== + fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -9974,6 +10438,13 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-port-please@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-2.6.1.tgz#80143de24fcaab39b01df977f66ad967e06b17d1" + integrity sha512-4PDSrL6+cuMM1xs6w36ZIkaKzzE0xzfVBCfebHIJ3FE8iB9oic/ECwPw3iNiD4h1AoJ5XLLBhEviFAVrZsDC5A== + dependencies: + fs-memo "^1.2.0" + get-port@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" @@ -10828,6 +11299,11 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + is-absolute-url@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" @@ -11332,6 +11808,14 @@ isobject@^4.0.0: resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== +isomorphic-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" + integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== + dependencies: + node-fetch "^2.6.1" + whatwg-fetch "^3.4.1" + isomorphic-unfetch@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" @@ -11487,6 +11971,16 @@ jest-diff@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" +jest-diff@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.1.2.tgz#bb7aaf5353227d6f4f96c5e7e8713ce576a607dc" + integrity sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.0.0" + jest-get-type "^29.0.0" + pretty-format "^29.1.2" + jest-docblock@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" @@ -11535,6 +12029,11 @@ jest-get-type@^27.5.1: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== +jest-get-type@^29.0.0: + version "29.0.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.0.0.tgz#843f6c50a1b778f7325df1129a0fd7aa713aef80" + integrity sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw== + jest-haste-map@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" @@ -11617,6 +12116,16 @@ jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" +jest-matcher-utils@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.1.2.tgz#e68c4bcc0266e70aa1a5c13fb7b8cd4695e318a1" + integrity sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw== + dependencies: + chalk "^4.0.0" + jest-diff "^29.1.2" + jest-get-type "^29.0.0" + pretty-format "^29.1.2" + jest-message-util@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" @@ -11632,7 +12141,22 @@ jest-message-util@^27.5.1: slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^27.0.6, jest-mock@^27.5.1: +jest-message-util@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.1.2.tgz#c21a33c25f9dc1ebfcd0f921d89438847a09a501" + integrity sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.1.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.1.2" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.0.6, jest-mock@^27.3.0, jest-mock@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== @@ -11803,6 +12327,18 @@ jest-util@^27.5.1: graceful-fs "^4.2.9" picomatch "^2.2.3" +jest-util@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.1.2.tgz#ac5798e93cb6a6703084e194cfa0898d66126df1" + integrity sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ== + dependencies: + "@jest/types" "^29.1.2" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-validate@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" @@ -12001,6 +12537,11 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-stream/-/json-stream-1.0.0.tgz#1a3854e28d2bbeeab31cc7ddf683d2ddc5652708" + integrity sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg== + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -12262,6 +12803,16 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -12327,6 +12878,27 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lost-pixel@^2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/lost-pixel/-/lost-pixel-2.20.0.tgz#c8a1d40298694e34df7e99d95674a24e0d9b6910" + integrity sha512-gYmyA/Cqu7Xn21VvKuW942jV8hFk1OmjT+YWeCH1HBS4BptltzvbQRHDY4hg8t3DuouaNPDaQpMJyJjMOCGoow== + dependencies: + async "3.2.4" + axios "0.27.2" + fs-extra "^10.1.0" + get-port-please "2.6.1" + lodash.get "^4.4.2" + lodash.kebabcase "^4.1.1" + minio "7.0.32" + pixelmatch "5.3.0" + playwright "1.25.2" + pngjs "^6.0.0" + posthog-node "^2.1.0" + serve-handler "^6.1.3" + ts-node "10.9.1" + uuid "^9.0.0" + yargs "^17.5.1" + loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -13057,7 +13629,19 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.30, mime-types@~2.1.24, mime-types@~2.1.34: +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + +mime-types@^2.1.12, mime-types@^2.1.14, mime-types@^2.1.27, mime-types@^2.1.30, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -13121,6 +13705,13 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== +minimatch@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -13140,6 +13731,29 @@ minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1. resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== +minio@7.0.32: + version "7.0.32" + resolved "https://registry.yarnpkg.com/minio/-/minio-7.0.32.tgz#fed6a4679c5954d3efc6df47f73f7e7124446e2c" + integrity sha512-txa7Vr0N24MKzeAybP/wY1jxbLnfGHXwZYyfFXuMW55HX2+HOcKEIgH4hU6Qj/kiMgyXs/ozHjAuLIDrR8nwLg== + dependencies: + async "^3.1.0" + block-stream2 "^2.0.0" + browser-or-node "^1.3.0" + buffer-crc32 "^0.2.13" + crypto-browserify "^3.12.0" + es6-error "^4.1.1" + fast-xml-parser "^3.17.5" + ipaddr.js "^2.0.1" + json-stream "^1.0.0" + lodash "^4.17.21" + mime-types "^2.1.14" + mkdirp "^0.5.1" + query-string "^7.1.1" + through2 "^3.0.1" + web-encoding "^1.1.5" + xml "^1.0.0" + xml2js "^0.4.15" + minipass-collect@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" @@ -13397,11 +14011,6 @@ node-dir@^0.1.10, node-dir@^0.1.17: dependencies: minimatch "^3.0.2" -node-domexception@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" - integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== - node-fetch@2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" @@ -13414,15 +14023,6 @@ node-fetch@^2.6.1, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^3.2.10: - version "3.2.10" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.10.tgz#e8347f94b54ae18b57c9c049ef641cef398a85c8" - integrity sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA== - dependencies: - data-uri-to-buffer "^4.0.0" - fetch-blob "^3.1.4" - formdata-polyfill "^4.0.10" - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -14038,6 +14638,11 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== +path-is-inside@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== + path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -14063,6 +14668,11 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-to-regexp@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" + integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -14164,6 +14774,13 @@ pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.5: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== +pixelmatch@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.3.0.tgz#5e5321a7abedfb7962d60dbf345deda87cb9560a" + integrity sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q== + dependencies: + pngjs "^6.0.0" + pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -14185,11 +14802,28 @@ pkg-dir@^5.0.0: dependencies: find-up "^5.0.0" +playwright-core@1.25.2: + version "1.25.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.25.2.tgz#ea4baa398a4d45fcdfe48799482b599e3d0f033f" + integrity sha512-0yTbUE9lIddkEpLHL3u8PoCL+pWiZtj5A/j3U7YoNjcmKKDGBnCrgHJMzwd2J5vy6l28q4ki3JIuz7McLHhl1A== + +playwright@1.25.2: + version "1.25.2" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.25.2.tgz#0fc67e4385a52a51371ff9114bf68e3ad50a7f41" + integrity sha512-RwMB5SFRV/8wSfK+tK8ycpqdzORvoqUNz9DUeRfSgZFrZej5uuBl9wFjWcc+OkXFEtaPmx1acAVGG7hA4IJ1kg== + dependencies: + playwright-core "1.25.2" + pluralize@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +pngjs@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" + integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== + pnp-webpack-plugin@1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" @@ -14331,6 +14965,13 @@ postcss@^8.2.15: picocolors "^1.0.0" source-map-js "^1.0.2" +posthog-node@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-2.1.0.tgz#d99acda28b208cbeefed2e6cd0ddfa8cc2d79910" + integrity sha512-xr56mZRQo7rnL2YdwbipcxTZeyi5dcI6IM4++wIN7JLYwinrJYcQv01nan4gU4kMy33Qz5qT6boWMQRwpKZJVQ== + dependencies: + axios "^0.27.0" + prebuild-install@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" @@ -14409,6 +15050,15 @@ pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^29.0.0, pretty-format@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.1.2.tgz#b1f6b75be7d699be1a051f5da36e8ae9e76a8e6a" + integrity sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg== + dependencies: + "@jest/schemas" "^29.0.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + pretty-hrtime@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -14573,7 +15223,7 @@ punycode@1.3.2: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== -punycode@^1.2.4: +punycode@^1.2.4, punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== @@ -14602,6 +15252,16 @@ qs@^6.10.0: dependencies: side-channel "^1.0.4" +query-string@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.1.tgz#754620669db978625a90f635f12617c271a088e1" + integrity sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w== + dependencies: + decode-uri-component "^0.2.0" + filter-obj "^1.1.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -14647,6 +15307,11 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" +range-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A== + range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -14785,7 +15450,7 @@ react-is@17.0.2, react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -"react-is@^16.12.0 || ^17.0.0 || ^18.0.0": +"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== @@ -14980,7 +15645,7 @@ read-pkg@^5.1.1, read-pkg@^5.2.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: +"readable-stream@2 || 3", readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -15023,6 +15688,14 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + refractor@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" @@ -15584,6 +16257,11 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" @@ -15739,6 +16417,20 @@ serve-favicon@^2.5.0: parseurl "~1.3.2" safe-buffer "5.1.1" +serve-handler@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8" + integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w== + dependencies: + bytes "3.0.0" + content-disposition "0.5.2" + fast-url-parser "1.1.3" + mime-types "2.1.18" + minimatch "3.0.4" + path-is-inside "1.0.2" + path-to-regexp "2.2.1" + range-parser "1.2.0" + serve-static@1.14.2: version "1.14.2" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" @@ -16077,6 +16769,11 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -16217,6 +16914,11 @@ stream-slice@^0.1.2: resolved "https://registry.yarnpkg.com/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b" integrity sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA== +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== + string-argv@^0.3.1, string-argv@~0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -16406,6 +17108,11 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== +strnum@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + style-loader@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" @@ -16678,6 +17385,14 @@ through2@^2.0.0, through2@^2.0.3: readable-stream "~2.3.6" xtend "~4.0.1" +through2@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" + integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== + dependencies: + inherits "^2.0.4" + readable-stream "2 || 3" + through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -16857,6 +17572,25 @@ ts-morph@12.0.0: "@ts-morph/common" "~0.11.0" code-block-writer "^10.1.1" +ts-node@10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + ts-node@8.9.1: version "8.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.9.1.tgz#2f857f46c47e91dcd28a14e052482eb14cfd65a5" @@ -17551,6 +18285,11 @@ uvu@^0.5.0: kleur "^4.0.3" sade "^1.7.3" +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + v8-to-istanbul@^8.1.0: version "8.1.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" @@ -17690,7 +18429,7 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-encoding@1.1.5: +web-encoding@1.1.5, web-encoding@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864" integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA== @@ -17704,7 +18443,7 @@ web-namespaces@^1.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== -web-streams-polyfill@^3.0.3, web-streams-polyfill@^3.1.1: +web-streams-polyfill@^3.1.1: version "3.2.1" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== @@ -17866,6 +18605,11 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" +whatwg-fetch@^3.4.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" @@ -18084,6 +18828,24 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml2js@^0.4.15: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xml@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" @@ -18137,6 +18899,11 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.9: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.0.0: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs@^15.0.2: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -18167,6 +18934,19 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.5.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + yarn-or-npm@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/yarn-or-npm/-/yarn-or-npm-3.0.1.tgz#6336eea4dff7e23e226acc98c1a8ada17a1b8666"