Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@

- **`box-sizing`** now applies ([#33](https://github.com/brewkits/hyper_render/issues/33)): `border-box` includes padding and border in `width` / `min-width` / `max-width`, including `%`, on in-flow blocks. Limits are in `doc/LIMITATIONS.md`.
- **`position: relative`** now applies ([#34](https://github.com/brewkits/hyper_render/issues/34)): `top` / `right` / `bottom` / `left` (lengths) move blocks, inline spans and flex/grid items without affecting layout, and hit-testing and selection follow. Moved content paints above normal content and is clipped to the render box, so untrusted HTML can't paint over the host app. Other content stays unclipped.
- **Horizontal block margins** now apply: `margin-left`, `margin-right` and `margin: 0 auto` inset or centre in-flow blocks. They used to have no effect, so a `max-width` layout sat at the left edge.
- **Rendering changes:**
- A block's background and border now follow its `width`. They used to span the whole container.
- `min-width: %` now applies on blocks.
- A first block styled only with a background or border now paints it.
- Gradients on canvas blocks and inline spans now paint. They painted nothing.
- A `<details>` toggle no longer leaves a block's old background behind.
- A float now sits inside its containing block. It used to sit at the render box edge, ignoring a parent's padding.
- A `<pre>` now fits inside its parent's padding instead of overflowing.
- In RTL, a block with a `width` anchors to the right edge.
- `margin` in `em` now uses the element's font size, not the root's.
- Inline `!important` no longer makes a value invalid: `style="margin-left:10px !important"` used to be dropped.
- `HyperViewer(textDirection:)` and an ambient RTL `Directionality` now apply to short documents in sync mode. Virtualized and paged modes already honoured them.
- **Requires `hyper_render_core` `^1.14.0`.**

Expand Down
10 changes: 5 additions & 5 deletions doc/CSS_PROPERTIES_MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ This document lists CSS property support in HyperRender.
| `max-width` | ✅ | px, % | Constrains a block's content width (text wraps inside it) |
| `min-height` | ❌ | — | Parsed into `ComputedStyle.minHeight`, then read by nothing in the render path. Found by `test/flagship_execution_audit_test.dart` |
| `max-height` | ❌ | — | Parsed into `ComputedStyle.maxHeight`, then read by nothing in the render path. Found by `test/flagship_execution_audit_test.dart` |
| `margin` | ✅ | px, %, auto | All 4 directions + shorthand |
| `margin-top` | ✅ | px, %, auto | |
| `margin-right` | ✅ | px, %, auto | |
| `margin-bottom` | ✅ | px, %, auto | |
| `margin-left` | ✅ | px, %, auto | |
| `margin` | ✅ | px, em, rem, auto | All 4 directions + shorthand. `%` not supported. `auto` centres in-flow blocks with a width; see [LIMITATIONS.md](LIMITATIONS.md) |
| `margin-top` | ✅ | px, em, rem | |
| `margin-right` | ✅ | px, em, rem, auto | |
| `margin-bottom` | ✅ | px, em, rem | |
| `margin-left` | ✅ | px, em, rem, auto | |
| `padding` | ✅ | px, % | All 4 directions + shorthand |
| `padding-top` | ✅ | px, % | |
| `padding-right` | ✅ | px, % | |
Expand Down
2 changes: 1 addition & 1 deletion doc/LIMITATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ are silently ignored.
|----------|------------|
| `opacity` | Applied per-element; stacking context opacity not propagated |
| `box-sizing: border-box` | Applied on in-flow blocks only. Borders don't reserve layout space, so text can overlap a border. A flex item's `width` already includes its padding whatever `box-sizing` says. `width` has no effect on a flex or grid container, `<table>` or `<td>`, and floated images ignore padding, so `box-sizing` changes nothing there |
| Horizontal block `margin` | `margin-left`, `margin-right` and `margin: 0 auto` have no effect on an in-flow block, so a block with a `width` always sits at the left edge and can't be centred this way |
| Horizontal `margin` | Applies to in-flow blocks and flex/grid containers. `%` is not supported. `auto` works on in-flow blocks with a `width`, `max-width` or `min-width`, but not on flex/grid containers or items, tables or images. Negative margins can reach into a parent's padding but stay inside the render box. A large container flattened for virtualization loses its margins and width, so a long `max-width; margin: 0 auto` article renders full-width: set them on its children, or use `mode: HyperRenderMode.sync` |
| `position: relative` | Lengths only: `%` offsets are ignored. Moved content paints above normal content but in no finer order (no `z-index` or stacking contexts), and is clipped to the render box so it can't paint over the host app (the sanitizer doesn't filter CSS properties). In virtualized mode that box is one chunk. A flex or grid item moved past its container is still visible inside the box. Not applied to `<td>`. A large container flattened for virtualization loses its offset |
| `calc()` | Arithmetic on px/em/rem only; `%` in calc not resolved |
| `text-align` | Center/right/justify on canvas paragraphs, LTR and box-level RTL (`textDirection: rtl`). An explicit `text-align` overrides RTL's default right edge; `justify` in RTL is not yet distributed (keeps the start edge) |
Expand Down
3 changes: 2 additions & 1 deletion packages/hyper_render_core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

- **`box-sizing`:** new `ComputedStyle.boxSizing` / `HyperBoxSizing`. `border-box` applies to `width` / `min-width` / `max-width`, including `%`, on in-flow blocks.
- **`position: relative`:** `top` / `right` / `bottom` / `left` (lengths) move blocks, inline spans and flex/grid items without affecting layout. New `ComputedStyle.insetTop` / `insetRight` / `insetBottom` / `insetLeft` and `relativeOffset()`. Hit-testing and selection follow; moved content paints above normal content, clipped to the render box.
- **Behavior changes:** a block's background and border follow its `width`; `min-width: %` applies on blocks; a first block styled only with a background or border paints it; canvas gradients paint; a `<details>` toggle no longer leaves an old background behind.
- **Horizontal block margins:** `margin-left`, `margin-right` and `margin: 0 auto` now apply to in-flow blocks. New `ComputedStyle.marginLeftAuto` / `marginRightAuto`.
- **Behavior changes:** a block's background and border follow its `width`; `min-width: %` applies on blocks; a first block styled only with a background or border paints it; canvas gradients paint; a `<details>` toggle no longer leaves an old background behind. Floats sit inside their containing block, `<pre>` fits its parent's padding, RTL blocks with a `width` anchor right, `margin` `em` uses the element's font size, and inline `!important` no longer invalidates a value.

## 1.13.0

Expand Down
24 changes: 22 additions & 2 deletions packages/hyper_render_core/lib/src/core/render_hyper_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1170,15 +1170,35 @@ class RenderHyperBox extends RenderBox
// magnitude too large for documents with many paragraphs.
double maxWidth = 0;
double lineWidth = 0;
// Horizontal padding and margins of the open blocks. Layout takes these off
// the line, so a host sizing to this width must leave room for them.
final insets = <(UDTNode, double)>[];

void flushLine() {
if (lineWidth > maxWidth) maxWidth = lineWidth;
final total = lineWidth > 0
? lineWidth + (insets.isEmpty ? 0 : insets.last.$2)
: 0.0;
if (total > maxWidth) maxWidth = total;
lineWidth = 0;
}

for (final fragment in _fragments) {
if (fragment is _BlockStartFragment || fragment is _BlockEndFragment) {
if (fragment is _BlockStartFragment) {
flushLine();
final margin = fragment.appliesHorizontalMargins
? fragment.style.margin.left + fragment.style.margin.right
: 0.0;
final own = fragment.paddingLeft + fragment.paddingRight + margin;
insets.add((
fragment.sourceNode,
math.max(0.0, (insets.isEmpty ? 0.0 : insets.last.$2) + own),
));
} else if (fragment is _BlockEndFragment) {
flushLine();
// A first block may have skipped its start fragment, so check the owner.
if (insets.isNotEmpty && insets.last.$1 == fragment.sourceNode) {
insets.removeLast();
}
} else if (fragment.type == FragmentType.lineBreak) {
flushLine();
} else if (fragment.type == FragmentType.text ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ class _BlockStartFragment extends Fragment {
/// and the last fitting fragment gets "…" appended (CSS text-overflow: ellipsis).
final bool truncateWithEllipsis;

/// Whether the line breaker applies this block's left and right margins.
/// False where something else owns them: flex and grid containers draw them
/// in a child widget, and floats handle them in float layout.
final bool appliesHorizontalMargins;

_BlockStartFragment({
required super.sourceNode,
required super.style,
Expand All @@ -22,6 +27,7 @@ class _BlockStartFragment extends Fragment {
this.paddingLeft = 0,
this.paddingRight = 0,
this.truncateWithEllipsis = false,
this.appliesHorizontalMargins = false,
}) : super(type: FragmentType.text, text: '');
}

Expand Down
Loading
Loading