mirror of
https://github.com/docmost/docmost.git
synced 2026-08-30 02:25:01 +08:00
feat(ee): bases
Table and kanban UI, formula engine package, and the base-embed editor extension
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { Popover } from "@mantine/core";
|
||||
import { Choice, SelectTypeOptions } from "@/ee/base/types/base.types";
|
||||
import { choiceColor } from "@/ee/base/components/cells/choice-color";
|
||||
import { ChoicePicker } from "@/ee/base/components/cells/choice-picker";
|
||||
import { FieldProps, FieldShell } from "./detail-field";
|
||||
import classes from "@/ee/base/styles/row-detail-modal.module.css";
|
||||
import cellClasses from "@/ee/base/styles/cells.module.css";
|
||||
|
||||
export function FieldChoice({ property, value, readOnly, onChange }: FieldProps) {
|
||||
const [opened, setOpened] = useState(false);
|
||||
const multiple = property.type === "multiSelect";
|
||||
const choices =
|
||||
(property.typeOptions as SelectTypeOptions | undefined)?.choices ?? [];
|
||||
|
||||
const selectedIds = multiple
|
||||
? Array.isArray(value)
|
||||
? (value as string[])
|
||||
: []
|
||||
: typeof value === "string"
|
||||
? [value]
|
||||
: [];
|
||||
const selectedChoices = choices.filter((c) => selectedIds.includes(c.id));
|
||||
|
||||
const handleToggle = useCallback(
|
||||
(choice: Choice) => {
|
||||
if (multiple) {
|
||||
const next = selectedIds.includes(choice.id)
|
||||
? selectedIds.filter((id) => id !== choice.id)
|
||||
: [...selectedIds, choice.id];
|
||||
onChange(next.length > 0 ? next : null);
|
||||
} else {
|
||||
onChange(choice.id === selectedIds[0] ? null : choice.id);
|
||||
setOpened(false);
|
||||
}
|
||||
},
|
||||
[multiple, selectedIds, onChange],
|
||||
);
|
||||
|
||||
const chips = selectedChoices.map((choice) => (
|
||||
<span
|
||||
key={choice.id}
|
||||
className={cellClasses.badge}
|
||||
style={choiceColor(choice.color)}
|
||||
>
|
||||
{choice.name}
|
||||
</span>
|
||||
));
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<FieldShell>
|
||||
<div className={classes.fieldChips}>{chips}</div>
|
||||
</FieldShell>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover
|
||||
opened={opened}
|
||||
onChange={setOpened}
|
||||
position="bottom-start"
|
||||
width="target"
|
||||
shadow="md"
|
||||
withinPortal
|
||||
trapFocus
|
||||
closeOnClickOutside
|
||||
closeOnEscape={false}
|
||||
>
|
||||
<Popover.Target>
|
||||
<FieldShell
|
||||
cursor="pointer"
|
||||
active={opened}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={property.name}
|
||||
onClick={() => setOpened((o) => !o)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
setOpened((o) => !o);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className={classes.fieldChips}>{chips}</div>
|
||||
</FieldShell>
|
||||
</Popover.Target>
|
||||
<Popover.Dropdown p={4}>
|
||||
{opened && (
|
||||
<ChoicePicker
|
||||
property={property}
|
||||
selectedIds={selectedIds}
|
||||
multiple={multiple}
|
||||
grouped={property.type === "status"}
|
||||
allowCreate={property.type !== "status"}
|
||||
onToggle={handleToggle}
|
||||
onEscape={() => setOpened(false)}
|
||||
/>
|
||||
)}
|
||||
</Popover.Dropdown>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user