diff --git a/Makefile b/Makefile index 05a2dd1..e2e21e3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ CC = clang TARGET = clayterm.wasm SRC = src/module.c +CLAY_GROW_PATCH = patches/clay-grow-minDimensions.patch CFLAGS = --target=wasm32 -nostdlib -O2 \ -ffunction-sections -fdata-sections \ @@ -47,7 +48,12 @@ all: $(TARGET) wasm.ts DEPS = $(wildcard src/*.c src/*.h) -$(TARGET): $(DEPS) +# Fix GROW element minDimensions so they compress to the parent content box instead of +# expanding beyond the terminal boundary. Idempotent; reverted by `make clean`. +# Drop once the fix ships in upstream clay. +$(TARGET): $(DEPS) $(CLAY_GROW_PATCH) + @grep -q "GROW elements resolve against the parent content box" clay/clay.h || git -C clay apply ../$(CLAY_GROW_PATCH) + @grep -q "GROW elements resolve against the parent content box" clay/clay.h || { echo "ERROR: failed to apply $(CLAY_GROW_PATCH) to clay/clay.h" >&2; exit 1; } $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(SRC) wasm.ts: $(TARGET) @@ -55,5 +61,6 @@ wasm.ts: $(TARGET) clean: rm -f $(TARGET) wasm.ts + -git -C clay checkout -- clay.h .PHONY: all clean diff --git a/patches/clay-grow-minDimensions.patch b/patches/clay-grow-minDimensions.patch new file mode 100644 index 0000000..b2ac0da --- /dev/null +++ b/patches/clay-grow-minDimensions.patch @@ -0,0 +1,34 @@ +diff --git a/clay.h b/clay.h +index 7c967bb..5421621 100644 +--- a/clay.h ++++ b/clay.h +@@ -1921,7 +1921,14 @@ void Clay__CloseElement(void) { + layoutConfig->sizing.width.size.minMax.max = CLAY__MAXFLOAT; + } + openLayoutElement->dimensions.width = CLAY__MIN(CLAY__MAX(openLayoutElement->dimensions.width, layoutConfig->sizing.width.size.minMax.min), layoutConfig->sizing.width.size.minMax.max); +- openLayoutElement->minDimensions.width = CLAY__MIN(CLAY__MAX(openLayoutElement->minDimensions.width, layoutConfig->sizing.width.size.minMax.min), layoutConfig->sizing.width.size.minMax.max); ++ // GROW elements resolve against the parent content box and must be compressible to their ++ // configured min (default 0). Content-derived minDimensions would prevent this compression, ++ // so for GROW we use only the user-configured min, not the content-derived value. ++ if (layoutConfig->sizing.width.type == CLAY__SIZING_TYPE_GROW) { ++ openLayoutElement->minDimensions.width = layoutConfig->sizing.width.size.minMax.min; ++ } else { ++ openLayoutElement->minDimensions.width = CLAY__MIN(CLAY__MAX(openLayoutElement->minDimensions.width, layoutConfig->sizing.width.size.minMax.min), layoutConfig->sizing.width.size.minMax.max); ++ } + } else { + openLayoutElement->dimensions.width = 0; + } +@@ -1932,7 +1939,12 @@ void Clay__CloseElement(void) { + layoutConfig->sizing.height.size.minMax.max = CLAY__MAXFLOAT; + } + openLayoutElement->dimensions.height = CLAY__MIN(CLAY__MAX(openLayoutElement->dimensions.height, layoutConfig->sizing.height.size.minMax.min), layoutConfig->sizing.height.size.minMax.max); +- openLayoutElement->minDimensions.height = CLAY__MIN(CLAY__MAX(openLayoutElement->minDimensions.height, layoutConfig->sizing.height.size.minMax.min), layoutConfig->sizing.height.size.minMax.max); ++ // Same rationale as width: GROW elements use the configured min, not content-derived. ++ if (layoutConfig->sizing.height.type == CLAY__SIZING_TYPE_GROW) { ++ openLayoutElement->minDimensions.height = layoutConfig->sizing.height.size.minMax.min; ++ } else { ++ openLayoutElement->minDimensions.height = CLAY__MIN(CLAY__MAX(openLayoutElement->minDimensions.height, layoutConfig->sizing.height.size.minMax.min), layoutConfig->sizing.height.size.minMax.max); ++ } + } else { + openLayoutElement->dimensions.height = 0; + } diff --git a/specs/renderer-spec.md b/specs/renderer-spec.md index 398e78a..2289a99 100644 --- a/specs/renderer-spec.md +++ b/specs/renderer-spec.md @@ -477,10 +477,16 @@ These functions produce sizing-axis values for use in element layout configuration: ``` -grow(): SizingAxis +grow(min?: number, max?: number): SizingAxis ``` The element expands to fill available space in the parent along this axis. +Available space is computed from the **parent's content box** — the parent's +dimension minus its padding — at every nesting level, regardless of whether the +parent's own size was computed from `fixed()`, `grow()`, or any other mode. A +`grow()` element's minimum size is its configured `min` (default 0), not the +natural size of its content; this ensures it can always be compressed to fit the +parent content box when necessary. ``` fixed(value: number): SizingAxis