Web: alle Kategorie-Auswahlen als aufklappbarer Baum
Statt der nativen "— —"-Dropdowns nutzen jetzt auch Produktformular (Kategorie + Inline-"Neue Kategorie"-Elternwahl), Einlagern-Maske und Produkte-Filter den CategorySelect-Baum. CategorySelect um optionale Zusatz-Eintraege (extraOptions) erweitert, damit der Produkte-Filter "Alle Kategorien"/"Ohne Kategorie" weiter anbietet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,9 @@ export default function CategorySelect({
|
||||
onChange,
|
||||
nodes,
|
||||
rootLabel = "– oberste Ebene –",
|
||||
// Zusätzliche Einträge über dem Baum, z.B. { value: 0, label: "Ohne Kategorie" }
|
||||
// für Filter. Ihr Wert wird unverändert an onChange gereicht.
|
||||
extraOptions = [],
|
||||
disabled = false,
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -29,8 +32,10 @@ export default function CategorySelect({
|
||||
const idset = new Set(nodes.map((n) => n.id));
|
||||
const hasKids = (id) => nodes.some((n) => n.parent_id === id);
|
||||
|
||||
const selected = value == null || value === "" ? null : Number(value);
|
||||
const label = selected == null ? rootLabel : nameById[selected] ?? rootLabel;
|
||||
const isRoot = value == null || value === "";
|
||||
const extra = extraOptions.find((o) => String(o.value) === String(value));
|
||||
const selectedId = !isRoot && !extra ? Number(value) : null;
|
||||
const label = isRoot ? rootLabel : extra ? extra.label : nameById[selectedId] ?? rootLabel;
|
||||
|
||||
function place() {
|
||||
const r = btnRef.current?.getBoundingClientRect();
|
||||
@@ -101,7 +106,7 @@ export default function CategorySelect({
|
||||
aria-expanded={open}
|
||||
onClick={() => setOpen((o) => !o)}
|
||||
>
|
||||
<span className={selected == null ? "muted" : ""}>{label}</span>
|
||||
<span className={isRoot ? "muted" : ""}>{label}</span>
|
||||
<Icon name="chevronRight" size={13} className={`caret ${open ? "open" : ""}`} />
|
||||
</button>
|
||||
|
||||
@@ -113,12 +118,23 @@ export default function CategorySelect({
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={`tree-pop-opt ${selected == null ? "sel" : ""}`}
|
||||
className={`tree-pop-opt ${isRoot ? "sel" : ""}`}
|
||||
style={{ paddingLeft: 12 }}
|
||||
onClick={() => pick(null)}
|
||||
>
|
||||
{rootLabel}
|
||||
</button>
|
||||
{extraOptions.map((o) => (
|
||||
<button
|
||||
key={String(o.value)}
|
||||
type="button"
|
||||
className={`tree-pop-opt ${extra && String(extra.value) === String(o.value) ? "sel" : ""}`}
|
||||
style={{ paddingLeft: 12 }}
|
||||
onClick={() => pick(o.value)}
|
||||
>
|
||||
{o.label}
|
||||
</button>
|
||||
))}
|
||||
{visible.map((n) => {
|
||||
const kids = hasKids(n.id);
|
||||
const zu = collapsed.has(n.id);
|
||||
@@ -139,7 +155,7 @@ export default function CategorySelect({
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className={`tree-pop-opt ${selected === n.id ? "sel" : ""}`}
|
||||
className={`tree-pop-opt ${selectedId === n.id ? "sel" : ""}`}
|
||||
onClick={() => pick(n.id)}
|
||||
>
|
||||
{n.name}
|
||||
|
||||
Reference in New Issue
Block a user