wip fix
This commit is contained in:
parent
de6ab61756
commit
22ec9dca9f
|
|
@ -1,32 +1,57 @@
|
|||
import { FC } from "react";
|
||||
import { useGlobal } from "web-utils";
|
||||
import { EDGlobal, EdMeta, active } from "../../logic/ed-global";
|
||||
import { useGlobal, useLocal } from "web-utils";
|
||||
import { IItem } from "../../../../utils/types/item";
|
||||
import { FMCompDef } from "../../../../utils/types/meta-fn";
|
||||
import { Menu, MenuItem } from "../../../../utils/ui/context-menu";
|
||||
import { EDGlobal, EdMeta, active } from "../../logic/ed-global";
|
||||
import { reset } from "./prop-instance/prop-reset";
|
||||
import { EdPropInstanceText } from "./prop-instance/prop-text";
|
||||
import { Loading } from "../../../../utils/ui/loading";
|
||||
|
||||
export const EdSidePropInstance: FC<{ meta: EdMeta }> = ({ meta }) => {
|
||||
const p = useGlobal(EDGlobal, "EDITOR");
|
||||
const local = useLocal({
|
||||
rightClickEvent: null as any,
|
||||
reset: { mprop: null as any, name: "" },
|
||||
});
|
||||
|
||||
const item = meta?.item as IItem;
|
||||
if (!item) return null;
|
||||
|
||||
let filtered = [] as FMCompDef[];
|
||||
let filtered = [] as { mprop: FMCompDef; name: string }[];
|
||||
const mprops = meta.mitem?.get("component")?.get("props");
|
||||
if (mprops && meta.mitem) {
|
||||
mprops.forEach((m, key) => {
|
||||
filtered.push(m);
|
||||
const comp_id = meta.mitem?.get("component")?.get("id") || "";
|
||||
const mcprops = p.comp.list[comp_id].doc
|
||||
.getMap("map")
|
||||
.get("root")
|
||||
?.get("component")
|
||||
?.get("props");
|
||||
|
||||
if (mprops && meta.mitem && mcprops) {
|
||||
mcprops.forEach((m, key) => {
|
||||
let mprop = mprops.get(key);
|
||||
|
||||
if (!mprop) {
|
||||
const json = m.toJSON();
|
||||
const map = new Y.Map() as any;
|
||||
syncronize(map, json);
|
||||
mprops.set(key, map);
|
||||
filtered.push({ mprop: map, name: key });
|
||||
} else {
|
||||
filtered.push({ mprop, name: key });
|
||||
}
|
||||
});
|
||||
|
||||
filtered = filtered.sort((a, b) => {
|
||||
const aidx = a.get("idx") || 0;
|
||||
const bidx = b.get("idx") || 0;
|
||||
const aidx = a.mprop.get("idx") || 0;
|
||||
const bidx = b.mprop.get("idx") || 0;
|
||||
return aidx - bidx;
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col text-[12px]">
|
||||
<div className="flex border-b p-1 h-[35px] items-center bg-slate-50 justify-between select-none">
|
||||
<div className="flex flex-1 flex-col text-[12px]">
|
||||
<div className="flex border-b p-1 h-[27px] items-center bg-slate-50 justify-between select-none">
|
||||
<div className="flex-1 overflow-hidden mr-2 text-ellipsis whitespace-nowrap">
|
||||
{meta.item.name}
|
||||
</div>
|
||||
|
|
@ -55,6 +80,57 @@ export const EdSidePropInstance: FC<{ meta: EdMeta }> = ({ meta }) => {
|
|||
Edit Component
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-1 relative overflow-auto">
|
||||
<div className={cx("absolute inset-0")}>
|
||||
{local.rightClickEvent && (
|
||||
<Menu
|
||||
mouseEvent={local.rightClickEvent}
|
||||
onClose={() => {
|
||||
local.rightClickEvent = null;
|
||||
local.render();
|
||||
}}
|
||||
>
|
||||
<MenuItem
|
||||
label="Reset"
|
||||
onClick={() => {
|
||||
if (local.reset.name) {
|
||||
reset(p, comp_id, local.reset.mprop, local.reset.name);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<MenuItem label={"Edit Code"} onClick={() => {}} />
|
||||
</Menu>
|
||||
)}
|
||||
{filtered.length === 0 && (
|
||||
<div className="flex absolute inset-0 items-center justify-center">
|
||||
No Prop Available
|
||||
</div>
|
||||
)}
|
||||
{filtered.map(({ name, mprop }) => {
|
||||
const type = mprop.get("meta")?.get("type") || "text";
|
||||
return (
|
||||
<div
|
||||
key={name}
|
||||
className="border-b text-[13px] relative"
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
local.reset = { mprop, name };
|
||||
local.rightClickEvent = e;
|
||||
local.render();
|
||||
}}
|
||||
>
|
||||
<>
|
||||
{type === "text" && (
|
||||
<EdPropInstanceText mprop={mprop} name={name} />
|
||||
)}
|
||||
{type !== "text" && <div className="p-1">{name}</div>}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { FMCompDef } from "../../../../../utils/types/meta-fn";
|
||||
import { PG } from "../../../logic/ed-global";
|
||||
|
||||
export const reset = (
|
||||
p: PG,
|
||||
comp_id: string,
|
||||
mprop: FMCompDef,
|
||||
name: string
|
||||
) => {
|
||||
if (comp_id) {
|
||||
const ref = p.comp.list[comp_id];
|
||||
|
||||
if (ref.doc) {
|
||||
const mcprops = ref.doc
|
||||
.getMap("map")
|
||||
.get("root")
|
||||
?.get("component")
|
||||
?.get("props");
|
||||
const mcprop = mcprops?.get(name);
|
||||
if (mcprop) {
|
||||
mprop.doc?.transact(() => {
|
||||
mprop.set("value", mcprop.get("value"));
|
||||
mprop.set("valueBuilt", mcprop.get("valueBuilt"));
|
||||
});
|
||||
|
||||
p.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import {
|
||||
FC,
|
||||
TextareaHTMLAttributes,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { FMCompDef } from "../../../../../utils/types/meta-fn";
|
||||
import { useGlobal, useLocal } from "web-utils";
|
||||
import { EDGlobal } from "../../../logic/ed-global";
|
||||
import { Tooltip } from "../../../../../utils/ui/tooltip";
|
||||
|
||||
export const EdPropInstanceText: FC<{
|
||||
name: string;
|
||||
mprop: FMCompDef;
|
||||
}> = ({ name, mprop }) => {
|
||||
const p = useGlobal(EDGlobal, "EDITOR");
|
||||
|
||||
const local = useLocal({
|
||||
value: "",
|
||||
codeEditing: false,
|
||||
timeout: null as any,
|
||||
});
|
||||
|
||||
const val = mprop.get("value");
|
||||
const valBuilt = mprop.get("valueBuilt");
|
||||
|
||||
useEffect(() => {
|
||||
if (val) {
|
||||
try {
|
||||
eval(`local.value = ${valBuilt}`);
|
||||
} catch (e) {}
|
||||
} else {
|
||||
local.value = "";
|
||||
}
|
||||
local.render();
|
||||
}, [val, valBuilt]);
|
||||
|
||||
const label = (
|
||||
<div className="pl-1 max-w-[50px] overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{name}
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
{name.length > 8 ? (
|
||||
<Tooltip content={name} placement="left" delay={100}>
|
||||
{label}
|
||||
</Tooltip>
|
||||
) : (
|
||||
label
|
||||
)}
|
||||
<AutoHeightTextarea
|
||||
className="flex-1 outline-none border-l p-1 ml-1 overflow-hidden"
|
||||
value={local.value}
|
||||
spellCheck={false}
|
||||
onChange={(e) => {
|
||||
local.value = e.currentTarget.value;
|
||||
local.render();
|
||||
clearTimeout(local.timeout);
|
||||
local.timeout = setTimeout(() => {
|
||||
mprop.doc?.transact(() => {
|
||||
mprop.set("value", `\`${local.value}\``);
|
||||
mprop.set("valueBuilt", `\`${local.value}\``);
|
||||
});
|
||||
}, 1000);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export function AutoHeightTextarea({
|
||||
minRows = 1,
|
||||
...props
|
||||
}: TextareaHTMLAttributes<HTMLTextAreaElement> & { minRows?: number }) {
|
||||
const ref = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const calculateAndSetHeight = useCallback(() => {
|
||||
if (!ref.current) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
borderBottomWidth,
|
||||
borderTopWidth,
|
||||
boxSizing,
|
||||
lineHeight,
|
||||
paddingBottom,
|
||||
paddingTop,
|
||||
} = window.getComputedStyle(ref.current);
|
||||
ref.current.style.height = lineHeight; // set height temporarily to a single row to obtain scrollHeight, disregarding empty space after text (otherwise, scrollHeight would be equal to the height of the element) - this solves auto-shrinking of the textarea (it's not needed for auto-growing it)
|
||||
const { scrollHeight } = ref.current; // scrollHeight = content height + padding top + padding bottom
|
||||
|
||||
if (boxSizing === "border-box") {
|
||||
const minHeight =
|
||||
parseFloat(lineHeight) * minRows +
|
||||
parseFloat(paddingTop) +
|
||||
parseFloat(paddingBottom) +
|
||||
parseFloat(borderTopWidth) +
|
||||
parseFloat(borderBottomWidth);
|
||||
const allTextHeight =
|
||||
scrollHeight +
|
||||
parseFloat(borderTopWidth) +
|
||||
parseFloat(borderBottomWidth);
|
||||
ref.current.style.height = `${Math.max(minHeight, allTextHeight)}px`;
|
||||
} else if (boxSizing === "content-box") {
|
||||
const minHeight = parseFloat(lineHeight) * minRows;
|
||||
const allTextHeight =
|
||||
scrollHeight - parseFloat(paddingTop) - parseFloat(paddingBottom);
|
||||
ref.current.style.height = `${Math.max(minHeight, allTextHeight)}px`;
|
||||
} else {
|
||||
console.error("Unknown box-sizing value.");
|
||||
}
|
||||
}, [minRows]);
|
||||
|
||||
useEffect(() => {
|
||||
calculateAndSetHeight();
|
||||
}, [calculateAndSetHeight]);
|
||||
|
||||
const handleChange: React.ChangeEventHandler<HTMLTextAreaElement> = (e) => {
|
||||
calculateAndSetHeight();
|
||||
if (props.onChange) {
|
||||
props.onChange(e);
|
||||
}
|
||||
};
|
||||
calculateAndSetHeight();
|
||||
|
||||
return <textarea {...props} onChange={handleChange} ref={ref} />;
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import { HTML5Backend } from "react-dnd-html5-backend";
|
|||
import { useGlobal, useLocal } from "web-utils";
|
||||
import { IItem } from "../../../../utils/types/item";
|
||||
import { FMCompDef } from "../../../../utils/types/meta-fn";
|
||||
import { EDGlobal, EdMeta } from "../../logic/ed-global";
|
||||
import { EDGlobal, EdMeta, active } from "../../logic/ed-global";
|
||||
import { EdPropCompTreeItem, PropItem } from "./prop-master/tree-item";
|
||||
import { propPopover } from "./prop-master/prop-form";
|
||||
|
||||
|
|
@ -54,17 +54,42 @@ export const EdSidePropComp: FC<{ meta: EdMeta }> = ({ meta }) => {
|
|||
return (
|
||||
<div className="flex flex-col text-[12px] flex-1">
|
||||
<div className="flex border-b p-1 h-[35px] items-center bg-slate-50 justify-between select-none">
|
||||
<div className="flex-1 overflow-hidden mr-2 text-ellipsis whitespace-nowrap">
|
||||
{item.name}
|
||||
</div>
|
||||
<div
|
||||
className="border px-1 cursor-pointer bg-white hover:bg-blue-100"
|
||||
className="flex cursor-pointer items-center"
|
||||
onClick={() => {
|
||||
p.ui.side.prop = false;
|
||||
p.render();
|
||||
}}
|
||||
>
|
||||
Close
|
||||
<svg
|
||||
width="15"
|
||||
height="15"
|
||||
viewBox="0 0 15 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.84182 3.13514C9.04327 3.32401 9.05348 3.64042 8.86462 3.84188L5.43521 7.49991L8.86462 11.1579C9.05348 11.3594 9.04327 11.6758 8.84182 11.8647C8.64036 12.0535 8.32394 12.0433 8.13508 11.8419L4.38508 7.84188C4.20477 7.64955 4.20477 7.35027 4.38508 7.15794L8.13508 3.15794C8.32394 2.95648 8.64036 2.94628 8.84182 3.13514Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<div>Style</div>
|
||||
</div>
|
||||
<div
|
||||
className="border px-1 cursor-pointer bg-white hover:bg-blue-100"
|
||||
onClick={() => {
|
||||
if (active.comp_id) {
|
||||
active.comp_id = active.instance.comp_id || "";
|
||||
active.item_id = active.instance.item_id || "";
|
||||
active.instance.comp_id = "";
|
||||
active.instance.item_id = "";
|
||||
p.render();
|
||||
}
|
||||
}}
|
||||
>
|
||||
Back to Instance
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-1 relative overflow-auto">
|
||||
|
|
|
|||
Loading…
Reference in New Issue