clay icon indicating copy to clipboard operation
clay copied to clipboard

[Core/Sugar] Allow non-fixed sizing for padding and gap

Open lakazatong opened this issue 3 months ago • 2 comments

Overview

Extend .padding and .gap to support explicit sizing rules: CLAY_SIZING_FIXED, CLAY_SIZING_GROW, or CLAY_SIZING_PERCENT.

Current API (fixed only):

.padding = CLAY_PADDING_ALL(100)

Proposed API:

.padding = CLAY_PADDING_ALL(CLAY_SIZING_FIXED(100))
.padding = CLAY_PADDING_ALL(CLAY_SIZING_GROW(100))
.padding = CLAY_PADDING_ALL(CLAY_SIZING_PERCENT(50))

Implementation suggestion

Padding

Step 1 - Along the layout axis:

  • For each side with a non-fixed sizing rule:
    • Set the numeric padding to 0.
    • Insert an invisible spacer node on that side sized according to the rule.

Step 2 - Across the layout axis:

  • If either side across the axis is non-fixed:
    • Wrap all children (including any non-fixed padding spacer nodes from step 1) in a container.
    • Flip the parent's layout axis.
    • Apply the same padding logic as in step 1.

Gap

Step 1 - Along the layout axis:

  • If the gap has a non-fixed sizing rule:
    • Set the numeric gap to 0.
    • Insert an invisible spacer node between each child sized according to the rule.

Step 2 - Across the layout axis:

  • Gap doesn't apply across the layout axis.

Example

.padding = { .left = CLAY_SIZING_GROW(100), .right = CLAY_SIZING_FIXED(100) }
.gap = CLAY_SIZING_PERCENT(10)

Benefits / Drawbacks

Benefits

  • Consistent with the rest of the API.
  • Avoids manual invisible spacer node gymnastics currently needed for dynamic padding or gaps.

Drawbacks

  • Non-fixed gaps nearly double the children count.
  • Following the suggested implementation, padding across the axis with non-fixed sizing will generate an unexpected tree structure, it works as sugar rather than being fully native.
  • It's quite verbose for most of the cases where one just wants fixed size padding or gap, I suggest .padding = { .right = CLAY_SIZING_FIXED(100) } and .padding = { .right = 100 } to work the same (tbh CLAY_SIZING_FIXED should always be optional, only nice for code generators that would have something like CLAY_SIZING_{mode}({x}) for convenience)

Note

This proposal is concerned primarily with API design and developer experience, not implementation constraints. Ideally, implementation details should adapt to the API, not the other way around, to keep the library intuitive and consistent, while the suggested implementation is provided only to aid maintainers.

lakazatong avatar Oct 04 '25 21:10 lakazatong

How frequently do you need this feature in your project? If it's a specific widget that requires dynamic padding, can't it be abstracted into a function so that the spacer trickery is in a single place in code?

SolidAlloy avatar Oct 06 '25 15:10 SolidAlloy

I haven't started a project with Clay yet. It's a long story, so I'll just say I experimented with layout engines as a whole and ended up finding out Clay couldn't express the idea of flexible padding and gap without using invisible spacer elements (which is fine actually, it's just for the sake of API consistency and QOF feature). Clay is definitely a big source of inspiration lol.

I agree it's probably a niche use case, but when making responsive UIs (which Clay is trying to be by default as much as possible, or at least give the right tools to make it so) it could be considered. Making it built-in could make developers more inclined to use it, because it's something they might have never considered before. Exposing it could help.

Beyond all that, it would remove friction for any future user of this library that would want dynamic padding and/or gap (for all children). Making the life of the developer easier is one of the top priority of a library like Clay. Again, it also makes the sizing API consistent.

It wouldn't be the first time Clay encourages to make invisible spacer elements, in the first introduction to Clay video (around 25:00), Nic uses a grow container to push some elements to the right, exactly what I described in my dynamic gap suggestion. Though, it would have made them all grow, not a specific one, in that case one would make the spacer element manually and insert it in the right place. I wouldn't push it as far as saying Clay needs a way of abstracting even that out.

lakazatong avatar Oct 06 '25 17:10 lakazatong