diff --git a/app/web/src/nova/ed/panel/side/prop-instance.tsx b/app/web/src/nova/ed/panel/side/prop-instance.tsx index 565d469e..800ae90a 100644 --- a/app/web/src/nova/ed/panel/side/prop-instance.tsx +++ b/app/web/src/nova/ed/panel/side/prop-instance.tsx @@ -10,6 +10,7 @@ import { EdPropInstanceOptions } from "./prop-instance/prop-option"; import { reset } from "./prop-instance/prop-reset"; import { EdPropInstanceText } from "./prop-instance/prop-text"; import { EdStyleAll } from "./style/side-all"; +import { EdPropInstanceFile } from "./prop-instance/prop-file"; export const EdSidePropInstance: FC<{ meta: IMeta }> = ({ meta }) => { const p = useGlobal(EDGlobal, "EDITOR"); @@ -215,8 +216,12 @@ export const EdSidePropInstance: FC<{ meta: IMeta }> = ({ meta }) => { (![`"`, "'", "`"].includes(value[0]) || ![`"`, "'", "`"].includes(value[value.length - 1])) ) { - hasCode = true; + hasCode = false; } + + if (type === "file" && !value.startsWith("siteurl(")) + hasCode = true; + if (value.length > 100) { hasCode = true; } @@ -238,6 +243,7 @@ export const EdSidePropInstance: FC<{ meta: IMeta }> = ({ meta }) => { = ({ meta }) => { ) : ( <> + {type === "file" && ( + + )} {type === "text" && ( | undefined; onEditCode: React.MouseEventHandler | undefined; -}> = ({ label, name, labelClick, onEditCode }) => { +}> = ({ label, name, labelClick, onEditCode, comp_id, mprop }) => { const p = useGlobal(EDGlobal, "EDITOR"); return ( -
+
{ + reset(p, comp_id, mprop, name); + }} dangerouslySetInnerHTML={{ __html: ``, }} diff --git a/app/web/src/nova/ed/panel/side/prop-instance/prop-file.tsx b/app/web/src/nova/ed/panel/side/prop-instance/prop-file.tsx new file mode 100644 index 00000000..cbfecbf9 --- /dev/null +++ b/app/web/src/nova/ed/panel/side/prop-instance/prop-file.tsx @@ -0,0 +1,115 @@ +import { + FC, + TextareaHTMLAttributes, + useCallback, + useEffect, + useRef, +} from "react"; +import { useGlobal, useLocal } from "web-utils"; +import { FMCompDef } from "../../../../../utils/types/meta-fn"; +import { EdPropLabel } from "./prop-label"; +import { treeRebuild } from "../../../logic/tree/build"; +import { EDGlobal } from "../../../logic/ed-global"; + +export const EdPropInstanceFile: FC<{ + name: string; + label?: string; + mprop: FMCompDef; + labelClick?: React.MouseEventHandler | undefined; +}> = ({ label, name, mprop, labelClick }) => { + const p = useGlobal(EDGlobal, "EDITOR"); + const val = mprop.get("value"); + + const local = useLocal({ + value: unquote(val), + codeEditing: false, + timeout: null as any, + }); + + useEffect(() => { + local.value = unquote(val); + local.render(); + }, [val]); + + const is_file = local.value.startsWith("siteurl("); + + return ( +
+ +
+
+ ); +}; + +const unquote = (text: any) => { + if (typeof text === "string") { + const str = text.trim(); + const first = str[0]; + + if (['"', "'", "`"].includes(first)) { + if (first === str[str.length - 1]) { + return str.slice(1, -1); + } + } + return str; + } + return ""; +}; + +export function AutoHeightTextarea({ + minRows = 1, + ...props +}: TextareaHTMLAttributes & { minRows?: number }) { + const ref = useRef(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 = (e) => { + calculateAndSetHeight(); + if (props.onChange) { + props.onChange(e); + } + }; + calculateAndSetHeight(); + + return