diff --git a/src/Core/Menus.fs b/src/Core/Menus.fs index bb40efb..c488c0f 100644 --- a/src/Core/Menus.fs +++ b/src/Core/Menus.fs @@ -75,18 +75,13 @@ let render (render: 'reactElement RenderApi) (menus: MenuOutput list) = let rec recur shortCircuit (render, renderMe: (string * 'reactElement list) -> 'reactElement) menu : 'reactElement = // renderMe lets us delay rendering of a checked/unchecked option inside an either until we have data about its label and children. - let (|OneSelection|_|) lst = - match lst |> List.filter Tuple3.get1 with - | [true, key, v] -> Some (key, v) - | _ -> None - // if we're inside of a collapsed EITHER, then convert any and all leaves into checkboxes that can uncheck part of this EITHER and uncollapse it let collapsedRender key = { render with unconditional = fun (label, children) -> render.checked'(label, key, children) } match menu with - | Either(None, OneSelection (key, child)) -> - // if the either has no label and is already ready, just omit it from the visual tree and show the child directly. I'm not sure it's correct to ignore renderMe though. + | Either(_, [true, key, child]) -> + // if the either has exactly one option (presumably because others are filtered out as unselected), just omit it from the visual tree and show the child directly. I'm not sure it's correct to ignore renderMe though. let renderChild (label, children) = render.checked'(label, key, children) recur shortCircuit (collapsedRender key, renderChild) child | Either(label, selections) -> @@ -255,6 +250,9 @@ type Op = | lst when lst.Length = n -> Fulfilled(lst |> List.collect fst, lst |> List.map snd) | lst when lst.Length > 0 -> Partial(lst |> List.collect fst, children |> List.map snd) // return all child menus so user can keep selecting | _ -> Fallback([], children |> List.map snd) // return all child menus so user can keep selecting + let config = + if config.inner.label.IsSome || n = 1 then config + else { config with inner = { config.inner with label = Some $"Choose {n}:" } } eitherF (|Fulfilled|Partial|Fallback|) [] options config static member and' (offers: 't OptionOffer list) : 't ListOffer = diff --git a/test/Chargen.Accept.fs b/test/Chargen.Accept.fs index bc69caa..c7f5a8c 100644 --- a/test/Chargen.Accept.fs +++ b/test/Chargen.Accept.fs @@ -278,7 +278,7 @@ let tests = // swash is not a MenuOutput but it can create MenuOutputs which can then be either unit tested or turned into ReactElements let expectedMenus = [ Leveled("Stealth +1", key "Stealth", 0, 3) // Leveled because it can go up to +3 - Either(None, [ + Either(Some "Choose 2:", [ false, key "Combat Reflexes", Leaf "Combat Reflexes" false, key "Acrobatics", Leaf "Acrobatics +1" true, key "Climbing +1", Leaf "Climbing +1" // Leaf not Level because swash() template is only using trait', not level @@ -309,7 +309,7 @@ let tests = match pseudoActual with | Fragment([ NumberInput(Expect "Stealth +1", Expect ["Stealth"], Expect 0, Expect 3) - Unconditional(Expect "Choose one:", [ + Unconditional(Expect "Choose 2:", [ Unchecked(Expect "Combat Reflexes", Expect ["Combat Reflexes"]) Unchecked(Expect "Acrobatics +1", Expect ["Acrobatics"]) // note: Acrobatics is the key here, not Acrobatics +1, because it's leveled. Checked(Expect "Climbing +1", Expect ["Climbing +1"], [])