feat(core): fall back to defaults when Box properties are unset - #1262
feat(core): fall back to defaults when Box properties are unset#1262posva wants to merge 1 commit into
Conversation
Store raw (possibly undefined) values and derive defaults in getters so that clearing a property restores the original default. Border-related properties now derive the implied border from one place, replacing the initializeBorder hack (anomalyco#186). Explicit border: false now wins over border-implying props.
|
I think that makes sense and I would support that. I had GPT Sol do a review pass and here are its findings:
<box customBorderChars={BorderChars.double} borderStyle={style()} />
// undefined -> "heavy" -> undefinedThe custom prop remains present, but the renderable forgets it and ultimately turns the border off. Confirmed end-to-end in both React and Solid.
<box {...props()} /> // { borderStyle: "double" } -> {}
<box style={style()} /> // { backgroundColor: "red" } -> {}The border remains enabled and the background remains red. Direct signal props work, but the PR does not fulfill its stated behavior for supported Solid APIs.
|
|
Hello, while working on Vue TermUI, I faced this "cannot reset to default" problem quite often, so here is a proposal to make it better, starting with the Box renderable.
Why
Frameworks like Vue, React and Solid don't set props once — they update them over time. When a prop is removed from a template or JSX, the framework sets the property to
undefined(ornull) and expects the renderable to go back to its default value. Right now that doesn't work: defaults are copied into private fields when the renderable is created, so once a value is set there is no way back to "unset".Two places where this hurts:
<box :border-color="isActive ? '#f00' : undefined">should show the default border color when inactive, not the last color that was set.The idea (only applied to
BoxRenderablefor now)undefined— the default is never copied in.value ?? default, from a module-levelBOX_DEFAULTSobject. The default is applied when reading, so clearing a property always works.undefinedto mean "go back to the default".Box is a good test case because it has an extra problem: the border has no single source of truth. Setting any of
borderStyle,borderColor,focusedBorderColororcustomBorderCharsturns the border on (#186 — frameworks set props one by one, after the constructor ran), andborderitself can also be set directly. Before, this worked by mutating_borderfrom aninitializeBorder()hook: setting one property could change another behind your back, and removing a prop could never undo it.Now
borderis computed: an explicitbordervalue wins; otherwise the border is on if any border-related property is set; otherwise the default (false). One helper,syncBorderSides(), recomputesborderSidesand the yoga edges after every border-related change, so a setter can't leave the layout out of sync.Behavior changes
backgroundColor,border,borderStyle,borderColor,focusedBorderColor,customBorderChars,titleAlignment,bottomTitleAlignment) now brings back the default.border: falsenow wins over the other border props (before, they silently turned the border on anyway).focusedBorderColorrequests a render even when not focused (it can turn the border on or off, which changes the layout).