You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rust core feature parity with the canonical TypeScript engine — @ornery/ui-grid-core's WASM build now mirrors all fourteen ported pipeline modules (viewmodel, identity, row-state, edit, display, infinite-scroll, pinning, pagination, sorting, filtering, tree, grouping, state, pipeline) and a new wasm-parity spec suite locks the contract in. Each TS module has a subprocess-driven parity test that runs the wasm shim and asserts byte-identical output for the same input fixtures.
Rust ↔ JS callback bridge for rowIdentity — closures can't cross the wasm boundary via serde, so the bridge now plucks the JS rowIdentity callback off the live JsValue and pre-resolves identities (recursively, for tree mode) before serde deserializes. build_grid_rows_js / build_pipeline_js and resolve_grid_row_id_js now use the wasm path consistently.
WebAssembly performance pass — cleaner wasm-bridge plumbing reduces per-call overhead on hot paths, and demo apps disable wasm module auto-registration so consumers opt in explicitly.
Vitest config across the workspace + CI coverage reporting — added a shared vitest config and brought CI coverage reporting back online so test gates run consistently across packages.
Row selection on the expandable harness across all wrappers — the Angular, React, and Web Components "expandable" demos now also enable enableRowSelection, so the selection checkbox column appears alongside the expand toggle. Live demos exercise the same UX surface across all three frameworks.
Egui parity plan — added a planning doc describing how the egui adapter will reach parity with the web-suite features (selection / validate / row-edit, keys / filters / pagination, new-core APIs).
Date-picker slot template on the Web Components templated harness — the vanilla demo now renders an interactive <input type="date"> for the renewal column via a slot template, with a delegated change handler that walks back to the body cell, mutates the row in place, and re-publishes through setData() so picked values persist.
Changed
Expand/tree toggle leads the cell content instead of trailing it — the disclosure chevron now sits on the leading edge of the primary cell, in front of the row label, matching the tree-toggle convention. The margin-inline-start: auto override that previously pushed the expand toggle to the trailing edge has been removed; both initial render and patch paths emit the toggle before .cell-content.
Host element establishes its own stacking + paint context — :host now sets isolation: isolate and contain: layout paint, so sibling repaints in the surrounding page (e.g. button hover transforms on the demo pages) don't invalidate the grid's sticky filter strip. Fixes the filter-row flicker observed on the React and vanilla demos while Angular was already flicker-free via its component view encapsulation.
Viewport-width measurement under-estimates by 2px — the body viewport's overflow-x: auto plus sub-pixel rounding on the host box made tracks resolve ~1–2px wider than the actual renderable width, surfacing a spurious default horizontal scrollbar. setViewportWidth now floors and subtracts a 2px safety margin.
Demo button hover effects no longer use transform — the web-components and React docs pages dropped transform: translateY(-1px) on .scenario-button:hover (and friends) in favour of a plain background gradient shift. transform/filter promote the button to its own compositing layer; combined with the host isolation fix this removes both the trigger and the surface for filter-row repaint flicker.
Per-row patch fingerprint cache for selection / focus / expand toggles — patchExistingRows now fingerprints each row's visual state (selection, focus, expand, dirty/saving/error, tree level, per-column validity, entity reference) and skips patchBodyCell when nothing relevant changed. Selection / focus / expand toggles now repaint only the affected row plus the previously- and newly-focused cells, instead of O(rows × cols). Caches are cleared on full re-mount, slow-path innerHTML rebuild, setFrameworkRenderedSlots, and template MutationObserver firing.
setFrameworkRenderedSlots exposed on VanillaUiGridElement — external consumers no longer need to cast the element to call it. controller.getEditingCellKey() is also exposed for the patch path.
Fixed
Framework-slot wrappers (Angular embedded views, React portals) survive across patch passes — the patch path's per-row fingerprint short-circuit was skipping stageCell for unchanged rows, so frameworkSlots.flush() diffed an empty pending set against a full last set and emitted a spurious cellSlotsChanged removed for every cell. Custom-rendered cells were torn down on first paint and only reappeared after a scroll triggered a virtual-body rebuild that re-staged everything. Added FrameworkSlotBridge.carryRowCells(rowId) and call it from patchExistingRows when canSkip is true so the row's known slots carry forward and the diff is a no-op.
Cell selection retention bug across shadow boundaries — click handlers used closest('.body-cell') which stops at shadow boundaries, so clicks on framework-projected light-DOM cell content (Angular ng-template, React render props) never resolved to the body cell. The previously focused cell kept its cell-focused class, making multiple cells appear "selected" simultaneously. Replaced every closest('.body-cell') call in events.ts with a new bodyCellFromEvent() helper that walks composedPath(), which crosses the shadow boundary correctly.
Expand toggle no longer attaches to the row-selection checkbox cell — isGridPrimaryColumn returned true for visibleColumns[0], but when row selection is enabled the synthetic selectionRowHeaderCol is prepended at index 0, so the tree/expand toggle and indent calc attached to the checkbox cell instead of the first data column. Skip the selectionRowHeaderCol sentinel in isGridPrimaryColumn (TS and Rust core, kept identical so wasm-parity specs still hold).
React demo page double scrollbar on Linux — .react-demo-frame had overflow-x: auto. Per the CSS spec, when one axis is non-visible the other is coerced from visible to auto, so the frame grew its own vertical scrollbar in addition to the grid's body-viewport scrollbar. Switched to overflow: visible; horizontal overflow is owned by the grid's body viewport internally.
Vanilla MutationObserver infinite-loop with framework wrappers — the observer fired on every slot mutation, including the <span slot="cell-…"> projection wrappers Angular and React append for cell rendering. Each mutation triggered ensureController → setOptions → refresh → cellSlotsChanged, which made the wrapper append more spans, ad infinitum. The observer now filters to <template>-typed slot mutations (the consumer-template surface it actually cares about). React tests also moved to happy-dom now that the loop is gone.
Rust core ↔ TS core divergences — fixed a set of silently-different outputs that the new parity specs caught:
row_state::ToggleGridRowExpandedResult / ToggleGridTreeRowExpandedResult now serialize as named-field structs instead of tuples (which produced [bool, {...}] instead of {expanded, nextExpandedRows}).
edit::clear_grid_edit_session now returns a ClearGridEditSessionResult struct (was a tuple).
edit::find_next_grid_cell now returns FindNextGridCellResult { row, column } (was just GridCellPosition; TS callers expect resolved row + column).
edit::should_grid_edit_on_focus: GridColumnDef.enable_cell_edit_on_focus is now Option<bool> so a column with Some(false) correctly opts out even when GridOptions.enable_cell_edit_on_focus is Some(true) — TS uses ?? coalescing, so an explicit false wins over options-level true.
state::GridSavedState now skips serializing empty Vec / BTreeMap / Option fields so empty-input round-trips produce {} rather than {sort: null, pagination: null, columnOrder: [], …}.
row_searcher::guess_condition now emits a literal-substring regex for the default contains case. Previously emitted Comparator(Contains), but run_column_filter had no Contains arm in the comparator branch — it fell through to _ => true, so the filter silently matched every row. Tree filtering, pipeline filtering, and the row-searcher contains test were all visibly wrong before.
tree::resolve_row_id now honours options.row_identity_overrides, the hidden serde field populated by the wasm bridge from the JS rowIdentity callback.
c-abi fixture regenerated to drop the now-skipped enableCellEditOnFocus default-emit so the deterministic engine round-trip stays stable.