diff --git a/apps/designer/app/canvas/features/wrapper-component/selected-instance-connector.ts b/apps/designer/app/canvas/features/wrapper-component/selected-instance-connector.ts
index 588f40f690..4c388d9324 100644
--- a/apps/designer/app/canvas/features/wrapper-component/selected-instance-connector.ts
+++ b/apps/designer/app/canvas/features/wrapper-component/selected-instance-connector.ts
@@ -1,5 +1,5 @@
import { useEffect } from "react";
-import type { Instance, Styles, UserProp } from "@webstudio-is/react-sdk";
+import type { Instance, PropsItem, Styles } from "@webstudio-is/react-sdk";
import { getBrowserStyle } from "@webstudio-is/react-sdk";
import { publish, subscribe, subscribeAll } from "~/shared/pubsub";
import {
@@ -53,7 +53,7 @@ export const SelectedInstanceConnector = ({
instanceElementRef: { current: undefined | HTMLElement };
instance: Instance;
instanceStyles: Styles;
- instanceProps: undefined | UserProp[];
+ instanceProps: undefined | PropsItem[];
}) => {
useEffect(() => {
const element = instanceElementRef.current;
diff --git a/apps/designer/app/canvas/features/wrapper-component/wrapper-component.tsx b/apps/designer/app/canvas/features/wrapper-component/wrapper-component.tsx
index 2532650512..355284fbf1 100644
--- a/apps/designer/app/canvas/features/wrapper-component/wrapper-component.tsx
+++ b/apps/designer/app/canvas/features/wrapper-component/wrapper-component.tsx
@@ -5,7 +5,7 @@ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext
import {
type Instance,
type OnChangeChildren,
- type UserProp,
+ type PropsItem,
renderWrapperComponentChildren,
getComponent,
idAttribute,
@@ -44,7 +44,7 @@ const ContentEditable = ({
return ;
};
-type UserProps = Record;
+type UserProps = Record;
type WrapperComponentDevProps = {
instance: Instance;
@@ -81,7 +81,7 @@ export const WrapperComponentDev = ({
}
for (const item of instanceProps) {
if (item.type !== "asset") {
- result[item.prop] = item.value;
+ result[item.name] = item.value;
}
}
return result;
diff --git a/apps/designer/app/canvas/shared/instance.ts b/apps/designer/app/canvas/shared/instance.ts
index d4620411c1..d2c3ad7be8 100644
--- a/apps/designer/app/canvas/shared/instance.ts
+++ b/apps/designer/app/canvas/shared/instance.ts
@@ -1,7 +1,7 @@
import { useEffect } from "react";
import {
type Instance,
- type UserProp,
+ type PropsItem,
getComponentMeta,
allUserPropsContainer,
} from "@webstudio-is/react-sdk";
@@ -31,7 +31,7 @@ declare module "~/shared/pubsub" {
insertInstance: {
instance: Instance;
dropTarget?: { parentId: Instance["id"]; position: number };
- props?: Array;
+ props?: Array;
};
unselectInstance: undefined;
}
diff --git a/apps/designer/app/designer/features/props-panel/control.stories.tsx b/apps/designer/app/designer/features/props-panel/control.stories.tsx
index 847eed1c35..aac3ec4a90 100644
--- a/apps/designer/app/designer/features/props-panel/control.stories.tsx
+++ b/apps/designer/app/designer/features/props-panel/control.stories.tsx
@@ -9,8 +9,9 @@ export const Primitive: ComponentStoryObj = {
args: {
component: "Image",
userProp: {
- prop: "src",
+ name: "src",
id: "ddf20afe-65a8-478e-a52d-1be2d2f70830",
+ instanceId: "instanceId",
type: "string",
value: "",
},
@@ -21,8 +22,9 @@ export const Options: ComponentStoryObj = {
args: {
component: "Image",
userProp: {
- prop: "loading",
+ name: "loading",
id: "ddf20afe-65a8-478e-a52d-1be2d2f70830",
+ instanceId: "instanceId",
type: "string",
value: "",
},
diff --git a/apps/designer/app/designer/features/props-panel/control.tsx b/apps/designer/app/designer/features/props-panel/control.tsx
index ea47191d69..d541c6ac3d 100644
--- a/apps/designer/app/designer/features/props-panel/control.tsx
+++ b/apps/designer/app/designer/features/props-panel/control.tsx
@@ -1,7 +1,7 @@
import {
getComponentMetaProps,
type Instance,
- type UserProp,
+ type PropsItem,
} from "@webstudio-is/react-sdk";
import warnOnce from "warn-once";
import {
@@ -179,7 +179,7 @@ const assertUnreachable = (_arg: never, errorMessage: string) => {
type ControlProps = {
component: Instance["component"];
- userProp: UserProp;
+ userProp: PropsItem;
onChangePropValue: (value: UserPropValue) => void;
setCssProperty: SetProperty;
};
@@ -193,7 +193,7 @@ export function Control({
}: ControlProps) {
const meta = getComponentMetaProps(component);
- const argType = meta[userProp.prop];
+ const argType = meta[userProp.name];
// argType can be undefined in case of new property created
const defaultValue = argType?.defaultValue ?? "";
@@ -202,7 +202,7 @@ export function Control({
if (type == null) {
warnOnce(
true,
- `No control type for prop "${userProp.prop}" component "${component}" found`
+ `No control type for prop "${userProp.name}" component "${component}" found`
);
return ;
}
@@ -211,14 +211,14 @@ export function Control({
warnOnce(
true,
`Control type "${typeof type}" for prop "${
- userProp.prop
+ userProp.name
}" component "${component}" is not a string`
);
return ;
}
- if (component === "Image" && userProp.prop === "src") {
+ if (component === "Image" && userProp.name === "src") {
const asset = userProp.type === "asset" ? userProp.value : null;
return (
@@ -298,7 +298,7 @@ export function Control({
warnOnce(
options == null,
- `options is not an array of strings for prop: ${userProp.prop} component: ${component}`
+ `options is not an array of strings for prop: ${userProp.name} component: ${component}`
);
const DEFAULT_OPTIONS: string[] = [];
@@ -356,7 +356,7 @@ export function Control({
warnOnce(
true,
- `Control type "${type}" is not implemented for prop: "${userProp.prop}" in component "${component}"`
+ `Control type "${type}" is not implemented for prop: "${userProp.name}" in component "${component}"`
);
return ;
diff --git a/apps/designer/app/designer/features/props-panel/props-panel.stories.tsx b/apps/designer/app/designer/features/props-panel/props-panel.stories.tsx
index fd8e8019aa..5276efc931 100644
--- a/apps/designer/app/designer/features/props-panel/props-panel.stories.tsx
+++ b/apps/designer/app/designer/features/props-panel/props-panel.stories.tsx
@@ -2,7 +2,7 @@ import type { ComponentStory } from "@storybook/react";
import {
allUserPropsContainer,
getComponentMetaProps,
- type UserProp,
+ type PropsItem,
} from "@webstudio-is/react-sdk";
import { PropsPanel } from "./props-panel";
@@ -16,7 +16,8 @@ export const NoProps: ComponentStory = () => {
"1": [
{
id: "disabled",
- prop: "disabled",
+ instanceId: "instanceId",
+ name: "disabled",
type: "boolean",
value: true,
},
@@ -73,12 +74,12 @@ const meta = getComponentMetaProps("Button");
export const AllProps: ComponentStory = () => {
allUserPropsContainer.set({
- "3": Object.entries(meta).map(([prop, value]) => {
+ "3": Object.entries(meta).map(([name, value]) => {
return {
- id: prop,
- prop,
+ id: name,
+ name,
value: value?.defaultValue ?? "",
- } as UserProp;
+ } as PropsItem;
}),
});
return (
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 5186909665..23bb9ec87c 100644
--- a/apps/designer/app/designer/features/props-panel/props-panel.tsx
+++ b/apps/designer/app/designer/features/props-panel/props-panel.tsx
@@ -5,7 +5,7 @@ import {
getComponentMetaProps,
useAllUserProps,
type Instance,
- type UserProp,
+ type PropsItem,
} from "@webstudio-is/react-sdk";
import { type Publish } from "~/shared/pubsub";
import { Control } from "./control";
@@ -124,7 +124,7 @@ const Combobox = ({
};
type PropertyProps = {
- userProp: UserProp;
+ userProp: PropsItem;
component: Instance["component"];
onChangePropName: (name: string) => void;
onChangePropValue: (value: UserPropValue) => void;
@@ -146,12 +146,12 @@ const Property = ({
}: PropertyProps) => {
const metaProps = getComponentMetaProps(component);
- const argType = metaProps[userProp.prop as keyof typeof metaProps];
+ const argType = metaProps[userProp.name as keyof typeof metaProps];
const isInvalid =
- userProp.prop != null &&
- userProp.prop.length > 0 &&
+ userProp.name != null &&
+ userProp.name.length > 0 &&
typeof argType === "undefined" &&
- !userProp.prop.match(/^data-(.)+/);
+ !userProp.name.match(/^data-(.)+/);
const allProps = Object.keys(metaProps).filter(
(propName) => existingProps.includes(propName) === false
@@ -167,12 +167,12 @@ const Property = ({
placeholder="Property"
readOnly={true}
state={isInvalid ? "invalid" : undefined}
- value={userProp.prop}
+ value={userProp.name}
/>
) : (
{
if (name != null) {
setError(undefined);
@@ -195,7 +195,7 @@ const Property = ({
/>
)}
{isInvalid || error !== undefined ? (
-
+
) : (
@@ -282,7 +282,7 @@ export const PropsPanel = ({
/>
);
- const existingProps = userProps.map((userProp) => userProp.prop);
+ const existingProps = userProps.map((userProp) => userProp.name);
return (
diff --git a/apps/designer/app/designer/features/props-panel/use-props-logic.test.ts b/apps/designer/app/designer/features/props-panel/use-props-logic.test.ts
index 9c96f37c97..66b27a5211 100644
--- a/apps/designer/app/designer/features/props-panel/use-props-logic.test.ts
+++ b/apps/designer/app/designer/features/props-panel/use-props-logic.test.ts
@@ -27,7 +27,7 @@ describe("usePropsLogic", () => {
);
expect(result.current.userProps.length).toEqual(1);
expect(result.current.userProps[0]).toMatchObject({
- prop: "href",
+ name: "href",
value: "",
});
});
@@ -50,11 +50,11 @@ describe("usePropsLogic", () => {
})
);
expect(res1.current.userProps[0]).toMatchObject({
- prop: "tag",
+ name: "tag",
value: "h1",
});
expect(res2.current.userProps[0]).toMatchObject({
- prop: "type",
+ name: "type",
value: "submit",
});
});
@@ -70,7 +70,7 @@ describe("usePropsLogic", () => {
);
expect(result.current.userProps.length).toEqual(1);
expect(result.current.userProps[0]).toMatchObject({
- prop: "type",
+ name: "type",
value: "submit",
});
});
@@ -81,7 +81,8 @@ describe("usePropsLogic", () => {
props: [
{
id: "default",
- prop: "type",
+ instanceId: "instanceId",
+ name: "type",
type: "string",
value: "submit",
},
@@ -93,7 +94,7 @@ describe("usePropsLogic", () => {
);
expect(result.current.userProps.length).toEqual(1);
expect(result.current.userProps[0]).toMatchObject({
- prop: "type",
+ name: "type",
value: "submit",
});
});
@@ -115,7 +116,7 @@ describe("usePropsLogic", () => {
});
expect(result.current.userProps.length).toEqual(2);
- expect(result.current.userProps[1]).toMatchObject({ prop: "", value: "" });
+ expect(result.current.userProps[1]).toMatchObject({ name: "", value: "" });
});
test("should respect initialProps ordering", () => {
@@ -124,35 +125,40 @@ describe("usePropsLogic", () => {
props: [
{
id: "22",
- prop: "aria-label",
+ instanceId: "instanceId",
+ name: "aria-label",
type: "string",
value: "https://example.com",
required: false,
},
{
id: "0",
- prop: "alt",
+ instanceId: "instanceId",
+ name: "alt",
type: "string",
value: "alt text",
required: true,
},
{
id: "1",
- prop: "width",
+ instanceId: "instanceId",
+ name: "width",
type: "number",
value: 101,
required: false,
},
{
id: "33",
- prop: "title",
+ instanceId: "instanceId",
+ name: "title",
type: "string",
value: "title text",
required: true,
},
{
id: "2",
- prop: "src",
+ instanceId: "instanceId",
+ name: "src",
type: "string",
value: "https://example.com",
required: true,
@@ -166,7 +172,7 @@ describe("usePropsLogic", () => {
const imgMeta = getComponentMeta("Image");
- const propNames = result.current.userProps.map((userProp) => userProp.prop);
+ const propNames = result.current.userProps.map((userProp) => userProp.name);
expect(imgMeta.initialProps).toEqual(
propNames.slice(0, imgMeta.initialProps?.length ?? 0)
@@ -175,9 +181,9 @@ describe("usePropsLogic", () => {
expect(propNames.slice(imgMeta.initialProps?.length ?? 0)).toEqual(
result.current.userProps
.filter(
- (userProp) => imgMeta.initialProps?.includes(userProp.prop) === false
+ (userProp) => imgMeta.initialProps?.includes(userProp.name) === false
)
- .map((userProp) => userProp.prop)
+ .map((userProp) => userProp.name)
);
});
@@ -194,7 +200,8 @@ describe("usePropsLogic", () => {
expect(
result.current.isRequired({
id: "2",
- prop: "src",
+ instanceId: "instanceId",
+ name: "src",
type: "string",
value: "https://example.com",
required: false,
@@ -215,7 +222,8 @@ describe("usePropsLogic", () => {
expect(
result.current.isRequired({
id: "2",
- prop: "arial-label",
+ instanceId: "instanceId",
+ name: "arial-label",
type: "string",
value: "https://example.com",
required: true,
@@ -225,7 +233,8 @@ describe("usePropsLogic", () => {
expect(
result.current.isRequired({
id: "2",
- prop: "arial-label",
+ instanceId: "instanceId",
+ name: "arial-label",
type: "string",
value: "https://example.com",
required: false,
diff --git a/apps/designer/app/designer/features/props-panel/use-props-logic.ts b/apps/designer/app/designer/features/props-panel/use-props-logic.ts
index dddfa34cb4..7a1c355dd0 100644
--- a/apps/designer/app/designer/features/props-panel/use-props-logic.ts
+++ b/apps/designer/app/designer/features/props-panel/use-props-logic.ts
@@ -2,7 +2,8 @@ import { useMemo, useState } from "react";
import ObjectId from "bson-objectid";
import warnOnce from "warn-once";
import type {
- UserProp,
+ Instance,
+ PropsItem,
MetaProps,
ComponentName,
} from "@webstudio-is/react-sdk";
@@ -12,7 +13,7 @@ import {
} from "@webstudio-is/react-sdk";
import type { SelectedInstanceData } from "@webstudio-is/project";
-export type UserPropValue = UserProp extends infer T
+export type UserPropValue = PropsItem extends infer T
? T extends { value: unknown; type: unknown }
? { value: T["value"]; type: T["type"] }
: never
@@ -73,20 +74,25 @@ const getRequiredPropsList = (component: ComponentName) => {
};
type UsePropsLogic = {
- props: UserProp[];
+ props: PropsItem[];
selectedInstanceData: SelectedInstanceData;
- updateProps: (update: UserProp) => void;
- deleteProp: (id: UserProp["id"]) => void;
+ updateProps: (update: PropsItem) => void;
+ deleteProp: (id: PropsItem["id"]) => void;
};
-const getPropsItemFromMetaProps = (metaProps: MetaProps, name: string) => {
+const getPropsItemFromMetaProps = (
+ instanceId: Instance["id"],
+ metaProps: MetaProps,
+ name: string
+) => {
const metaPropValue = metaProps[name];
if (metaPropValue === undefined) {
return undefined;
}
return {
id: ObjectId().toString(),
- prop: name,
+ instanceId,
+ name,
...getValueFromPropMeta(metaPropValue),
};
};
@@ -100,7 +106,7 @@ export const usePropsLogic = ({
updateProps,
deleteProp,
}: UsePropsLogic) => {
- const { component } = selectedInstanceData;
+ const { id: instanceId, component } = selectedInstanceData;
const metaProps = useMemo(
() => getComponentMetaProps(component),
@@ -110,24 +116,24 @@ export const usePropsLogic = ({
() => getRequiredPropsList(component),
[component]
);
- const requiredPropsByName = new Map();
+ const requiredPropsByName = new Map();
for (const name of requiredPropsList) {
- const propsItem = getPropsItemFromMetaProps(metaProps, name);
+ const propsItem = getPropsItemFromMetaProps(instanceId, metaProps, name);
if (propsItem) {
requiredPropsByName.set(name, propsItem);
}
}
- const [addedProps, setAddedProps] = useState([]);
- const addedPropsById = new Map();
+ const [addedProps, setAddedProps] = useState([]);
+ const addedPropsById = new Map();
for (const propsItem of addedProps) {
addedPropsById.set(propsItem.id, propsItem);
}
- const propsById = new Map();
+ const propsById = new Map();
for (const propsItem of props) {
- if (requiredPropsByName.has(propsItem.prop)) {
- requiredPropsByName.set(propsItem.prop, propsItem);
+ if (requiredPropsByName.has(propsItem.name)) {
+ requiredPropsByName.set(propsItem.name, propsItem);
continue;
}
if (addedPropsById.has(propsItem.id)) {
@@ -145,20 +151,23 @@ export const usePropsLogic = ({
...addedPropsById.values(),
];
- const handleChangePropName = (propsItem: UserProp, name: string) => {
+ const handleChangePropName = (propsItem: PropsItem, name: string) => {
// prevent changing name of required props
if (isRequired(propsItem)) {
return;
}
const typedValue = getValueFromPropMeta(metaProps[name]);
- updateProps({ id: propsItem.id, prop: name, ...typedValue });
+ updateProps({ id: propsItem.id, instanceId, name, ...typedValue });
};
- const handleChangePropValue = (propsItem: UserProp, value: UserPropValue) => {
+ const handleChangePropValue = (
+ propsItem: PropsItem,
+ value: UserPropValue
+ ) => {
updateProps({ ...propsItem, ...value });
};
- const handleDeleteProp = (propsItem: UserProp) => {
+ const handleDeleteProp = (propsItem: PropsItem) => {
// required prop should never be deleted
if (isRequired(propsItem)) {
return;
@@ -173,15 +182,16 @@ export const usePropsLogic = ({
...prev,
{
id: ObjectId().toString(),
- prop: "",
+ instanceId,
+ name: "",
type: "string",
value: "",
},
]);
};
- const isRequired = (propsItem: UserProp) => {
- return propsItem.required || requiredPropsList.includes(propsItem.prop);
+ const isRequired = (propsItem: PropsItem) => {
+ return propsItem.required || requiredPropsList.includes(propsItem.name);
};
return {
diff --git a/apps/designer/app/shared/copy-paste/serialize.ts b/apps/designer/app/shared/copy-paste/serialize.ts
index 50c1a19038..e69c9db8ff 100644
--- a/apps/designer/app/shared/copy-paste/serialize.ts
+++ b/apps/designer/app/shared/copy-paste/serialize.ts
@@ -1,11 +1,11 @@
-import { Instance, UserProps } from "@webstudio-is/react-sdk";
+import { Instance, Props } from "@webstudio-is/react-sdk";
import { z } from "zod";
const TYPE = "@webstudio/instance/v0.1" as const;
const InstanceCopyData = z.object({
instance: Instance,
- props: UserProps.optional(),
+ props: Props.optional(),
});
export type InstanceCopyData = z.infer;
diff --git a/apps/designer/app/shared/copy-paste/use-instance-copy-paste.ts b/apps/designer/app/shared/copy-paste/use-instance-copy-paste.ts
index fcbae1d2f8..51bb85ce52 100644
--- a/apps/designer/app/shared/copy-paste/use-instance-copy-paste.ts
+++ b/apps/designer/app/shared/copy-paste/use-instance-copy-paste.ts
@@ -1,5 +1,5 @@
import { utils } from "@webstudio-is/project";
-import type { Instance, UserProp } from "@webstudio-is/react-sdk";
+import type { Instance, PropsItem } from "@webstudio-is/react-sdk";
import { useEffect, useMemo } from "react";
import { type InstanceCopyData, serialize, deserialize } from "./serialize";
@@ -38,7 +38,7 @@ const isInstanceClipboardEvent = (
type Props = {
selectedInstanceData?: InstanceCopyData | undefined;
allowAnyTarget?: boolean;
- onPaste: (instance: Instance, props?: UserProp[]) => void;
+ onPaste: (instance: Instance, props?: PropsItem[]) => void;
onCut: (instance: Instance) => void;
};
diff --git a/packages/project/src/db/props.ts b/packages/project/src/db/props.ts
index 212451485a..dbc5467f76 100644
--- a/packages/project/src/db/props.ts
+++ b/packages/project/src/db/props.ts
@@ -3,8 +3,7 @@ import {
type Tree,
type AllUserProps,
type InstanceProps,
- type PropsItem,
- Props,
+ StoredProps,
} from "@webstudio-is/react-sdk";
import { applyPatches, type Patch } from "immer";
import { prisma } from "@webstudio-is/prisma-client";
@@ -19,7 +18,7 @@ export const loadByTreeId = async (treeId: Tree["id"]) => {
return [];
}
- const props = Props.parse(JSON.parse(tree.props));
+ const props = StoredProps.parse(JSON.parse(tree.props));
// Fin all assetId in all props
const assetIds: string[] = [];
@@ -64,7 +63,8 @@ export const loadByTreeId = async (treeId: Tree["id"]) => {
if (asset) {
instanceProps.props.push({
id: propsItem.id,
- prop: propsItem.name,
+ instanceId: propsItem.instanceId,
+ name: propsItem.name,
required: propsItem.required,
type: propsItem.type,
value: asset,
@@ -77,13 +77,7 @@ export const loadByTreeId = async (treeId: Tree["id"]) => {
continue;
}
- instanceProps.props.push({
- id: propsItem.id,
- prop: propsItem.name,
- required: propsItem.required,
- type: propsItem.type,
- value: propsItem.value,
- } as InstanceProps["props"][number]);
+ instanceProps.props.push(propsItem);
}
return Array.from(instancePropsMap.values());
@@ -107,28 +101,21 @@ export const patch = async (
patches
);
- const props: Props = [];
+ const props: StoredProps = [];
for (const [instanceId, instanceProps] of Object.entries(nextProps)) {
- for (const prop of instanceProps) {
- if (prop.type === "asset") {
+ for (const propsItem of instanceProps) {
+ if (propsItem.type === "asset") {
props.push({
- id: prop.id,
+ id: propsItem.id,
instanceId,
- name: prop.prop,
- required: prop.required,
- type: prop.type,
- value: prop.value.id,
+ name: propsItem.name,
+ required: propsItem.required,
+ type: propsItem.type,
+ value: propsItem.value.id,
});
continue;
}
- props.push({
- id: prop.id,
- instanceId,
- name: prop.prop,
- required: prop.required,
- type: prop.type,
- value: prop.value,
- } as PropsItem);
+ props.push(propsItem);
}
}
diff --git a/packages/project/src/shared/props/clone-user-props.ts b/packages/project/src/shared/props/clone-user-props.ts
index 002c5c73ce..251622bba3 100644
--- a/packages/project/src/shared/props/clone-user-props.ts
+++ b/packages/project/src/shared/props/clone-user-props.ts
@@ -1,5 +1,5 @@
-import type { UserProp } from "@webstudio-is/react-sdk";
+import type { PropsItem } from "@webstudio-is/react-sdk";
import ObjectId from "bson-objectid";
-export const cloneUserProps = (props: Array): Array =>
+export const cloneUserProps = (props: Array): Array =>
props.map((prop) => ({ ...prop, id: ObjectId().toString() }));
diff --git a/packages/react-sdk/src/db/props.ts b/packages/react-sdk/src/db/props.ts
index a6cfe00523..144456e79e 100644
--- a/packages/react-sdk/src/db/props.ts
+++ b/packages/react-sdk/src/db/props.ts
@@ -1,4 +1,5 @@
import { z } from "zod";
+import { Asset } from "@webstudio-is/asset-uploader";
const basePropsItem = {
id: z.string(),
@@ -7,7 +8,7 @@ const basePropsItem = {
required: z.optional(z.boolean()),
};
-export const PropsItem = z.discriminatedUnion("type", [
+const SharedPropsItem = z.union([
z.object({
...basePropsItem,
type: z.literal("number"),
@@ -23,14 +24,33 @@ export const PropsItem = z.discriminatedUnion("type", [
type: z.literal("boolean"),
value: z.boolean(),
}),
+]);
+
+export const StoredPropsItem = z.union([
+ SharedPropsItem,
z.object({
...basePropsItem,
type: z.literal("asset"),
- // In database we hold asset.id
+ // asset.id is stored in database
value: z.string(),
}),
]);
+export type StoredPropsItem = z.infer;
+
+export const StoredProps = z.array(StoredPropsItem);
+
+export type StoredProps = z.infer;
+
+export const PropsItem = z.union([
+ SharedPropsItem,
+ z.object({
+ ...basePropsItem,
+ type: z.literal("asset"),
+ value: Asset,
+ }),
+]);
+
export type PropsItem = z.infer;
export const Props = z.array(PropsItem);
diff --git a/packages/react-sdk/src/db/types.ts b/packages/react-sdk/src/db/types.ts
index c20872087d..42dc55e754 100644
--- a/packages/react-sdk/src/db/types.ts
+++ b/packages/react-sdk/src/db/types.ts
@@ -1,7 +1,6 @@
import type { InstanceProps as DbInstanceProps } from "@webstudio-is/prisma-client";
-import type { UserProp } from "../user-props";
import type { Instance } from "./instance";
-import type { Props } from "./props";
+import type { Props, PropsItem } from "./props";
import type { PresetStyles, Styles } from "./style";
export type Tree = {
@@ -13,5 +12,5 @@ export type Tree = {
};
export type InstanceProps = Omit & {
- props: Array;
+ props: Array;
};
diff --git a/packages/react-sdk/src/user-props/all-user-props.ts b/packages/react-sdk/src/user-props/all-user-props.ts
index 9b714cd89d..4ae128e4cc 100644
--- a/packages/react-sdk/src/user-props/all-user-props.ts
+++ b/packages/react-sdk/src/user-props/all-user-props.ts
@@ -1,11 +1,10 @@
import { useRef } from "react";
import { atom } from "nanostores";
import { useStore } from "@nanostores/react";
-import type { InstanceProps, Instance } from "../db";
-import { UserProp } from "./schema";
+import type { InstanceProps, Instance, PropsItem } from "../db";
export type AllUserProps = {
- [id: Instance["id"]]: UserProp[];
+ [id: Instance["id"]]: PropsItem[];
};
export const allUserPropsContainer = atom({});
diff --git a/packages/react-sdk/src/user-props/index.ts b/packages/react-sdk/src/user-props/index.ts
index 0c44558bc4..e8e6330a95 100644
--- a/packages/react-sdk/src/user-props/index.ts
+++ b/packages/react-sdk/src/user-props/index.ts
@@ -1,3 +1,2 @@
export * from "./all-user-props";
export * from "./use-user-props";
-export * from "./schema";
diff --git a/packages/react-sdk/src/user-props/schema.ts b/packages/react-sdk/src/user-props/schema.ts
deleted file mode 100644
index af29ce6bde..0000000000
--- a/packages/react-sdk/src/user-props/schema.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { z } from "zod";
-import { Asset } from "@webstudio-is/asset-uploader";
-
-const baseUserProps = {
- id: z.string(),
- prop: z.string(),
- required: z.optional(z.boolean()),
-};
-
-export const UserProp = z.discriminatedUnion("type", [
- z.object({
- ...baseUserProps,
- type: z.literal("number"),
- value: z.number(),
- }),
- z.object({
- ...baseUserProps,
- type: z.literal("string"),
- value: z.string(),
- }),
- z.object({
- ...baseUserProps,
- type: z.literal("boolean"),
- value: z.boolean(),
- }),
- z.object({
- ...baseUserProps,
- type: z.literal("asset"),
- value: Asset,
- }),
-]);
-
-export const UserProps = z.array(UserProp);
-
-export type UserProp = z.infer;
diff --git a/packages/react-sdk/src/user-props/use-user-props-asset.ts b/packages/react-sdk/src/user-props/use-user-props-asset.ts
index 9a2e48deab..5f7810430b 100644
--- a/packages/react-sdk/src/user-props/use-user-props-asset.ts
+++ b/packages/react-sdk/src/user-props/use-user-props-asset.ts
@@ -1,6 +1,5 @@
import { useMemo } from "react";
-import { type Instance } from "../db";
-import { type UserProp } from "./schema";
+import { PropsItem, type Instance } from "../db";
import { useAllUserProps } from "./all-user-props";
import type { Asset } from "@webstudio-is/asset-uploader";
@@ -9,7 +8,7 @@ import type { Asset } from "@webstudio-is/asset-uploader";
*/
export const useUserPropsAsset = (
instanceId: Instance["id"],
- propName: UserProp["prop"]
+ propName: PropsItem["name"]
): Asset | undefined => {
const allUserProps = useAllUserProps();
@@ -18,7 +17,7 @@ export const useUserPropsAsset = (
if (propsData == null) {
return undefined;
}
- const prop = propsData.find((prop) => prop.prop === propName);
+ const prop = propsData.find((prop) => prop.name === propName);
if (prop == null) {
return undefined;
diff --git a/packages/react-sdk/src/user-props/use-user-props.ts b/packages/react-sdk/src/user-props/use-user-props.ts
index 02f4716b5b..2d3a903555 100644
--- a/packages/react-sdk/src/user-props/use-user-props.ts
+++ b/packages/react-sdk/src/user-props/use-user-props.ts
@@ -1,9 +1,8 @@
import { useMemo } from "react";
-import { type Instance } from "../db";
-import { type UserProp } from "./schema";
+import type { Instance, PropsItem } from "../db";
import { useAllUserProps } from "./all-user-props";
-type UserProps = { [prop: UserProp["prop"]]: string | number | boolean };
+type UserProps = { [name: PropsItem["name"]]: string | number | boolean };
/**
* User props mapped in prop:value format,
@@ -21,7 +20,7 @@ export const useUserProps = (instanceId: Instance["id"]) => {
for (const userProp of propsData) {
if (userProp.type !== "asset") {
- result[userProp.prop] = userProp.value;
+ result[userProp.name] = userProp.value;
}
}