mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-08 21:15:18 +09:00
Merge branch 'main' into canvas-dnd-integration
This commit is contained in:
52 files changed
+636
-244
No files matched your search
+1
-1
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
// This tells ESLint to load the config from the package `eslint-config-custom`
|
||||
extends: ["custom"],
|
||||
extends: ["@webstudio-is/eslint-config-custom"],
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
name: 'Release NPM package'
|
||||
description: 'Release NPM package'
|
||||
inputs:
|
||||
package:
|
||||
description: 'Package.json location (relative)'
|
||||
default: 'package.json'
|
||||
required: true
|
||||
token:
|
||||
description: 'NPM Token'
|
||||
default: 'null'
|
||||
required: true
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install Dependencies
|
||||
run: yarn install
|
||||
shell: bash
|
||||
- uses: JS-DevTools/npm-publish@v1
|
||||
with:
|
||||
token: ${{ inputs.token }}
|
||||
dry-run: false
|
||||
check-version: true
|
||||
access: 'public'
|
||||
package: ${{ inputs.package }}
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
## Before merging
|
||||
|
||||
- [ ] tested locally and on preview environment (preview dev login: 5de6e)
|
||||
- [ ] tested locally and on preview environment (preview dev login: 5de6)
|
||||
- [ ] updated [test cases](https://github.com/webstudio-is/webstudio-designer/blob/main/apps/designer/docs/test-cases.md) document
|
||||
- [ ] added tests
|
||||
- [ ] if any new env variables are added, added them to `.env.example` and the `designer/env-check.js` if mandatory
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Design System Publish
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "packages/design-system/**/*"
|
||||
- ".github/workflows/design-system.yml"
|
||||
- ".github/actions/publish/action.yaml"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/publish
|
||||
with:
|
||||
package: "./packages/design-system/package.json"
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Eslint Config Publish
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "packages/eslint-config-custom/**/*"
|
||||
- ".github/workflows/eslint-config-custom.yml"
|
||||
- ".github/actions/publish/action.yaml"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/publish
|
||||
with:
|
||||
package: "./packages/eslint-config-custom/package.json"
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Icons Publish
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "packages/icons/**/*"
|
||||
- ".github/workflows/icons-publish.yml"
|
||||
- ".github/actions/publish/action.yaml"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/publish
|
||||
with:
|
||||
package: "./packages/icons/package.json"
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Jest Config Publish
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "packages/jest-config/**/*"
|
||||
- ".github/workflows/jest-config.yml"
|
||||
- ".github/actions/publish/action.yaml"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/publish
|
||||
with:
|
||||
package: "./packages/jest-config/package.json"
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -1,22 +0,0 @@
|
||||
name: SDK publish
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'packages/react-sdk/**/*'
|
||||
- '.github/workflows/react-sdk-publish.yml'
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install Dependencies
|
||||
run: yarn install
|
||||
- uses: JS-DevTools/npm-publish@v1
|
||||
with:
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
dry-run: false
|
||||
check-version: true
|
||||
package: './packages/react-sdk/package.json'
|
||||
@@ -0,0 +1,16 @@
|
||||
name: SDK publish
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "packages/react-sdk/**/*"
|
||||
- ".github/workflows/react-sdk.yml"
|
||||
- ".github/actions/publish/action.yaml"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/publish
|
||||
with:
|
||||
package: "./packages/react-sdk/package.json"
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Tsconfig Publish
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "packages/tsconfig/**/*"
|
||||
- ".github/workflows/tsconfig.yml"
|
||||
- ".github/actions/publish/action.yaml"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/publish
|
||||
with:
|
||||
package: "./packages/tsconfig/package.json"
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -28,9 +28,9 @@ export const Inspector = ({ publish }: InspectorProps) => {
|
||||
|
||||
if (selectedInstanceData === undefined) {
|
||||
return (
|
||||
<Box css={{ p: "$2" }}>
|
||||
<Box css={{ p: "$2", flexBasis: "100%" }}>
|
||||
{/* @todo: use this space for something more usefull: a-la figma's no instance selected sate, maybe create an issue with a more specific proposal? */}
|
||||
<Card css={{ p: "$3", mt: "$3" }}>
|
||||
<Card css={{ p: "$3", mt: "$3", width: "100%" }}>
|
||||
<Paragraph>Select an instance on the canvas</Paragraph>
|
||||
</Card>
|
||||
</Box>
|
||||
|
||||
@@ -2,48 +2,53 @@ import { ImageIcon } from "@webstudio-is/icons";
|
||||
import { Flex, Grid, Heading } from "@webstudio-is/design-system";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useActionData } from "@remix-run/react";
|
||||
import { Asset } from "@webstudio-is/prisma-client";
|
||||
import { AssetManagerImage } from "./components/image";
|
||||
import { AssetManagerThumbnail } from "./components/thumbnail";
|
||||
|
||||
import { AddAnAssetForm } from "./components/add-an-asset-form";
|
||||
import { UploadingAsset } from "../types";
|
||||
import { Asset } from "../types";
|
||||
|
||||
export const useAssetsState = (baseAssets: Array<Asset>) => {
|
||||
const imageChanges = useActionData();
|
||||
|
||||
const [assets, setAssets] = useState<Asset[]>(baseAssets);
|
||||
|
||||
useEffect(() => {
|
||||
if (imageChanges?.uploadedAssets?.length) {
|
||||
setAssets((currentAssets) => [
|
||||
...imageChanges.uploadedAssets,
|
||||
...currentAssets.filter((asset) => asset.status !== "uploading"),
|
||||
]);
|
||||
}
|
||||
if (imageChanges?.deletedAsset?.id) {
|
||||
setAssets((currentAssets) => [
|
||||
...currentAssets.filter(
|
||||
(asset) => asset.id !== imageChanges.deletedAsset.id
|
||||
),
|
||||
]);
|
||||
}
|
||||
}, [imageChanges]);
|
||||
|
||||
const onUploadAsset = (uploadedAssets: Array<Asset>) =>
|
||||
setAssets((assets) => [...uploadedAssets, ...assets]);
|
||||
|
||||
return { assets, onUploadAsset };
|
||||
};
|
||||
|
||||
export const TabContent = ({
|
||||
assets: baseAssets,
|
||||
}: {
|
||||
assets: Array<Asset | UploadingAsset>;
|
||||
assets: Array<Asset>;
|
||||
}) => {
|
||||
const newImages = useActionData();
|
||||
|
||||
const [assets, setAssets] = useState(baseAssets);
|
||||
|
||||
useEffect(() => {
|
||||
if (newImages?.length) {
|
||||
setAssets((currentAssets) => [
|
||||
...newImages,
|
||||
...currentAssets.filter((asset) => asset.status !== "uploading"),
|
||||
]);
|
||||
}
|
||||
}, [newImages]);
|
||||
|
||||
const { assets, onUploadAsset } = useAssetsState(baseAssets);
|
||||
return (
|
||||
<Flex gap="3" direction="column" css={{ padding: "$1" }}>
|
||||
<Flex justify="between">
|
||||
<Flex justify="between" align="center">
|
||||
<Heading>Assets</Heading>
|
||||
<AddAnAssetForm
|
||||
onSubmit={(uploadedAssets: Array<UploadingAsset>) =>
|
||||
setAssets((assets) => [...uploadedAssets, ...assets])
|
||||
}
|
||||
/>
|
||||
<AddAnAssetForm onSubmit={onUploadAsset} />
|
||||
</Flex>
|
||||
<Grid columns={2} gap={2}>
|
||||
{assets.map((asset) => (
|
||||
<AssetManagerImage
|
||||
key={asset.id}
|
||||
path={asset.path}
|
||||
alt={asset.alt || asset.name}
|
||||
status={asset.status}
|
||||
/>
|
||||
<AssetManagerThumbnail key={asset.id} {...asset} />
|
||||
))}
|
||||
</Grid>
|
||||
</Flex>
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Box, ProgressBar } from "@webstudio-is/design-system";
|
||||
import { useInterval } from "react-use";
|
||||
import placeholderImage from "~/shared/images/image-placeholder.svg";
|
||||
import brokenImage from "~/shared/images/broken-image-placeholder.svg";
|
||||
import { Asset } from "@webstudio-is/prisma-client";
|
||||
|
||||
const useImageWithFallback = ({ path }: { path: string }) => {
|
||||
const [src, setSrc] = useState(placeholderImage);
|
||||
|
||||
useEffect(() => {
|
||||
const newImage = new Image();
|
||||
newImage.onload = () => setSrc(path);
|
||||
newImage.onerror = () => setSrc(brokenImage);
|
||||
newImage.src = path;
|
||||
}, [path]);
|
||||
|
||||
return src;
|
||||
};
|
||||
|
||||
export const AssetManagerImage = ({
|
||||
path,
|
||||
alt,
|
||||
status,
|
||||
}: {
|
||||
path: string;
|
||||
alt?: string;
|
||||
status?: Asset["status"];
|
||||
}) => {
|
||||
const isUploading = status === "uploading";
|
||||
const src = useImageWithFallback({ path });
|
||||
const [progressBarPercentage, setProgressBarPercentage] = useState(0);
|
||||
|
||||
// @todo rewrite this fake indication to show real progress
|
||||
useInterval(
|
||||
() => {
|
||||
setProgressBarPercentage((percentage) =>
|
||||
percentage < 60 ? percentage + 1 : percentage
|
||||
);
|
||||
},
|
||||
isUploading ? 100 : null
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
title={alt || ""}
|
||||
css={{
|
||||
aspectRatio: "1/1",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
padding: "0 $2",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
css={{
|
||||
backgroundImage: `url("${src}")`,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundSize: "contain",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center",
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
top: 0,
|
||||
...(isUploading ? { filter: "blur(1px)", opacity: 0.7 } : {}),
|
||||
}}
|
||||
></Box>
|
||||
{isUploading && (
|
||||
<ProgressBar
|
||||
value={progressBarPercentage}
|
||||
max={60}
|
||||
css={{ width: "100%", height: "$1" }}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Flex,
|
||||
ProgressBar,
|
||||
Tooltip,
|
||||
} from "@webstudio-is/design-system";
|
||||
import { useInterval } from "react-use";
|
||||
import placeholderImage from "~/shared/images/image-placeholder.svg";
|
||||
import brokenImage from "~/shared/images/broken-image-placeholder.svg";
|
||||
import { useSubmit } from "@remix-run/react";
|
||||
import { Asset } from "~/designer/features/sidebar-left/types";
|
||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||
|
||||
const useImageWithFallback = ({ path }: { path: string }) => {
|
||||
const [src, setSrc] = useState(placeholderImage);
|
||||
|
||||
useEffect(() => {
|
||||
const newImage = new Image();
|
||||
newImage.onload = () => setSrc(path);
|
||||
newImage.onerror = () => setSrc(brokenImage);
|
||||
newImage.src = path;
|
||||
}, [path]);
|
||||
|
||||
return src;
|
||||
};
|
||||
|
||||
const useFakeProgress = ({
|
||||
isUploading,
|
||||
isDeleting,
|
||||
}: {
|
||||
isUploading: boolean;
|
||||
isDeleting: boolean;
|
||||
}) => {
|
||||
const [progressBarPercentage, setProgressBarPercentage] = useState(0);
|
||||
|
||||
// @todo rewrite this fake indication to show real progress
|
||||
useInterval(
|
||||
() => {
|
||||
setProgressBarPercentage((percentage) =>
|
||||
percentage < 60 ? percentage + 1 : percentage
|
||||
);
|
||||
},
|
||||
isUploading || isDeleting ? 100 : null
|
||||
);
|
||||
|
||||
return progressBarPercentage;
|
||||
};
|
||||
|
||||
export const AssetManagerThumbnail = ({
|
||||
path,
|
||||
alt,
|
||||
status,
|
||||
name,
|
||||
id,
|
||||
}: Asset) => {
|
||||
const submit = useSubmit();
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const isUploading = status === "uploading";
|
||||
const src = useImageWithFallback({ path });
|
||||
const [isTooltipOpen, setTolltipOpen] = useState(false);
|
||||
const progressBarPercentage = useFakeProgress({ isUploading, isDeleting });
|
||||
|
||||
const closeTooltip = () => setTolltipOpen(false);
|
||||
|
||||
const deleteAsset = () => {
|
||||
const formData = new FormData();
|
||||
formData.append("assetId", id);
|
||||
formData.append("assetName", name);
|
||||
closeTooltip();
|
||||
setIsDeleting(true);
|
||||
submit(formData, { method: "delete" });
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
title={alt || name}
|
||||
css={{
|
||||
aspectRatio: "1/1",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
padding: "0 $2",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
css={{
|
||||
backgroundImage: `url("${src}")`,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundSize: "contain",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center",
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
top: 0,
|
||||
...(isUploading ? { filter: "blur(1px)", opacity: 0.7 } : {}),
|
||||
}}
|
||||
></Box>
|
||||
{!isUploading && (
|
||||
<Tooltip
|
||||
open={isTooltipOpen}
|
||||
multiline
|
||||
onEscapeKeyDown={closeTooltip}
|
||||
onPointerDownOutside={closeTooltip}
|
||||
content={
|
||||
<Flex direction="column" gap={1} align="center" justify="center">
|
||||
Are you sure you want to delete this asset?
|
||||
<Button variant="red" onClick={deleteAsset}>
|
||||
Delete
|
||||
</Button>
|
||||
</Flex>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
variant="raw"
|
||||
title="Delete asset"
|
||||
onClick={() => setTolltipOpen(true)}
|
||||
css={{
|
||||
position: "absolute",
|
||||
top: "$1",
|
||||
right: "$1",
|
||||
cursor: "pointer",
|
||||
color: "$highContrast",
|
||||
}}
|
||||
>
|
||||
<Cross2Icon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isUploading || isDeleting) && (
|
||||
<ProgressBar
|
||||
value={progressBarPercentage}
|
||||
max={60}
|
||||
css={{ width: "100%", height: "$1" }}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Asset } from "@webstudio-is/prisma-client";
|
||||
import { Asset as BaseAsset } from "@webstudio-is/prisma-client";
|
||||
import { panels } from "./panels";
|
||||
|
||||
export type TabName = keyof typeof panels | "none";
|
||||
|
||||
export type UploadingAsset = Pick<
|
||||
Asset,
|
||||
BaseAsset,
|
||||
"id" | "status" | "name" | "path" | "alt"
|
||||
>;
|
||||
export type Asset = BaseAsset | UploadingAsset;
|
||||
@@ -1,4 +1,5 @@
|
||||
// Our root outlet doesn't contain a layout because we have 2 types of documents: canvas and designer and we need to decide down the line which one to render, thre is no single root document.
|
||||
import { TooltipProvider } from "@radix-ui/react-tooltip";
|
||||
import { Outlet } from "@remix-run/react";
|
||||
import { withSentryRouteTracing } from "@sentry/remix";
|
||||
import { ErrorBoundary } from "@sentry/remix";
|
||||
@@ -7,7 +8,9 @@ import { OutletProps } from "react-router-dom";
|
||||
const RootWithErrorBoundary = (props: OutletProps) => (
|
||||
// @ts-expect-error 'ErrorBoundary' cannot be used as a JSX component.
|
||||
<ErrorBoundary>
|
||||
<Outlet {...props} />
|
||||
<TooltipProvider>
|
||||
<Outlet {...props} />
|
||||
</TooltipProvider>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
|
||||
@@ -10,12 +10,16 @@ import * as db from "~/shared/db";
|
||||
import config from "~/config";
|
||||
import { ensureUserCookie } from "~/shared/session";
|
||||
import { authenticator } from "~/services/auth.server";
|
||||
import { zfd } from "zod-form-data";
|
||||
export { links };
|
||||
|
||||
const schema = zfd.formData({
|
||||
project: zfd.text(),
|
||||
});
|
||||
|
||||
export const action: ActionFunction = async ({ request }) => {
|
||||
const formData = await request.formData();
|
||||
const title = formData.get("project");
|
||||
if (typeof title !== "string") return { errors: "Title required" };
|
||||
const { project: title } = schema.parse(await request.formData());
|
||||
|
||||
const { userId, headers } = await ensureUserCookie(request);
|
||||
const authenticatedUser = await authenticator.isAuthenticated(request);
|
||||
try {
|
||||
|
||||
@@ -9,7 +9,11 @@ import { uploadAssets } from "~/shared/db/misc.server";
|
||||
import { ErrorMessage } from "~/shared/error";
|
||||
// if this file does not end in .server remix will not build
|
||||
// since it only allows node code in those files
|
||||
import { loadByProject } from "@webstudio-is/asset-uploader/index.server";
|
||||
import {
|
||||
deleteAsset,
|
||||
loadByProject,
|
||||
} from "@webstudio-is/asset-uploader/index.server";
|
||||
import { zfd } from "zod-form-data";
|
||||
|
||||
export { links };
|
||||
|
||||
@@ -33,19 +37,44 @@ type Error = {
|
||||
errors: "string";
|
||||
};
|
||||
|
||||
const deleteAssetSchema = zfd.formData({
|
||||
assetId: zfd.text(),
|
||||
assetName: zfd.text(),
|
||||
});
|
||||
|
||||
export const action: ActionFunction = async ({ request, params }) => {
|
||||
if (params.id === undefined) throw new Error("Project id undefined");
|
||||
try {
|
||||
if (request.method === "DELETE") {
|
||||
const { assetId, assetName } = deleteAssetSchema.parse(
|
||||
await request.formData()
|
||||
);
|
||||
const deletedAsset = await deleteAsset({
|
||||
id: assetId,
|
||||
name: assetName,
|
||||
});
|
||||
|
||||
return { deletedAsset };
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return {
|
||||
errors: error.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (request.method === "POST") {
|
||||
try {
|
||||
const assets = await uploadAssets({
|
||||
request,
|
||||
projectId: params.id,
|
||||
dirname: __dirname,
|
||||
});
|
||||
return assets.map((asset: Asset) => ({
|
||||
...asset,
|
||||
status: "uploaded",
|
||||
}));
|
||||
return {
|
||||
uploadedAssets: assets.map((asset: Asset) => ({
|
||||
...asset,
|
||||
status: "uploaded",
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return {
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { type ActionFunction } from "@remix-run/node";
|
||||
import { zfd } from "zod-form-data";
|
||||
import * as db from "~/shared/db";
|
||||
|
||||
const schema = zfd.formData({
|
||||
domain: zfd.text(),
|
||||
projectId: zfd.text(),
|
||||
});
|
||||
|
||||
export const action: ActionFunction = async ({ request }) => {
|
||||
const formData = await request.formData();
|
||||
const domain = formData.get("domain") as string | null;
|
||||
const projectId = formData.get("projectId") as string | null;
|
||||
const { domain, projectId } = schema.parse(await request.formData());
|
||||
try {
|
||||
const project = await db.misc.publish({ projectId, domain });
|
||||
return { domain: project.domain };
|
||||
|
||||
@@ -74,3 +74,10 @@
|
||||
- Add a Box component to the canvas
|
||||
- Open Props panel
|
||||
- See the default tag is provided and can be modified
|
||||
|
||||
1. Asset manager
|
||||
|
||||
- Open assets panel
|
||||
- Upload an image
|
||||
- Check it loads and shows a progress bar
|
||||
- Delete an asset by clicking on the `x` icon and then the delete button in the tooltip
|
||||
@@ -26,8 +26,8 @@
|
||||
"@stitches/react": "^1.2.7",
|
||||
"@vercel/node": "^2.4.1",
|
||||
"@webstudio-is/asset-uploader": "*",
|
||||
"@webstudio-is/react-sdk": "*",
|
||||
"@webstudio-is/prisma-client": "*",
|
||||
"@webstudio-is/react-sdk": "*",
|
||||
"@webstudio-is/design-system": "*",
|
||||
"@webstudio-is/icons": "*",
|
||||
"bson-objectid": "^2.0.2",
|
||||
@@ -60,7 +60,8 @@
|
||||
"remix-auth-github": "^1.1.1",
|
||||
"remix-auth-google": "^1.1.0",
|
||||
"sharp": "^0.30.7",
|
||||
"slugify": "^1.6.5"
|
||||
"slugify": "^1.6.5",
|
||||
"zod-form-data": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.5",
|
||||
@@ -98,12 +99,12 @@
|
||||
"esbuild-jest": "^0.5.0",
|
||||
"esbuild-node-externals": "^1.4.1",
|
||||
"esbuild-node-loader": "^0.8.0",
|
||||
"eslint-config-custom": "*",
|
||||
"jest": "^27.5.1",
|
||||
"prettier": "^2.6.2",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"relative-deps": "^1.0.7",
|
||||
"tsconfig": "*",
|
||||
"@webstudio-is/eslint-config-custom": "*",
|
||||
"@webstudio-is/tsconfig": "*",
|
||||
"typescript": "4.6.4"
|
||||
},
|
||||
"sideEffects": false,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
// Extends can't use node's resolution rn https://github.com/dividab/tsconfig-paths/issues/209#issuecomment-1177261091
|
||||
"extends": "../../node_modules/tsconfig/remix.json",
|
||||
"extends": "../../node_modules/@webstudio-is/tsconfig/remix.json",
|
||||
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
"storybook": "turbo run storybook:run"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-custom": "*",
|
||||
"@webstudio-is/eslint-config-custom": "*",
|
||||
"husky": ">=6",
|
||||
"lint-staged": "^13.0.2",
|
||||
"prettier": "latest",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// eslint-disable-next-line
|
||||
const base = require("jest-config/jest.config.js");
|
||||
const base = require("@webstudio-is/jest-config");
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
|
||||
@@ -15,13 +15,15 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.131.0",
|
||||
"@aws-sdk/lib-storage": "^3.131.0",
|
||||
"sharp": "^0.30.7",
|
||||
"@webstudio-is/prisma-client": "*"
|
||||
"@webstudio-is/prisma-client": "*",
|
||||
"app-root-path": "^3.0.0",
|
||||
"sharp": "^0.30.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/app-root-path": "^1.2.4",
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/sharp": "^0.30.4",
|
||||
"jest-config": "*",
|
||||
"@webstudio-is/jest-config": "*",
|
||||
"tsup": "^6.1.3",
|
||||
"typescript": "^4.6.2",
|
||||
"zod": "^3.17.3"
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const DEFAULT_UPLPOAD_PATH = "uploads";
|
||||
export const DEFAULT_UPLOAD_PATH = "public/uploads";
|
||||
@@ -0,0 +1,12 @@
|
||||
import { prisma, Asset } from "@webstudio-is/prisma-client";
|
||||
import { getAssetPath } from "../helpers/get-asset-path";
|
||||
|
||||
export const deleteAssetInDb = async (assetId: Asset["id"]): Promise<Asset> => {
|
||||
if (typeof assetId !== "string") {
|
||||
throw new Error("Asset ID required");
|
||||
}
|
||||
|
||||
const removedAsset = await prisma.asset.delete({ where: { id: assetId } });
|
||||
|
||||
return { ...removedAsset, path: getAssetPath(removedAsset) };
|
||||
};
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./create";
|
||||
export * from "./load";
|
||||
export * from "./delete";
|
||||
@@ -5,7 +5,7 @@ export const loadByProject = async (
|
||||
projectId?: Project["id"]
|
||||
): Promise<Asset[]> => {
|
||||
if (typeof projectId !== "string") {
|
||||
throw new Error("Tree ID required");
|
||||
throw new Error("Project ID required");
|
||||
}
|
||||
|
||||
const assets = await prisma.asset.findMany({
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { DeleteObjectCommand } from "@aws-sdk/client-s3";
|
||||
import { prisma, Asset } from "@webstudio-is/prisma-client";
|
||||
import { unlink } from "fs/promises";
|
||||
import path from "path";
|
||||
import { deleteAssetInDb } from "./db";
|
||||
import { imageFsDirectory } from "./helpers/image-fs-path";
|
||||
import { s3EnvVariables } from "./schema";
|
||||
import { getS3Client } from "./targets/s3/client";
|
||||
|
||||
export const deleteAsset = async ({
|
||||
id,
|
||||
name,
|
||||
}: {
|
||||
id: string;
|
||||
name: string;
|
||||
}): Promise<Asset> => {
|
||||
const currentAsset = await prisma.asset.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
if (!currentAsset) throw new Error("Asset does not exist");
|
||||
|
||||
if (currentAsset.location === "REMOTE") {
|
||||
const s3Envs = s3EnvVariables.parse(process.env);
|
||||
await getS3Client().send(
|
||||
new DeleteObjectCommand({
|
||||
Bucket: s3Envs.S3_BUCKET,
|
||||
Key: name,
|
||||
})
|
||||
);
|
||||
|
||||
return await deleteAssetInDb(id);
|
||||
} else {
|
||||
const directory = await imageFsDirectory();
|
||||
await unlink(path.join(directory, name));
|
||||
|
||||
return await deleteAssetInDb(id);
|
||||
}
|
||||
};
|
||||
@@ -7,7 +7,8 @@ const fsEnvs = fsEnvVariables.parse(process.env);
|
||||
|
||||
export const getAssetPath = (asset: DbAsset) => {
|
||||
if (asset.location === Location.FS) {
|
||||
return path.join("/", fsEnvs.FILE_UPLOAD_PATH, asset.name);
|
||||
const splitPath = fsEnvs.FILE_UPLOAD_PATH.split("public");
|
||||
return path.join("/", splitPath[splitPath.length - 1], asset.name);
|
||||
}
|
||||
|
||||
if (asset.location === Location.REMOTE && s3Envs.success) {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import path from "path";
|
||||
import appRoot from "app-root-path";
|
||||
import { fsEnvVariables } from "../schema";
|
||||
const fsUploadVars = fsEnvVariables.parse(process.env);
|
||||
|
||||
export const imageFsDirectory = () => {
|
||||
const isProd = process.env.NODE_ENV === "production";
|
||||
|
||||
if (isProd) return path.join(appRoot.path, fsUploadVars.FILE_UPLOAD_PATH);
|
||||
|
||||
return path.join(
|
||||
appRoot.path,
|
||||
"apps",
|
||||
"designer",
|
||||
fsUploadVars.FILE_UPLOAD_PATH
|
||||
);
|
||||
};
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./upload";
|
||||
export * from "./delete";
|
||||
export * from "./db";
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { NodeOnDiskFile } from "@remix-run/node";
|
||||
import { DEFAULT_UPLPOAD_PATH } from "./constants";
|
||||
import { DEFAULT_UPLOAD_PATH } from "./constants";
|
||||
|
||||
const SingleImageInUpload = z.instanceof(NodeOnDiskFile);
|
||||
|
||||
@@ -25,7 +25,7 @@ export const s3EnvVariables = z.object({
|
||||
});
|
||||
|
||||
export const fsEnvVariables = z.object({
|
||||
FILE_UPLOAD_PATH: z.string().optional().default(DEFAULT_UPLPOAD_PATH),
|
||||
FILE_UPLOAD_PATH: z.string().optional().default(DEFAULT_UPLOAD_PATH),
|
||||
});
|
||||
|
||||
export const assetEnvVariables = z.object({
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { S3Client } from "@aws-sdk/client-s3";
|
||||
import { s3EnvVariables } from "../../schema";
|
||||
|
||||
export const getS3Client = () => {
|
||||
const s3Envs = s3EnvVariables.parse(process.env);
|
||||
return new S3Client({
|
||||
endpoint: s3Envs.S3_ENDPOINT,
|
||||
region: s3Envs.S3_REGION,
|
||||
credentials: {
|
||||
accessKeyId: s3Envs.S3_ACCESS_KEY_ID,
|
||||
secretAccessKey: s3Envs.S3_SECRET_ACCESS_KEY,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UploadHandlerPart } from "@remix-run/node";
|
||||
import { PutObjectCommandInput, S3Client } from "@aws-sdk/client-s3";
|
||||
import { PutObjectCommandInput } from "@aws-sdk/client-s3";
|
||||
import { Upload } from "@aws-sdk/lib-storage";
|
||||
import ObjectID from "bson-objectid";
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
getFilenameAndExtension,
|
||||
} from "../../helpers/array-buffer-helpers";
|
||||
import { Location } from "@webstudio-is/prisma-client";
|
||||
import { getS3Client } from "./client";
|
||||
|
||||
type S3UploadHandler = ({
|
||||
file,
|
||||
@@ -57,16 +58,7 @@ export const s3UploadHandler: S3UploadHandler = async ({
|
||||
},
|
||||
};
|
||||
|
||||
const client = new S3Client({
|
||||
endpoint: s3Envs.S3_ENDPOINT,
|
||||
region: s3Envs.S3_REGION,
|
||||
credentials: {
|
||||
accessKeyId: s3Envs.S3_ACCESS_KEY_ID,
|
||||
secretAccessKey: s3Envs.S3_SECRET_ACCESS_KEY,
|
||||
},
|
||||
});
|
||||
|
||||
const upload = new Upload({ client, params });
|
||||
const upload = new Upload({ client: getS3Client(), params });
|
||||
|
||||
ImagesUploadedSuccess.parse(await upload.done());
|
||||
const image = sharp(uint8Array);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import path from "path";
|
||||
import {
|
||||
unstable_createFileUploadHandler,
|
||||
unstable_parseMultipartFormData,
|
||||
@@ -6,10 +5,12 @@ import {
|
||||
import { s3UploadHandler } from "./targets/s3/handler";
|
||||
import { uploadToS3 } from "./targets/s3/uploader";
|
||||
import { uploadToDisk } from "./targets/disk/upload";
|
||||
import { assetEnvVariables, fsEnvVariables, s3EnvVariables } from "./schema";
|
||||
import { assetEnvVariables, s3EnvVariables } from "./schema";
|
||||
import { Asset } from "@webstudio-is/prisma-client";
|
||||
import { imageFsDirectory } from "./helpers/image-fs-path";
|
||||
|
||||
const isS3Upload = s3EnvVariables.safeParse(process.env).success;
|
||||
const fsUploadVars = fsEnvVariables.parse(process.env);
|
||||
|
||||
const commonUploadVars = assetEnvVariables.parse(process.env);
|
||||
|
||||
// user inputs the max value in mb and we transform it to bytes
|
||||
@@ -18,14 +19,11 @@ export const MAX_UPLOAD_SIZE = parseInt(commonUploadVars.MAX_UPLOAD_SIZE) * 1e6;
|
||||
export const uploadAssets = async ({
|
||||
request,
|
||||
projectId,
|
||||
dirname,
|
||||
}: {
|
||||
request: Request;
|
||||
projectId: string;
|
||||
dirname: string;
|
||||
}) => {
|
||||
const uploads = path.join(dirname, "../public");
|
||||
const directory = path.join(uploads, fsUploadVars.FILE_UPLOAD_PATH);
|
||||
}): Promise<Asset[]> => {
|
||||
const directory = await imageFsDirectory();
|
||||
const formData = await unstable_parseMultipartFormData(
|
||||
request,
|
||||
isS3Upload
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Extends can't use node's resolution rn https://github.com/dividab/tsconfig-paths/issues/209#issuecomment-1177261091
|
||||
{
|
||||
"extends": "../../node_modules/tsconfig/base.json",
|
||||
"extends": "../../node_modules/@webstudio-is/tsconfig/base.json",
|
||||
"include": ["./src/**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
|
||||
@@ -55,9 +55,10 @@
|
||||
"@radix-ui/react-tabs": "^0.1.5",
|
||||
"@radix-ui/react-toggle": "^0.1.4",
|
||||
"@radix-ui/react-toggle-group": "^0.1.5",
|
||||
"@radix-ui/react-tooltip": "^0.1.7",
|
||||
"@radix-ui/react-tooltip": "^1.0.0",
|
||||
"@radix-ui/react-use-layout-effect": "^0.1.0",
|
||||
"@webstudio-is/icons": "*"
|
||||
"@webstudio-is/icons": "*",
|
||||
"@webstudio-is/react-sdk": "*"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React from "react";
|
||||
import React, { Ref } from "react";
|
||||
import { styled } from "../stitches.config";
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||
import { Box } from "./box";
|
||||
import { Text } from "./text";
|
||||
import type { CSS } from "@webstudio-is/react-sdk";
|
||||
|
||||
type TooltipProps = React.ComponentProps<typeof TooltipPrimitive.Root> &
|
||||
React.ComponentProps<typeof TooltipPrimitive.Content> & {
|
||||
@@ -10,6 +11,7 @@ type TooltipProps = React.ComponentProps<typeof TooltipPrimitive.Root> &
|
||||
content: React.ReactNode;
|
||||
multiline?: boolean;
|
||||
delayDuration?: number;
|
||||
css?: CSS;
|
||||
};
|
||||
|
||||
const Content = styled(TooltipPrimitive.Content, {
|
||||
@@ -18,27 +20,40 @@ const Content = styled(TooltipPrimitive.Content, {
|
||||
color: "$hiContrast",
|
||||
borderRadius: "$1",
|
||||
padding: "$1 $2",
|
||||
zIndex: "$max",
|
||||
position: "relative",
|
||||
|
||||
variants: {
|
||||
multiline: {
|
||||
true: {
|
||||
maxWidth: 250,
|
||||
// @todo makew this part of the design system
|
||||
maxWidth: 110,
|
||||
pb: 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const Tooltip = ({
|
||||
children,
|
||||
content,
|
||||
open,
|
||||
defaultOpen,
|
||||
onOpenChange,
|
||||
multiline,
|
||||
delayDuration,
|
||||
...props
|
||||
}: TooltipProps) => {
|
||||
const Arrow = styled(TooltipPrimitive.Arrow, {
|
||||
fill: "$loContrast",
|
||||
stroke: "$slate7",
|
||||
strokeWidth: "$1",
|
||||
marginTop: -0.5,
|
||||
});
|
||||
|
||||
export const Tooltip = React.forwardRef(function TooltipWrapper(
|
||||
{
|
||||
children,
|
||||
content,
|
||||
open,
|
||||
defaultOpen,
|
||||
onOpenChange,
|
||||
multiline,
|
||||
delayDuration,
|
||||
...props
|
||||
}: TooltipProps,
|
||||
ref: Ref<HTMLDivElement>
|
||||
) {
|
||||
return (
|
||||
<TooltipPrimitive.Root
|
||||
open={open}
|
||||
@@ -49,6 +64,7 @@ export const Tooltip = ({
|
||||
<TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>
|
||||
|
||||
<Content
|
||||
ref={ref}
|
||||
side="top"
|
||||
align="center"
|
||||
sideOffset={5}
|
||||
@@ -66,16 +82,9 @@ export const Tooltip = ({
|
||||
{content}
|
||||
</Text>
|
||||
<Box css={{ color: "$transparentExtreme" }}>
|
||||
<TooltipPrimitive.Arrow
|
||||
offset={5}
|
||||
width={11}
|
||||
height={5}
|
||||
style={{
|
||||
fill: "$loContrast",
|
||||
}}
|
||||
/>
|
||||
<Arrow offset={5} width={11} height={5} />
|
||||
</Box>
|
||||
</Content>
|
||||
</TooltipPrimitive.Root>
|
||||
);
|
||||
};
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
// Extends can't use node's resolution rn https://github.com/dividab/tsconfig-paths/issues/209#issuecomment-1177261091
|
||||
{
|
||||
"extends": "../../node_modules/tsconfig/base.json",
|
||||
"extends": "../../node_modules/@webstudio-is/tsconfig/base.json",
|
||||
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
|
||||
"compilerOptions": {
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2019"],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eslint-config-custom",
|
||||
"version": "0.0.0",
|
||||
"name": "@webstudio-is/eslint-config-custom",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@webstudio-is/icons",
|
||||
"version": "0.5.0",
|
||||
"description": "Webstudio JavaScript / TypeScript API",
|
||||
"version": "0.1.0",
|
||||
"description": "Webstudio Icons",
|
||||
"author": "Webstudio <github@webstudio.is>",
|
||||
"homepage": "https://webstudio.is",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Extends can't use node's resolution rn https://github.com/dividab/tsconfig-paths/issues/209#issuecomment-1177261091
|
||||
{
|
||||
"extends": "../../node_modules/tsconfig/base.json",
|
||||
"extends": "../../node_modules/@webstudio-is/tsconfig/base.json",
|
||||
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
|
||||
"compilerOptions": {
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2019"],
|
||||
|
||||
File renamed without changes.
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jest-config",
|
||||
"version": "0.0.0",
|
||||
"name": "@webstudio-is/jest-config",
|
||||
"version": "1.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/jest": "^27.4.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Extends can't use node's resolution rn https://github.com/dividab/tsconfig-paths/issues/209#issuecomment-1177261091
|
||||
{
|
||||
"extends": "../../node_modules/tsconfig/base.json",
|
||||
"extends": "../../node_modules/@webstudio-is/tsconfig/base.json",
|
||||
"include": ["./src/**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// eslint-disable-next-line
|
||||
const base = require("jest-config/jest.config.js");
|
||||
const base = require("@webstudio-is/jest-config");
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
|
||||
@@ -33,18 +33,18 @@
|
||||
"@types/css-tree": "^1.0.7",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/node": "^17.0.21",
|
||||
"@webstudio-is/prisma-client": "*",
|
||||
"babel-loader": "^8.2.5",
|
||||
"camelcase": "^6.3.0",
|
||||
"css-tree": "^2.1.0",
|
||||
"esbuild": "^0.14.25",
|
||||
"esbuild-node-externals": "^1.4.1",
|
||||
"esbuild-node-loader": "^0.8.0",
|
||||
"jest-config": "*",
|
||||
"@webstudio-is/jest-config": "*",
|
||||
"mdn-data": "2.0.23",
|
||||
"react": "^17.0.2",
|
||||
"react-docgen-typescript": "^2.2.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"@webstudio-is/prisma-client": "*",
|
||||
"tsup": "^6.1.3",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
@@ -59,9 +59,9 @@
|
||||
"@stitches/core": "^1.2.7",
|
||||
"@webstudio-is/icons": "*",
|
||||
"immer": "^9.0.12",
|
||||
"jest-config": "*",
|
||||
"mitt": "^3.0.0",
|
||||
"react-nano-state": "^0.4.0",
|
||||
"@webstudio-is/jest-config": "*",
|
||||
"zod": "^3.17.3"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Extends can't use node's resolution rn https://github.com/dividab/tsconfig-paths/issues/209#issuecomment-1177261091
|
||||
{
|
||||
"extends": "../../node_modules/tsconfig/base.json",
|
||||
"extends": "../../node_modules/@webstudio-is/tsconfig/base.json",
|
||||
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
|
||||
"compilerOptions": {
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2019"],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "tsconfig",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"name": "@webstudio-is/tsconfig",
|
||||
"version": "1.0.0",
|
||||
"private": false,
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"base.json",
|
||||
|
||||
@@ -2752,6 +2752,13 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/primitive@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.0.tgz#e1d8ef30b10ea10e69c76e896f608d9276352253"
|
||||
integrity sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-accessible-icon@^0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-accessible-icon/-/react-accessible-icon-0.1.4.tgz#bdbf1e3226a0e9e7778b68728b175bdc532b720c"
|
||||
@@ -2931,6 +2938,18 @@
|
||||
"@radix-ui/react-use-callback-ref" "0.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "0.1.0"
|
||||
|
||||
"@radix-ui/react-dismissable-layer@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.0.tgz#35b7826fa262fd84370faef310e627161dffa76b"
|
||||
integrity sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.0"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.0"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.0.0"
|
||||
|
||||
"@radix-ui/react-dropdown-menu@^0.1.6":
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz#3203229788cd57e552c9f19dcc7008e2b545919c"
|
||||
@@ -2975,6 +2994,14 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-layout-effect" "0.1.0"
|
||||
|
||||
"@radix-ui/react-id@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.0.tgz#8d43224910741870a45a8c9d092f25887bb6d11e"
|
||||
integrity sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-layout-effect" "1.0.0"
|
||||
|
||||
"@radix-ui/react-label@0.1.5", "@radix-ui/react-label@^0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-0.1.5.tgz#12cd965bfc983e0148121d4c99fb8e27a917c45c"
|
||||
@@ -3046,7 +3073,7 @@
|
||||
"@radix-ui/react-use-size" "0.1.1"
|
||||
"@radix-ui/rect" "0.1.1"
|
||||
|
||||
"@radix-ui/react-popper@^1.0.0":
|
||||
"@radix-ui/react-popper@1.0.0", "@radix-ui/react-popper@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.0.0.tgz#fb4f937864bf39c48f27f55beee61fa9f2bef93c"
|
||||
integrity sha512-k2dDd+1Wl0XWAMs9ZvAxxYsB9sOsEhrFQV4CINd7IUZf0wfdye4OHen9siwxvZImbzhgVeKTJi68OQmPRvVdMg==
|
||||
@@ -3071,6 +3098,14 @@
|
||||
"@radix-ui/react-primitive" "0.1.4"
|
||||
"@radix-ui/react-use-layout-effect" "0.1.0"
|
||||
|
||||
"@radix-ui/react-portal@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.0.tgz#7220b66743394fabb50c55cb32381395cc4a276b"
|
||||
integrity sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.0"
|
||||
|
||||
"@radix-ui/react-presence@0.1.2":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-0.1.2.tgz#9f11cce3df73cf65bc348e8b76d891f0d54c1fe3"
|
||||
@@ -3080,6 +3115,15 @@
|
||||
"@radix-ui/react-compose-refs" "0.1.0"
|
||||
"@radix-ui/react-use-layout-effect" "0.1.0"
|
||||
|
||||
"@radix-ui/react-presence@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.0.tgz#814fe46df11f9a468808a6010e3f3ca7e0b2e84a"
|
||||
integrity sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.0.0"
|
||||
|
||||
"@radix-ui/react-primitive@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz#6c233cf08b0cb87fecd107e9efecb3f21861edc1"
|
||||
@@ -3255,26 +3299,24 @@
|
||||
"@radix-ui/react-primitive" "0.1.4"
|
||||
"@radix-ui/react-use-controllable-state" "0.1.0"
|
||||
|
||||
"@radix-ui/react-tooltip@^0.1.7":
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-0.1.7.tgz#6f8c00d6e489565d14abf209ce0fb8853c8c8ee3"
|
||||
integrity sha512-eiBUsVOHenZ0JR16tl970bB0DafJBz6mFgSGfIGIVpflFj0LIsIDiLMsYyvYdx1KwwsIUDTEZtxcPm/sWjPzqA==
|
||||
"@radix-ui/react-tooltip@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.0.0.tgz#f7fcecf2bac5c31cd14666b5acd056015fc21646"
|
||||
integrity sha512-RB06pov+O4Npy10ei1C6fsyB9QoOjz7Ubo8Sl3qdKtLgkL9iI96925DYtH0bxx6MH6YB2FuzLU6B75qn3AQQQw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "0.1.0"
|
||||
"@radix-ui/react-compose-refs" "0.1.0"
|
||||
"@radix-ui/react-context" "0.1.1"
|
||||
"@radix-ui/react-id" "0.1.5"
|
||||
"@radix-ui/react-popper" "0.1.4"
|
||||
"@radix-ui/react-portal" "0.1.4"
|
||||
"@radix-ui/react-presence" "0.1.2"
|
||||
"@radix-ui/react-primitive" "0.1.4"
|
||||
"@radix-ui/react-slot" "0.1.2"
|
||||
"@radix-ui/react-use-controllable-state" "0.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "0.1.0"
|
||||
"@radix-ui/react-use-previous" "0.1.1"
|
||||
"@radix-ui/react-use-rect" "0.1.1"
|
||||
"@radix-ui/react-visually-hidden" "0.1.4"
|
||||
"@radix-ui/primitive" "1.0.0"
|
||||
"@radix-ui/react-compose-refs" "1.0.0"
|
||||
"@radix-ui/react-context" "1.0.0"
|
||||
"@radix-ui/react-dismissable-layer" "1.0.0"
|
||||
"@radix-ui/react-id" "1.0.0"
|
||||
"@radix-ui/react-popper" "1.0.0"
|
||||
"@radix-ui/react-portal" "1.0.0"
|
||||
"@radix-ui/react-presence" "1.0.0"
|
||||
"@radix-ui/react-primitive" "1.0.0"
|
||||
"@radix-ui/react-slot" "1.0.0"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.0"
|
||||
"@radix-ui/react-visually-hidden" "1.0.0"
|
||||
|
||||
"@radix-ui/react-use-body-pointer-events@0.1.1":
|
||||
version "0.1.1"
|
||||
@@ -3291,6 +3333,13 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-use-callback-ref@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz#9e7b8b6b4946fe3cbe8f748c82a2cce54e7b6a90"
|
||||
integrity sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-use-controllable-state@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.1.0.tgz#4fced164acfc69a4e34fb9d193afdab973a55de1"
|
||||
@@ -3299,6 +3348,14 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-callback-ref" "0.1.0"
|
||||
|
||||
"@radix-ui/react-use-controllable-state@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz#a64deaafbbc52d5d407afaa22d493d687c538b7f"
|
||||
integrity sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
|
||||
"@radix-ui/react-use-direction@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-direction/-/react-use-direction-0.1.0.tgz#97ac1d52e497c974389e7988f809238ed72e7df7"
|
||||
@@ -3314,6 +3371,14 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-callback-ref" "0.1.0"
|
||||
|
||||
"@radix-ui/react-use-escape-keydown@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.0.tgz#aef375db4736b9de38a5a679f6f49b45a060e5d1"
|
||||
integrity sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||
|
||||
"@radix-ui/react-use-layout-effect@0.1.0", "@radix-ui/react-use-layout-effect@^0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.1.0.tgz#ebf71bd6d2825de8f1fbb984abf2293823f0f223"
|
||||
@@ -3374,6 +3439,14 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "0.1.4"
|
||||
|
||||
"@radix-ui/react-visually-hidden@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.0.tgz#4d69d7e3b6d21ee4678ed6de5215dcd068394401"
|
||||
integrity sha512-MwAhMdX+n6S4InwRKSnpUsp+lLkYG6izQF56ul6guSX2mBBLOMV9Frx7xJlkEe2GjKLzbNuHhaCS6e5gopmZNA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.0"
|
||||
|
||||
"@radix-ui/rect@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-0.1.1.tgz#95b5ba51f469bea6b1b841e2d427e17e37d38419"
|
||||
@@ -4762,6 +4835,11 @@
|
||||
dependencies:
|
||||
"@types/estree" "*"
|
||||
|
||||
"@types/app-root-path@^1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/app-root-path/-/app-root-path-1.2.4.tgz#a78b703282b32ac54de768f5512ecc3569919dc7"
|
||||
integrity sha512-yhURoXmWN/zfw2MXXcOdUTwe5CWhzRWtb4Rs2+JwGpuhm2hxLCzjASi/aIuyVeJB3Iyks1teaHyOEfNNmltdvQ==
|
||||
|
||||
"@types/aria-query@^4.2.0":
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
|
||||
@@ -5893,6 +5971,11 @@ app-root-dir@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/app-root-dir/-/app-root-dir-1.0.2.tgz#38187ec2dea7577fff033ffcb12172692ff6e118"
|
||||
integrity sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==
|
||||
|
||||
app-root-path@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad"
|
||||
integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==
|
||||
|
||||
aproba@^1.0.3, aproba@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
|
||||
@@ -17918,6 +18001,11 @@ yocto-queue@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||
|
||||
zod-form-data@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/zod-form-data/-/zod-form-data-1.2.1.tgz#6da07d7964765b464e959a75f0d797690ee477f7"
|
||||
integrity sha512-L4zocmlzikYB9A2uVVj3OUKX/t3spOZTzQLOhoCXECn9w+eN3bw0D/KYGX4J72iLdCIwDP6YJyYwVXkx3WTu7A==
|
||||
|
||||
zod@^3.17.3:
|
||||
version "3.17.3"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.17.3.tgz#86abbc670ff0063a4588d85a4dcc917d6e4af2ba"
|
||||
|
||||
Reference in new issue
Block a user