Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2e05d30
docs: Comprehensive documentation audit and update for v1.2.3
vietnguyentuan2019 Apr 29, 2026
60ca7d8
feat(v1.2.3): release v1.2.3 with float layout fixes and enhanced tes…
vietnguyentuan2019 Apr 30, 2026
9977238
chore: fix linter warnings and remove layout assertion false-positives
vietnguyentuan2019 May 1, 2026
f2a5968
chore: remove unused import in hyper_viewer.dart
vietnguyentuan2019 May 1, 2026
0ba31a3
fix: ci/cd issues (format, analysis, gradlew permissions)
vietnguyentuan2019 May 1, 2026
fd6f26d
fix: ci/cd workflow issues (golden test exclusion, android emulator a…
vietnguyentuan2019 May 1, 2026
f6f760a
fix(ci): fix analysis and formatting issues
vietnguyentuan2019 May 1, 2026
38a5e7f
chore: regenerate golden references (Flutter 3.41.5) [skip ci]
github-actions[bot] May 1, 2026
f9a9f85
fix(ci): include gradle-wrapper files and fix android compile job
vietnguyentuan2019 May 1, 2026
b9009c1
fix(test): wrap bare <a> in <p> for aria-label WCAG test
vietnguyentuan2019 May 2, 2026
91f47d7
test: add golden tag to critical layouts test
vietnguyentuan2019 May 2, 2026
e7a82e8
fix(example): ensure mobile build readiness for Android and iOS
vietnguyentuan2019 May 2, 2026
b683aa9
fix(core): resolve 16KB page size crash on Android 15 & Apple Silicon
vietnguyentuan2019 May 2, 2026
d2d27d3
fix: 8 bug fixes across layout, markdown, and paint engine (v1.2.4)
vietnguyentuan2019 May 3, 2026
84fbb15
fix(scripts): use correct test command in prepare_publish.sh (exclude…
vietnguyentuan2019 May 3, 2026
6959d42
fix(example/ios): migrate to Flutter scene-based lifecycle (3.29+)
vietnguyentuan2019 May 3, 2026
213051e
fix(example): polish demo display and add float stress test
vietnguyentuan2019 May 3, 2026
be08e4e
fix(example/ios): revert scene lifecycle, restore Rosetta simulator g…
vietnguyentuan2019 May 3, 2026
00dd734
refactor(example): modernize iOS project configuration and prepare fo…
vietnguyentuan2019 May 3, 2026
1c8cb4e
fix(example): fix ios simulator arm64 support and test failures
vietnguyentuan2019 May 3, 2026
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
56 changes: 56 additions & 0 deletions .github/ISSUE_TEMPLATE/plugin_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Plugin Request
description: Request a new HyperRender plugin (e.g. math, charts, diagrams)
title: "[Plugin Request] <plugin name>"
labels: ["plugin", "enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a plugin! Community plugins extend HyperRender without touching the core engine.
Read [PLUGIN_DEVELOPMENT.md](../blob/main/doc/PLUGIN_DEVELOPMENT.md) before submitting to understand what's buildable.

- type: input
id: tag_name
attributes:
label: HTML tag(s) to handle
description: Which custom or standard HTML tag(s) should this plugin render?
placeholder: "<math>, <latex>, <chart>, <mermaid>, ..."
validations:
required: true

- type: textarea
id: use_case
attributes:
label: Use case
description: What content will this plugin render? Where is it used? (CMS, e-book, documentation, etc.)
placeholder: "Our CMS exports math equations as <latex> tags inline with article text. We need them rendered as readable formulas on mobile."
validations:
required: true

- type: dropdown
id: tier
attributes:
label: Plugin tier
description: Block plugins take full width (like images). Inline plugins flow inside text lines (like icons).
options:
- Block (full width, like a figure or table)
- Inline (flows with text, like an icon or badge)
- Not sure
validations:
required: true

- type: textarea
id: proposed_package
attributes:
label: Rendering library (optional)
description: Any Flutter package you'd suggest for the actual rendering?
placeholder: "flutter_math_fork for LaTeX, fl_chart for charts, flutter_svg for SVGs, ..."

- type: checkboxes
id: willing_to_build
attributes:
label: Are you willing to build this?
options:
- label: "Yes — I can submit a PR (see PLUGIN_DEVELOPMENT.md for the guide)"
- label: "No — I'm requesting someone else builds it"
- label: "Partial — I can help review or test but not lead the implementation"
82 changes: 82 additions & 0 deletions .github/ISSUE_TEMPLATE/plugin_submission.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Plugin Submission
description: Submit a community plugin you've built for HyperRender
title: "[Plugin Submission] hyper_render_<name>"
labels: ["plugin", "community"]
body:
- type: markdown
attributes:
value: |
Thanks for building a HyperRender plugin!
Please ensure your plugin meets the requirements in [PLUGIN_DEVELOPMENT.md — PR Requirements](../blob/main/doc/PLUGIN_DEVELOPMENT.md#pr-requirements-for-plugin-prs).

- type: input
id: package_name
attributes:
label: pub.dev package name
description: The package name you plan to publish (follow the `hyper_render_*` naming convention)
placeholder: hyper_render_math
validations:
required: true

- type: input
id: pub_url
attributes:
label: pub.dev URL or GitHub repo
placeholder: "https://github.com/yourname/hyper_render_math"
validations:
required: true

- type: input
id: tag_name
attributes:
label: HTML tag(s) handled
placeholder: "<math>, <latex>"
validations:
required: true

- type: dropdown
id: tier
attributes:
label: Plugin tier
options:
- Block (isInline == false)
- Inline (isInline == true)
- Both
validations:
required: true

- type: textarea
id: description
attributes:
label: What does it render?
description: One paragraph description for the plugin listing.
validations:
required: true

- type: textarea
id: dependencies
attributes:
label: External dependencies
description: List any Flutter packages your plugin depends on (so users know the transitive deps).
placeholder: "flutter_math_fork ^0.7.2"

- type: checkboxes
id: checklist
attributes:
label: Submission checklist
description: All items must be checked before the plugin can be listed.
options:
- label: "Package implements `HyperNodePlugin` from `hyper_render_core`"
required: true
- label: "`build()` returns `null` for unrecognized nodes (safe fallthrough)"
required: true
- label: "At least one widget test covering the happy path"
required: true
- label: "README includes a working code example"
required: true
- label: "CHANGELOG has an initial entry"
required: true
- label: "pubspec.yaml specifies `hyper_render_core: ^1.2.0` or later"
required: true
- label: "Tested on at least one mobile platform (iOS or Android)"
required: true
2 changes: 1 addition & 1 deletion .github/workflows/analyze.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
- name: flutter analyze --fatal-infos
if: steps.filter.outputs.any_dart == 'true'
run: |
flutter analyze --no-pub --fatal-infos 2>&1 | tee analyze_report.txt
flutter analyze --no-pub --fatal-warnings --fatal-infos 2>&1 | tee analyze_report.txt
EXIT=${PIPESTATUS[0]}

ERRORS=$(grep -c "error •" analyze_report.txt 2>/dev/null || true)
Expand Down
72 changes: 71 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,73 @@ jobs:
- '**/analysis_options.yaml'

# ── PR: fast single-OS run — only changed packages ─────────────────────────
android-compile:
name: Compile (Android)
runs-on: ubuntu-22.04
needs: path-filter
if: >-
github.event_name == 'pull_request' &&
needs.path-filter.outputs.changed_any_dart == 'true'

steps:
- uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: stable
cache: true
- name: flutter pub get
run: flutter pub get
- name: Check Android compileSdk
working-directory: example/android
run: ./gradlew assembleDebug

emulator-tests:
name: Integration Tests (Emulator)
runs-on: macos-latest
needs: path-filter
if: >-
github.event_name == 'pull_request' &&
needs.path-filter.outputs.changed_any_dart == 'true'
strategy:
fail-fast: false
matrix:
platform: [android, ios]
steps:
- uses: actions/checkout@v4
- name: Setup Java
if: matrix.platform == 'android'
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: stable
cache: true
- name: flutter pub get
run: flutter pub get
- name: Run Android Emulator Tests
if: matrix.platform == 'android'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 29
arch: arm64-v8a
script: flutter test test/integration/
- name: Run iOS Simulator Tests
if: matrix.platform == 'ios'
run: |
xcrun simctl list devicetypes
flutter test test/integration/ -d "iPhone 15" || flutter test test/integration/

test-pr:
name: Tests (PR · ubuntu-22.04 · stable)
runs-on: ubuntu-22.04
Expand Down Expand Up @@ -108,7 +175,10 @@ jobs:
if: >-
needs.path-filter.outputs.changed_root == 'true' ||
needs.path-filter.outputs.changed_core == 'true'
run: flutter test --no-pub
run: |
# Run root tests, excluding test/golden/ which is handled by golden.yml
find test -maxdepth 1 -name "*_test.dart" | xargs flutter test --no-pub
find test -maxdepth 1 -type d -not -path test -not -path test/golden -not -path "test/failures" -not -path "test/.*" | xargs flutter test --no-pub

- name: Test hyper_render_core
if: needs.path-filter.outputs.changed_core == 'true'
Expand Down
38 changes: 27 additions & 11 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Claude Code session files
# AI / LLM Tools
.claude/
.gemini/
.cursor/
.windsurf/
.aider*
.env
.env.*
*.local
memory/
RESEARCH.md
PLAN.md
TODO.md
ACT.md
TEST.md

# Private / internal documents (not for public repository)
doc/internal/
Expand All @@ -13,17 +26,20 @@ TEST_SUMMARY.md
IMPROVEMENTS_SUMMARY.md
PRIORITY_ACTION_PLAN.md

# Miscellaneous
*.class
*.log
*.pyc
*.swp
# User-specific / Local config
.vscode/
.history/
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
*.swp
*.temp
*.tmp
*.log
.DS_Store?
Icon?
ehthumbs.db
Thumbs.db



# IntelliJ related
*.iml
Expand Down
5 changes: 5 additions & 0 deletions .pubignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ pubspec_dev.yaml
# Internal archive / historical comparison docs
archive/

# AI assistant config files
CLAUDE.md
GEMINI.md
.claude/

# Coverage artifacts
coverage/

Expand Down
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# Changelog

## [1.2.4] - 2026-05-03

### 🐛 Bug Fixes

- **Markdown CRLF line endings left stray `\r` in code blocks** (`markdown_adapter.dart`): `content.split('\n')` on Windows `\r\n` content produced lines like `"some code\r"` — the carriage-return was stored verbatim in code block text and rendered as a stray character in monospace. Content is now normalised to LF (bare `\r` old-Mac endings also handled) before splitting.
- **Virtualized Markdown/Delta sections orphaned headings** (`hyper_viewer.dart`): `_splitIntoSections` (Markdown/Quill Delta virtualized/paged path) lacked the heading-widow guard that `HtmlAdapter.parseToSections` already had. A heading that pushed `currentSize ≥ chunkSize` became the last element of a section, stranding its content at the top of the next section without a heading. Added twin guards: (1) never end a section on `h1`–`h6`, (2) never split immediately before a heading.
- **`Paint()` allocated every frame for filter/backdrop-filter decorations** (`render_hyper_box_paint.dart`): `_paintBlockDecorations` / `_paintInlineDecorations` created inline `Paint()` objects for CSS `filter` and `backdrop-filter` on every paint call. Added reusable `_filterPaint` instance field (same pattern as `_fillPaint` / `_strokePaint`).
- **`_effectiveConfig` dropped `useMicrotaskParsing` and blocked `allowedCustomSchemes`** (`hyper_viewer.dart`): When HTML contained CSS animations, `_effectiveConfig` rebuilt `HyperRenderConfig` but omitted `useMicrotaskParsing` (reset to `false`, breaking widget tests for animated HTML) and did not merge `allowedCustomSchemes` into `extraLinkSchemes` (custom-scheme deep-links silently blocked at the render layer). Both fields now correctly propagated.
- **`allowedTags` diff used reference equality** (`hyper_viewer.dart`): `didUpdateWidget` compared `oldWidget.allowedTags != widget.allowedTags` which is always `true` for new list literals — causing unnecessary re-parses on every rebuild. Now uses `listEquals` for content equality.
- **Incremental layout hash collision on duplicate sections** (`hyper_viewer.dart`): `_mergeSections` used `Map<int, DocumentNode>` keyed by 32-bit hash; two sections with identical text share the same hash, so the second overwrote the first and both received the same cached node. Changed to `Map<int, List<DocumentNode>>` with queue semantics.
- **`sanitize` doc-comment stated wrong default** (`hyper_viewer.dart`): Comment claimed default was `false`; actual default is `true`. Corrected with accurate security guidance.
- **`addPostFrameCallback` fired on every `build()` in paged mode** (`hyper_viewer.dart`): `_buildPagedContent` registered `pageController._onSectionsReady` unconditionally each build. Now guarded by `_lastNotifiedPageCount` — fires only when section count changes.

## [1.2.3] - 2026-04-30

### 🚀 Performance & Stability

- **Test Coverage Optimization**: Increased global test coverage to >75% with new comprehensive suites for parsers, adapters, and selection logic.
- **Golden Test Alignment**: Updated golden tests for consistent multi-platform rendering validation.
- **Improved Widget Test Robustness**: Updated `find.byType(HyperRenderWidget)` assertions to handle multiple instances in the tree caused by virtualization and float nesting.

### 🐛 Bug Fixes

- **Fixed `HyperRenderWidget` compilation error**: Resolved a signature mismatch in recursive widget construction where `codeHighlighter` was passed outside of `config` and `pluginRegistry` was missing.
- **Fixed Float Layout logic**: Explicit CSS `width` and `height` properties are now correctly respected for non-image float elements, rather than always falling back to intrinsic text dimensions.
- **Fixed Plugin Propagation**: Ensured `pluginRegistry` is correctly passed to nested renderers, allowing custom tags to work inside floated containers.
- **Missing `foundation` import** in `hyper_viewer.dart`: Fixed compilation error when using `compute` function in some environments.
- **Improved selection logic** for virtualized lists: Fixed edge cases when selecting text across off-screen chunks.
- **Flexible Markdown parsing**: Updated adapter to handle variations in tag output (e.g., `<b>` vs `<strong>`) across different environments.

## [1.2.2] - 2026-04-02

### 🐛 Bug Fixes
Expand Down
Loading
Loading