Lay a row out from its end on the phone too
`:align` was a prop the Flutter backend never read. Every hbox came out laid from the left, which for `:align :end` is not a shade off — it is the order reversed: glimmer lays an end-aligned row's first child furthest right, so the message heading's chips, written react-then-reply-then-pencil to read pencil-then-reply-then-react, came out with the pencil last. Last in a row that also never took the width left over from the nick and the clock, so on a phone it was past the edge of the screen and a line you wrote yourself had nothing on it to rewrite it with. So `:align` is `mainAxisAlignment` now, and `:end` reverses the children to mean what it means over there. An end-aligned row fills its parent as well — there is no edge to sit against inside a row the width of its own children, which is the same reason `fills-row?` already answered for an entry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
23b7999 parent: 1528bb0 modified
flutter/src/frq/hiccup.cljd +44 -18 | @@ -136,12 +136,20 @@ | ||
| 136 | 136 | |
| 137 | 137 | jolt-cosmic gives an entry Length::Fixed(w) when it has a width and |
| 138 | 138 | Length::Fill otherwise; Fill in a Row is Flutter's Expanded. A TextField that |
| 139 | - is neither is offered unbounded width, which is a layout error." | |
| 139 | + is neither is offered unbounded width, which is a layout error. | |
| 140 | + | |
| 141 | + A row aligned to its end fills too, for the same reason it does in glimmer: | |
| 142 | + `:align :end` is \"against the right edge of what is left\", and a row sized | |
| 143 | + to its own children has no left-over to sit at the end of. The message | |
| 144 | + heading is the one that showed it — the chips rode along directly after the | |
| 145 | + clock, and on a phone the last of them was off the edge of the screen." | |
| 140 | 146 | [node] |
| 141 | 147 | (and (vector? node) |
| 142 | - (= :entry (first node)) | |
| 143 | 148 | (let [p (second node)] |
| 144 | - (or (not (map? p)) (nil? (width-of p)) (:hexpand p))))) | |
| 149 | + (case (first node) | |
| 150 | + :entry (or (not (map? p)) (nil? (width-of p)) (:hexpand p)) | |
| 151 | + :hbox (and (map? p) (= :end (:align p))) | |
| 152 | + false)))) | |
| 145 | 153 | |
| 146 | 154 | (declare body) |
| 147 | 155 | |
| @@ -526,21 +534,39 @@ | ||
| 526 | 534 | .runSpacing (dbl (:spacing p) 0.0) |
| 527 | 535 | .crossAxisAlignment m/WrapCrossAlignment.center |
| 528 | 536 | .children kids) |
| 529 | - (m/Row | |
| 530 | - ;; Stretch when a child fills vertically: a Row hands its | |
| 531 | - ;; children a loose height by default, and a column that | |
| 532 | - ;; wants what is left of it needs a tight one. | |
| 533 | - .crossAxisAlignment (if (some #(fills-column? (expand %)) (body node)) | |
| 534 | - m/CrossAxisAlignment.stretch | |
| 535 | - m/CrossAxisAlignment.center) | |
| 536 | - ;; A row holding something that fills has to be given the | |
| 537 | - ;; width to divide, so it is max rather than min whenever a | |
| 538 | - ;; child asks. | |
| 539 | - .mainAxisSize (if (some #(fills-row? (expand %)) (body node)) | |
| 540 | - m/MainAxisSize.max | |
| 541 | - m/MainAxisSize.min) | |
| 542 | - .spacing (dbl (:spacing p) 0.0) | |
| 543 | - .children (flexed fills-row? (body node))))] | |
| 537 | + ;; `:align` is where in the row its children sit, and it is | |
| 538 | + ;; glimmer's meaning that the shared screens are written | |
| 539 | + ;; against: `:end` lays them out *from* the right, so the | |
| 540 | + ;; first child in the source is the rightmost on screen. | |
| 541 | + ;; Ignoring it put the message heading's chips in the | |
| 542 | + ;; opposite order and left the pencil — the one written | |
| 543 | + ;; first so it would land beside the words — hanging off the | |
| 544 | + ;; end of a phone's width, which is why a line you wrote had | |
| 545 | + ;; no way to rewrite it. | |
| 546 | + (let [end? (= :end (:align p)) | |
| 547 | + kids (flexed fills-row? (body node))] | |
| 548 | + (m/Row | |
| 549 | + .mainAxisAlignment (case (:align p) | |
| 550 | + :end m/MainAxisAlignment.end | |
| 551 | + :center m/MainAxisAlignment.center | |
| 552 | + m/MainAxisAlignment.start) | |
| 553 | + ;; Stretch when a child fills vertically: a Row hands its | |
| 554 | + ;; children a loose height by default, and a column that | |
| 555 | + ;; wants what is left of it needs a tight one. | |
| 556 | + .crossAxisAlignment (if (some #(fills-column? (expand %)) (body node)) | |
| 557 | + m/CrossAxisAlignment.stretch | |
| 558 | + m/CrossAxisAlignment.center) | |
| 559 | + ;; A row holding something that fills has to be given the | |
| 560 | + ;; width to divide, so it is max rather than min whenever a | |
| 561 | + ;; child asks. A row aligned to an edge needs it too: there | |
| 562 | + ;; is no edge to sit against inside a row the width of its | |
| 563 | + ;; own children. | |
| 564 | + .mainAxisSize (if (or end? | |
| 565 | + (some #(fills-row? (expand %)) (body node))) | |
| 566 | + m/MainAxisSize.max | |
| 567 | + m/MainAxisSize.min) | |
| 568 | + .spacing (dbl (:spacing p) 0.0) | |
| 569 | + .children (if end? (vec (reverse kids)) kids))))] | |
| 544 | 570 | (if-let [mg (insets-of p)] |
| 545 | 571 | (m/Padding .padding mg .child row) |
| 546 | 572 | row)) |
| @@ -136,12 +136,20 @@ | |||
| 136 | 136 | ||
| 137 | jolt-cosmic gives an entry Length::Fixed(w) when it has a width and | 137 | jolt-cosmic gives an entry Length::Fixed(w) when it has a width and |
| 138 | Length::Fill otherwise; Fill in a Row is Flutter's Expanded. A TextField that | 138 | Length::Fill otherwise; Fill in a Row is Flutter's Expanded. A TextField that |
| 139 | - is neither is offered unbounded width, which is a layout error." | 139 | + is neither is offered unbounded width, which is a layout error. |
| 140 | + | ||
| 141 | + A row aligned to its end fills too, for the same reason it does in glimmer: | ||
| 142 | + `:align :end` is \"against the right edge of what is left\", and a row sized | ||
| 143 | + to its own children has no left-over to sit at the end of. The message | ||
| 144 | + heading is the one that showed it — the chips rode along directly after the | ||
| 145 | + clock, and on a phone the last of them was off the edge of the screen." | ||
| 140 | [node] | 146 | [node] |
| 141 | (and (vector? node) | 147 | (and (vector? node) |
| 142 | - (= :entry (first node)) | ||
| 143 | (let [p (second node)] | 148 | (let [p (second node)] |
| 144 | - (or (not (map? p)) (nil? (width-of p)) (:hexpand p))))) | 149 | + (case (first node) |
| 150 | + :entry (or (not (map? p)) (nil? (width-of p)) (:hexpand p)) | ||
| 151 | + :hbox (and (map? p) (= :end (:align p))) | ||
| 152 | + false)))) | ||
| 145 | 153 | ||
| 146 | (declare body) | 154 | (declare body) |
| 147 | 155 | ||
| @@ -526,21 +534,39 @@ | |||
| 526 | .runSpacing (dbl (:spacing p) 0.0) | 534 | .runSpacing (dbl (:spacing p) 0.0) |
| 527 | .crossAxisAlignment m/WrapCrossAlignment.center | 535 | .crossAxisAlignment m/WrapCrossAlignment.center |
| 528 | .children kids) | 536 | .children kids) |
| 529 | - (m/Row | 537 | + ;; `:align` is where in the row its children sit, and it is |
| 530 | - ;; Stretch when a child fills vertically: a Row hands its | 538 | + ;; glimmer's meaning that the shared screens are written |
| 531 | - ;; children a loose height by default, and a column that | 539 | + ;; against: `:end` lays them out *from* the right, so the |
| 532 | - ;; wants what is left of it needs a tight one. | 540 | + ;; first child in the source is the rightmost on screen. |
| 533 | - .crossAxisAlignment (if (some #(fills-column? (expand %)) (body node)) | 541 | + ;; Ignoring it put the message heading's chips in the |
| 534 | - m/CrossAxisAlignment.stretch | 542 | + ;; opposite order and left the pencil — the one written |
| 535 | - m/CrossAxisAlignment.center) | 543 | + ;; first so it would land beside the words — hanging off the |
| 536 | - ;; A row holding something that fills has to be given the | 544 | + ;; end of a phone's width, which is why a line you wrote had |
| 537 | - ;; width to divide, so it is max rather than min whenever a | 545 | + ;; no way to rewrite it. |
| 538 | - ;; child asks. | 546 | + (let [end? (= :end (:align p)) |
| 539 | - .mainAxisSize (if (some #(fills-row? (expand %)) (body node)) | 547 | + kids (flexed fills-row? (body node))] |
| 540 | - m/MainAxisSize.max | 548 | + (m/Row |
| 541 | - m/MainAxisSize.min) | 549 | + .mainAxisAlignment (case (:align p) |
| 542 | - .spacing (dbl (:spacing p) 0.0) | 550 | + :end m/MainAxisAlignment.end |
| 543 | - .children (flexed fills-row? (body node))))] | 551 | + :center m/MainAxisAlignment.center |
| 552 | + m/MainAxisAlignment.start) | ||
| 553 | + ;; Stretch when a child fills vertically: a Row hands its | ||
| 554 | + ;; children a loose height by default, and a column that | ||
| 555 | + ;; wants what is left of it needs a tight one. | ||
| 556 | + .crossAxisAlignment (if (some #(fills-column? (expand %)) (body node)) | ||
| 557 | + m/CrossAxisAlignment.stretch | ||
| 558 | + m/CrossAxisAlignment.center) | ||
| 559 | + ;; A row holding something that fills has to be given the | ||
| 560 | + ;; width to divide, so it is max rather than min whenever a | ||
| 561 | + ;; child asks. A row aligned to an edge needs it too: there | ||
| 562 | + ;; is no edge to sit against inside a row the width of its | ||
| 563 | + ;; own children. | ||
| 564 | + .mainAxisSize (if (or end? | ||
| 565 | + (some #(fills-row? (expand %)) (body node))) | ||
| 566 | + m/MainAxisSize.max | ||
| 567 | + m/MainAxisSize.min) | ||
| 568 | + .spacing (dbl (:spacing p) 0.0) | ||
| 569 | + .children (if end? (vec (reverse kids)) kids))))] | ||
| 544 | (if-let [mg (insets-of p)] | 570 | (if-let [mg (insets-of p)] |
| 545 | (m/Padding .padding mg .child row) | 571 | (m/Padding .padding mg .child row) |
| 546 | row)) | 572 | row)) |