This commit is contained in:
Rizky 2024-06-25 05:34:13 +07:00
parent 42c1142cfa
commit 3bbf39c803
1 changed files with 144 additions and 178 deletions

View File

@ -1,4 +1,4 @@
import { FC, Fragment, useEffect } from "react"; import { FC, Fragment, useCallback, useEffect } from "react";
import { useGlobal, useLocal } from "web-utils"; import { useGlobal, useLocal } from "web-utils";
import { apiProxy } from "../../../../../base/load/api/api-proxy"; import { apiProxy } from "../../../../../base/load/api/api-proxy";
import { dbProxy } from "../../../../../base/load/db/db-proxy"; import { dbProxy } from "../../../../../base/load/db/db-proxy";
@ -43,6 +43,8 @@ export const EdPropInstanceOptions: FC<{
options: [] as MetaOption[], options: [] as MetaOption[],
optDeps: [] as any[], optDeps: [] as any[],
resetOnDeps: false as boolean | (() => any[]), resetOnDeps: false as boolean | (() => any[]),
open: false,
pendingVal: null as any,
}); });
const p = useGlobal(EDGlobal, "EDITOR"); const p = useGlobal(EDGlobal, "EDITOR");
@ -184,32 +186,49 @@ export const EdPropInstanceOptions: FC<{
eval(`evalue = ${prop.value}`); eval(`evalue = ${prop.value}`);
} catch (e) {} } catch (e) {}
if (local.open) {
evalue = local.pendingVal;
} else {
local.pendingVal = evalue;
}
useEffect(() => { useEffect(() => {
if (Array.isArray(local.options) && !Array.isArray(evalue)) { if (Array.isArray(local.options) && !Array.isArray(evalue)) {
local.val = evalue; if (mode !== "checkbox") {
local.render(); local.val = evalue;
local.render();
}
} }
}, [evalue]); }, [evalue]);
const onChange = (val: string, item: MetaOption | undefined) => { const onChange = useCallback(
mprop.doc?.transact(() => { (val: string, item: MetaOption | undefined) => {
mprop.set("value", val); if (local.open) {
mprop.set("valueBuilt", val); eval(`local.pendingVal = ${val}`);
}); local.render();
return;
}
treeRebuild(p); mprop.doc?.transact(() => {
p.render(); mprop.set("value", val);
mprop.set("valueBuilt", val);
});
setTimeout(() => { treeRebuild(p);
if (item?.reload) { p.render();
for (const name of item.reload) {
if (config.opt[name]) { setTimeout(() => {
config.opt[name](); if (item?.reload) {
for (const name of item.reload) {
if (config.opt[name]) {
config.opt[name]();
}
} }
} }
} });
}); },
}; [local.open]
);
let mode = cprop.meta?.option_mode; let mode = cprop.meta?.option_mode;
if (!mode) mode = "button"; if (!mode) mode = "button";
@ -283,6 +302,18 @@ export const EdPropInstanceOptions: FC<{
{mode === "checkbox" && ( {mode === "checkbox" && (
<Popover <Popover
placement="top" placement="top"
onOpenChange={(open) => {
local.open = open;
local.render();
if (!open) {
onChange(JSON.stringify(local.pendingVal), null as any);
} else {
local.pendingVal = null;
local.render();
}
}}
open={local.open}
content={ content={
<div <div
className={cx( className={cx(
@ -315,72 +346,19 @@ export const EdPropInstanceOptions: FC<{
} }
}); });
return ( return (
<Fragment key={idx}> <SingleCheckbox
<SingleCheckbox item={item}
item={item} idx={idx}
idx={idx} val={val}
val={val} key={idx}
depth={0} depth={0}
onChange={(val) => { onChange={(val) => {
onChange(JSON.stringify(val), item); onChange(JSON.stringify(val), item);
local.render(); local.render();
}} }}
/> found={found}
{item.options && render={local.render}
found && />
item.options.map((child, idx) => {
const sub_found = found.checked.find(
(e: any) => {
if (!item.options) {
return e === child.value;
} else {
if (
typeof e === "object" &&
e.value === child.value
) {
return true;
}
return false;
}
}
);
return (
<Fragment key={idx}>
<SingleCheckbox
key={idx}
item={child}
idx={idx}
depth={1}
val={found.checked}
onChange={(newval) => {
onChange(JSON.stringify(val), child);
local.render();
}}
/>
{child.options &&
sub_found &&
child.options.map((item, sidx) => {
return (
<SingleCheckbox
item={item}
idx={idx}
key={sidx}
depth={2}
val={sub_found.checked}
onChange={(newval) => {
onChange(
JSON.stringify(val),
item
);
local.render();
}}
/>
);
})}
</Fragment>
);
})}
</Fragment>
); );
})} })}
</div> </div>
@ -390,7 +368,10 @@ export const EdPropInstanceOptions: FC<{
> >
<div <div
className="flex flex-1 items-stretch bg-white border hover:border-blue-500 hover:bg-blue-50 rounded-sm select-none cursor-pointer m-[3px]" className="flex flex-1 items-stretch bg-white border hover:border-blue-500 hover:bg-blue-50 rounded-sm select-none cursor-pointer m-[3px]"
onClick={() => {}} onClick={() => {
local.open = true;
local.render();
}}
ref={(el) => { ref={(el) => {
if (!local.checkbox.width && el) { if (!local.checkbox.width && el) {
const bound = el.getBoundingClientRect(); const bound = el.getBoundingClientRect();
@ -421,70 +402,22 @@ export const EdPropInstanceOptions: FC<{
); );
}; };
const CheckboxLayer = ({
value,
render,
evalue,
onChange,
}: {
value: MetaOption[];
render: () => void;
onChange: (val: string, item: MetaOption | undefined) => void;
evalue: Array<any>;
}) => {
return (
<div className={cx("flex flex-col bg-white")}>
{Array.isArray(value) &&
value.map((item, idx) => {
const val: any[] = Array.isArray(evalue) ? evalue : [];
const found = val.find((e) => {
if (!item.options) {
return e === item.value;
} else {
if (typeof e === "object" && e.value === item.value) {
return true;
}
return false;
}
});
return (
<Fragment key={idx}>
<SingleCheckbox
item={item}
idx={idx}
val={val}
depth={0}
onChange={(val) => {
onChange(JSON.stringify(val), item);
render();
}}
/>
{item.options && found && (
<CheckboxLayer
value={item.options}
render={render}
evalue={found.checked}
onChange={onChange}
/>
)}
</Fragment>
);
})}
</div>
);
};
const SingleCheckbox = ({ const SingleCheckbox = ({
val, val,
item, item,
idx, idx,
onChange, onChange,
depth, depth,
found,
render,
}: { }: {
item: MetaOption; item: MetaOption;
idx: number; idx: number;
depth: number; depth: number;
val: any[]; val: any[];
found: any;
onChange: (val: MetaOption[], item: MetaOption) => void; onChange: (val: MetaOption[], item: MetaOption) => void;
render: () => void;
}) => { }) => {
const is_check = !!val.find((e) => { const is_check = !!val.find((e) => {
if (!item.options) { if (!item.options) {
@ -530,52 +463,85 @@ const SingleCheckbox = ({
}, []); }, []);
return ( return (
<div <>
className={cx( <div
"flex pl-1 text-xs cursor-pointer select-none space-x-1 items-center", className={cx(
idx === 0 && !depth ? "" : "border-t", "flex pl-1 text-xs cursor-pointer select-none space-x-1 items-center",
item.checked && "opacity-50", idx === 0 && !depth ? "" : "border-t",
depth && item.checked && "opacity-50",
css` depth &&
padding-left: ${depth * 20}px; css`
`, padding-left: ${depth * 20}px;
is_check `,
? css` is_check
color: green; ? css`
border-left: 3px solid green; color: green;
border-left: 3px solid green;
&:hover { &:hover {
border-left: 3px solid #a8d4a8; border-left: 3px solid #a8d4a8;
} }
svg {
width: 14px;
}
`
: css`
border-left: 3px solid transparent;
svg {
color: gray;
width: 14px;
}
&:hover {
border-left: 3px solid #0084ff;
color: #0084ff;
svg { svg {
color: #0084ff; width: 14px;
} }
`
: css`
border-left: 3px solid transparent;
svg {
color: gray;
width: 14px;
}
&:hover {
border-left: 3px solid #0084ff;
color: #0084ff;
svg {
color: #0084ff;
}
}
`
)}
onClick={() => {
toggleCheck();
}}
>
{!is_check ? unchecked : checked}
<div>{item.label}</div>
</div>
{item.options &&
found &&
item.options.map((child, idx) => {
const sub_found = found.checked.find((e: any) => {
if (!item.options) {
return e === child.value;
} else {
if (typeof e === "object" && e.value === child.value) {
return true;
} }
` return false;
)} }
onClick={() => { });
toggleCheck();
}} return (
> <SingleCheckbox
{!is_check ? unchecked : checked} key={idx}
<div>{item.label}</div> item={child}
</div> idx={idx}
depth={depth + 1}
val={found.checked}
found={sub_found}
onChange={(newval) => {
onChange(val, child);
render();
}}
render={render}
/>
);
})}
</>
); );
}; };