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
9 changes: 9 additions & 0 deletions .pubignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,12 @@ coverage/
# macOS artifacts
**/.DS_Store
**/Pods/

# Sub-packages are published on their own; the root package depends on
# hyper_render_core through pub.dev, so shipping their sources only doubles
# the archive size.
packages/

# Screen-recording entry point for the README GIFs (reads a local /tmp file);
# nothing imports it.
example/lib/demo_auto_player.dart
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 1.13.1

Packaging and documentation only; no code changes in the library.

- **Smaller download:** the archive no longer ships `packages/` (the sub-packages are published on their own and `hyper_render_core` is a normal pub.dev dependency) or the GIF-recording entry point `example/lib/demo_auto_player.dart`. About 32 MB → 18 MB.
- **Docs corrected:** every `widgetBuilder: (context, node) { ... }` example (README, MIGRATION, security and performance guides) did not compile. The callback is `Widget? Function(UDTNode node)`. `node.isImage` does not exist; examples use `node.tagName == 'img'`.
- **Docs no longer over-claim:** `box-sizing` and `position: relative` were listed as supported. They are parsed but not applied (`width` always sizes the content box; `top`/`left` do not move the element). The CSS matrix, `SUPPORTED_HTML.md` and `LIMITATIONS.md` now say so, and the docs-sync test guards both rows.

## 1.13.0

- **Character-range highlight boxes:** `RenderHyperBox.getBoxesForCharRange(charStart, charEnd)` returns the rects of a character range, for drawing your own highlights (search hits, annotations, read-aloud). Offsets are local to each `RenderHyperBox`, so in virtualized / `auto` mode (>10k chars) they restart at 0 per chunk. Also new: `RenderHyperBox.debugLineFragments()` for the laid-out fragment geometry. By [@DrkXo](https://github.com/DrkXo) ([#26](https://github.com/brewkits/hyper_render/pull/26)).
Expand Down
2 changes: 1 addition & 1 deletion MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ HtmlWidget(
// HyperRender
HyperViewer(
html: html,
widgetBuilder: (context, node) {
widgetBuilder: (node) {
if (node is AtomicNode && node.tagName == 'iframe') return MyWidget();
return null; // fall through to default rendering
},
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Already using `flutter_html`? You don't need to rewrite your widget tree or lear
```dart
// 1. In your pubspec.yaml:
// dependencies:
// hyper_render: ^1.13.0
// hyper_render: ^1.13.1

// 2. In your Dart file — replace this single line:
// ❌ import 'package:flutter_html/flutter_html.dart';
Expand Down Expand Up @@ -68,7 +68,7 @@ Html(

```yaml
dependencies:
hyper_render: ^1.13.0
hyper_render: ^1.13.1
```

```dart
Expand Down Expand Up @@ -432,7 +432,7 @@ ctrl.scrollToOffset(1200); // absolute pixel offset
```dart
HyperViewer(
html: html,
widgetBuilder: (context, node) {
widgetBuilder: (node) {
if (node is AtomicNode && node.tagName == 'iframe') {
return YoutubePlayer(url: node.attributes['src'] ?? '');
}
Expand Down
4 changes: 2 additions & 2 deletions doc/CSS_PROPERTIES_MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ This document lists CSS property support in HyperRender.
| `border-style` | ✅ | solid, dashed, dotted, double, none | Custom styles beyond Flutter defaults |
| `border-color` | ✅ | All color formats | |
| `border-radius` | ✅ | px, % | All 4 corners + shorthand |
| `box-sizing` | ✅ | border-box, content-box | Full support |
| `box-sizing` | ❌ | — | Parsed, not applied: `width` always sizes the content box, so `border-box` is ignored (measured: `width:200px;padding:20px` wraps at 200px with or without it) |
| `aspect-ratio` | ✅ | W/H, bare number, auto | Applied to img/video sizing (v1.4.0) |

---
Expand All @@ -59,7 +59,7 @@ This document lists CSS property support in HyperRender.
| `opacity` | ✅ | 0-1 | |
| `overflow` | ⚠️ | hidden, visible | No scroll support |
| `position: static` | ✅ | static | Default |
| `position: relative` | ✅ | relative | Supported |
| `position: relative` | ❌ | — | Parsed, not applied: `top` / `left` offsets do not move the element |
| `position: absolute` | ❌ | — | Use `pluginRegistry` for overlay widgets |
| `position: fixed` | ❌ | — | Use `pluginRegistry` for overlay widgets |
| `top` / `right` / `bottom` / `left` | ❌ | — | Requires absolute/fixed; not supported |
Expand Down
2 changes: 1 addition & 1 deletion doc/LIMITATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ are silently ignored.
| Property | Limitation |
|----------|------------|
| `opacity` | Applied per-element; stacking context opacity not propagated |
| `position: relative` | Supported but child `absolute` positioning is not |
| `position: relative` / `box-sizing: border-box` | Parsed but not applied: no offset for `relative`, and `width` always sizes the content box |
| `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) |
| `float` scope | A float reserves a box from the element's own `width`/`height`; it does **not** lay the floated element's content out inside that box. So float works for replaced elements (`<img style="float:left">`) and for empty, explicitly sized boxes (`<div style="float:left;width:150px;height:120px">`) — text wraps beside both. It does **not** work for an element sized by its own text: a floated `<div>` with content renders that content in normal flow while still reserving a phantom float box, which can make the block *taller* than not floating it; a floated inline `<span>` (the drop-cap idiom) has no effect at all. Pinned by `test/flagship_execution_audit_test.dart` |
Expand Down
16 changes: 8 additions & 8 deletions doc/PERFORMANCE_TUNING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Performance Tuning Guide

Last Updated: June 2026
Version: 1.4.0
Last Updated: October 2026
Version: 1.13.0

This guide helps you optimize HyperRender performance for different use cases.

Expand Down Expand Up @@ -40,7 +40,7 @@ DON'T:

HyperRender offers 3 render modes optimized for different scenarios:

### 1. HyperRenderMode.sync (Default for small content)
### 1. HyperRenderMode.sync (best for small content)

How it works:
- Parses HTML on main thread (synchronous)
Expand Down Expand Up @@ -170,7 +170,7 @@ void main() {
```dart
HyperViewer(
html: content,
widgetBuilder: (context, node) {
widgetBuilder: (node) {
if (node is AtomicNode && node.tagName == 'img') {
final src = node.src;
if (src == null) return null;
Expand Down Expand Up @@ -421,8 +421,8 @@ HyperViewer(
)

// Lazy-load images
widgetBuilder: (context, node) {
if (node is AtomicNode && node.isImage) {
widgetBuilder: (node) {
if (node is AtomicNode && node.tagName == 'img') {
return CachedNetworkImage(
imageUrl: node.src!,
placeholder: (context, url) => Shimmer(...),
Expand Down Expand Up @@ -513,8 +513,8 @@ HyperViewer(
```dart
HyperViewer(
html: content,
widgetBuilder: (context, node) {
if (node is AtomicNode && node.isImage) {
widgetBuilder: (node) {
if (node is AtomicNode && node.tagName == 'img') {
return CachedNetworkImage(
imageUrl: node.src!,
memCacheWidth: 800,
Expand Down
2 changes: 1 addition & 1 deletion doc/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# HyperRender Documentation

Welcome to the documentation for **HyperRender v1.13.0** — the high-performance HTML/Markdown renderer for Flutter.
Welcome to the documentation for **HyperRender v1.13.1** — the high-performance HTML/Markdown renderer for Flutter.

## Documentation Index

Expand Down
6 changes: 3 additions & 3 deletions doc/SECURITY_BEST_PRACTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ When using `widgetBuilder`, validate the input:
```dart
HyperViewer(
html: content,
widgetBuilder: (context, node) {
widgetBuilder: (node) {
// Validate node properties
if (node.tagName == 'custom-widget') {
final dataUrl = node.attributes['data-url'];
Expand All @@ -295,7 +295,7 @@ HyperViewer(
```dart
HyperViewer(
html: content,
widgetBuilder: (context, node) {
widgetBuilder: (node) {
if (node is AtomicNode && node.isVideo) {
final videoUrl = node.src;

Expand Down Expand Up @@ -412,7 +412,7 @@ Defense:
allowedTags: const {'p', 'strong', 'em'}, // No 'img'

// Option 2: Proxy images through your server
widgetBuilder: (context, node) {
widgetBuilder: (node) {
if (node is AtomicNode && node.tagName == 'img') {
final src = node.src;
if (src != null && src.startsWith('https://yourcdn.com/')) {
Expand Down
6 changes: 3 additions & 3 deletions doc/SUPPORTED_HTML.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ or the `fallbackBuilder` parameter to delegate to a WebView or other renderer.
| `border` | width, style, color |
| `border-style` | solid, dashed, dotted, double, none |
| `border-radius` | px, % |
| `box-sizing` | border-box, content-box |
| `box-sizing` | **Not applied** — `width` always sizes the content box |
| `overflow` | visible, hidden |

### Layout
Expand All @@ -107,7 +107,7 @@ or the `fallbackBuilder` parameter to delegate to a WebView or other renderer.
| `display` | block, inline, inline-block, none, flex, grid, table |
| `float` | left, right, none (Full wrapping support) |
| `clear` | left, right, both, none |
| `position` | **relative only** |
| `position` | **Not applied** — `static` flow only (no `relative` offsets, `absolute`, `fixed`) |
| Flexbox | Containers and items, incl. wrapping flex on a dedicated `RenderFlexWrap` (v1.9.0). Not applied: `align-content`; `flex-basis` drives wrapping containers only |
| CSS Grid | `grid-template-columns/rows` (px, fr, auto, repeat), `grid-column/row` span, gap (v1.2.0). Not applied: `grid-auto-flow`, `align-content` |

Expand Down Expand Up @@ -162,4 +162,4 @@ or the `fallbackBuilder` parameter to delegate to a WebView or other renderer.

---

*Last updated: April 29, 2026 — HyperRender v1.3.0*
*Last updated: October 10, 2026 — HyperRender v1.13.0*
7 changes: 3 additions & 4 deletions example/lib/formula_demo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -519,10 +519,9 @@ FormulaWidget(
color: DemoColors.warning),
_CodeSnippet(
code: r'''// Apply flutter_math_fork to ALL formulas in a document
HyperViewer(
html: myDeltaJson,
format: HyperRenderFormat.delta,
widgetBuilder: (context, node) {
HyperViewer.delta(
delta: myDeltaJson,
widgetBuilder: (node) {
if (node is AtomicNode && node.tagName == 'formula') {
final formula = node.attributes['data'] ?? '';
return Math.tex(formula,
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: hyper_render
description: "The only Flutter HTML/Markdown renderer with CSS float layout, crash-free text selection at any document size, CJK Ruby typography, and AI/LLM token streaming."
version: 1.13.0
version: 1.13.1
homepage: https://github.com/brewkits/hyper_render
repository: https://github.com/brewkits/hyper_render
issue_tracker: https://github.com/brewkits/hyper_render/issues
Expand Down
4 changes: 4 additions & 0 deletions test/docs_matrix_sync_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ const _executionVerified = <String>[
const _mustNotBeFull = <String>[
'position: absolute',
'position: fixed',
// Parsed into ComputedStyle and read by nothing in the render path; checked
// by laying out `width:200px;padding:20px` with and without border-box.
'position: relative',
'box-sizing',
'z-index',
// Parsed into ComputedStyle and read by nothing in the render path —
// measured, not assumed, by test/flagship_execution_audit_test.dart.
Expand Down
Loading