Skip to main content

zero_adaptive_link 0.6.0 copy "zero_adaptive_link: ^0.6.0" to clipboard
zero_adaptive_link: ^0.6.0 copied to clipboard

Adaptive navigation for Flutter: one onTap, the right behavior everywhere.

Changelog #

0.6.0 #

Added / 新增 #

  • Added ZeroLinkMode.fullscreen and ZeroNav.openFullscreen: any matched location can now be opened as a fullscreen overlay above the shell, even when its route does not declare fullscreen. ZeroAnchor falls back to ZeroLink for non-push modes so web and native agree.
    • 新增 ZeroLinkMode.fullscreen 与 ZeroNav.openFullscreen:现在可把任意匹配到的 location 以覆盖 shell 的 fullscreen 覆盖层打开,即使其路由未声明 fullscreen。非 push 模式下 ZeroAnchor 回退到 ZeroLink,使 web 与原生行为一致。
  • Exported ZeroShellRouteBuilder and ZeroGoTabCallback from the barrel, so the public field types of ZeroRoute.shellBuilder and ZeroShellState.goTab can be referenced by consumers.
    • 从 barrel 导出 ZeroShellRouteBuilder 与 ZeroGoTabCallback,使 ZeroRoute.shellBuilder 和 ZeroShellState.goTab 的公开字段类型可被使用方引用。
  • Added ZeroRouteMatcher.encodeSegment (shared by the matcher and namedLocation) and friendly asserts for nested empty tabs, shell / routes exclusivity, breakpoint thresholds and more than two SlidingPanes children.
    • 新增 ZeroRouteMatcher.encodeSegment(供 matcher 与 namedLocation 共用),并为嵌套空 tab、shell / routes 互斥、断点阈值以及 SlidingPanes 超过两个 child 补上友好断言。

Changed / 优化 #

  • ZeroRouter.canonicalHref now builds the fragment with Uri, so a literal #, spaces and other hazards are escaped instead of truncating the shareable URL.
    • ZeroRouter.canonicalHref 现在用 Uri 构造 fragment,字面 #、空格等字符会被转义,不再截断可分享 URL。
  • ZeroRouteStateScope.updateShouldNotify compares observable fields instead of object identity; ZeroNavigationChrome clamps an out-of-range tab index; the default loader error page shows the exception; redirect cycles are detected as soon as a location repeats.
    • ZeroRouteStateScope.updateShouldNotify 改为比较可观察字段而非对象身份;ZeroNavigationChrome 夹取越界的 tab 下标;默认 loader 错误页显示异常对象;重定向一旦出现重复 location 即判定为环。
  • Documentation now matches the code: ZeroLink is a FocusableActionDetector, the 0.4.0 swipe direction is described as left-to-right in both languages, and 0.5.0 credits the DOM anchor to ZeroAnchor rather than ZeroLink.
    • 文档与代码对齐:ZeroLink 现描述为 FocusableActionDetector;0.4.0 滑动方向在中英文中统一为从左向右;0.5.0 的真实 DOM 锚点归到 ZeroAnchor 而非 ZeroLink。

Fixed / 修复 #

  • Fixed a query-only navigation duplicating the whole page stack: only the leaf match carries the query and a query change now reconciles the leaf in place, so back, breadcrumbs and isDetailOpen stay correct. Raw query strings and literal + path characters also round-trip unchanged.
    • 修复仅 query 变化会把整条页面栈重复压栈的问题:现在只有叶子匹配携带 query,query 变化时就地协调叶子,返回栈、面包屑与 isDetailOpen 因此保持正确;原始 query 字符串与路径中的字面 + 也能原样往返。
  • Fixed ZeroRouteState.copyWith discarding pageKey, which broke the breakpoint handoff for routes with a loader. The inner route-state scope no longer reuses the outer GlobalKey.
    • 修复 ZeroRouteState.copyWith 丢弃 pageKey 的问题(它会破坏带 loader 路由的跨断点交接);内层 route-state scope 不再复用外层 GlobalKey。
  • Fixed ZeroLink.onTap being ignored on Enter / Space, and fixed ZeroLinkMode.fullscreen being documented but absent.
    • 修复 ZeroLink.onTap 在 Enter / Space 激活时被忽略的问题,并补齐了文档已宣传却不存在的 ZeroLinkMode.fullscreen。
  • Fixed the web ZeroAnchor re-registering its platform view factory on every build; it now registers once per mounted state, updates the DOM element in place and keeps mode / tabIndex / arguments consistent with non-web platforms.
    • 修复 web 版 ZeroAnchor 每次 build 都重注册 platform view factory 的问题;现在每个挂载的 State 只注册一次、原地更新 DOM 元素,并让 mode / tabIndex / arguments 与非 web 平台一致。
  • Fixed namedLocation corrupting longer parameter names with replaceAll and returning unresolved placeholders; whole :param tokens are replaced and a missing parameter returns null.
    • 修复 namedLocation 用 replaceAll 破坏更长参数名、以及参数缺失时返回残留占位符的问题;现在只替换完整 :param 标记,参数缺失返回 null。
  • Fixed nested-shell route names never being registered (and duplicate names never asserted), breadcrumb clicks truncating the outer stack with a sub-stack index, and nested goTab joining a tab path onto a host location that carries a query.
    • 修复嵌套 shell 的路由名从未注册(重名也因此不触发断言)、面包屑点击用 sub-stack 下标截断外层栈、以及嵌套 goTab 把 tab 路径拼到带 query 的宿主 location 上的问题。
  • Fixed pushReplacementNamed and pushNamedAndRemoveUntil mutating the stack before their async resolve, which bypassed the generation guard and left an unannounced truncated stack when superseded.
    • 修复 pushReplacementNamed 与 pushNamedAndRemoveUntil 在异步解析之前就改栈的问题:这曾绕过 generation 守卫,在被取代时留下未通知的残缺栈。
  • Fixed a resize-handle gesture cancellation leaving _dragActive stuck forever, and mirrored the detail-pane swipe-to-dismiss direction with paneSide.
    • 修复拖拽分割线的手势被取消后 _dragActive 永久卡住的问题,并让 detail pane 的滑动收起方向随 paneSide 镜像。
  • Fixed focusing an existing entry while a fullscreen overlay was open (the URL snapped back to the overlay), _onDidRemovePage leaving discarded push futures pending, canPop ignoring framework routes, refresh() clearing an open overlay, and _ImperativeRouteCounter.didReplace shifting its count on null routes.
    • 修复覆盖层打开时聚焦已有条目会让 URL 跳回覆盖层、_onDidRemovePage 让被遗弃的 push Future 永久挂起、canPop 忽略框架级路由、refresh() 清掉已打开覆盖层,以及 _ImperativeRouteCounter.didReplace 在 route 为 null 时计数偏移的问题。
  • Fixed onNavigation firing during delegate construction, focus restoration only running in initState, _setTabStack reusing an entry with stale arguments, and nested default tabs turning the whole location into an error page when they fail to match.
    • 修复 onNavigation 在 delegate 构造期触发、焦点恢复只在 initState 执行、_setTabStack 复用带旧 arguments 的条目,以及嵌套默认 tab 匹配失败时把整个 location 变成错误页的问题。

0.5.0 #

Added / 新增 #

  • Nested ZeroShell: a ZeroRoute can now host a ZeroShell via ZeroRoute.shell; its shellBuilder receives the nested shell widget as its child. Route tables nest arbitrarily deep, and each shell derives its active tab and renders its own tabs / panes from the same flat location stack — so a deep link like #/settings/profile restores both the outer tab and the nested one. The delegate re-resolves the whole (flat) match stack on every navigation, so a nested shell needs no private state machine.
    • 嵌套 ZeroShell:现在 ZeroRoute 可通过 ZeroRoute.shell 承载一个 ZeroShell,其 shellBuilder 会以嵌套 shell 组件作为 child 收到。路由表可任意深度嵌套,每个 shell 都从同一份(扁平)location 栈推导出自己的活动 tab 并渲染自身的 tabs / panes——因此 #/settings/profile 这样的深链会同时恢复外层与内层 tab。delegate 在每次导航时重新解析整条(扁平)匹配栈,嵌套 shell 因而无需私有状态机。
  • Real web anchors: the new ZeroAnchor renders a genuine DOM <a href="#/..."> on web via dart:js_interop, so right-click "open in new tab" and link previews work; clicks are still routed through the router (no full reload). ZeroLink stays a widget-level link. ZeroRouter.canonicalHref(location) returns the shareable hash URL.
    • 真实 web 锚点:新增的 ZeroAnchor 在 web 上通过 dart:js_interop 渲染真正的 DOM <a href="#/...">,使右键「在新标签打开」与链接预览可用;点击仍走路由(不会整页刷新)。ZeroLink 仍是组件级链接。ZeroRouter.canonicalHref(location) 返回可分享的 hash URL。
  • Scroll & focus restoration: ZeroRouter enables PageStorage-based scroll restoration (one bucket per router) and restores primary focus across breakpoint crossings and browser history changes. Route content is keyed so it survives the handoff; opt out with restoreScrollOffset: false / restoreFocus: false.
    • 滚动与焦点恢复:ZeroRouter 启用基于 PageStorage 的滚动恢复(每个 router 一个桶),并在跨断点切换与浏览器历史变化时恢复主焦点。路由内容以键标记以在交接中存活;可用 restoreScrollOffset: false / restoreFocus: false 关闭。

Fixed / 修复 #

  • Descending into a nested shell's default tab now strips the host prefix from that tab's initialLocation. A nested tab's initialLocation is a full location (/settings/profile) while its routes are authored relative to the host (/profile), so the host's own segments used to leak into the child pattern: the default tab never matched, the tab's stack stayed empty, and tapping such a tab fell back to the root location with an empty pane tree.
    • 下钻嵌套 shell 的默认 tab 时,现在会先从该 tab 的 initialLocation 剥掉宿主前缀。嵌套 tab 的 initialLocation 是完整 location(/settings/profile),而其路由相对宿主书写(/profile),此前宿主的段会混进子级 pattern:默认 tab 始终匹配不上、该 tab 的栈为空,点击该 tab 会回落到根 location 并渲染空的 pane 树。

0.4.0 #

Fixed / 修复 #

  • Fixed ZeroNav.popFrom(context) blanking the app on expanded widths: a pane context resolves to the root navigator (no branch navigator is mounted there), and the old nav.canPop() guard was always true for the single shell route, so nav.pop() removed the shell route instead of collapsing the detail pane. The root branch now mirrors maybePopFrom — framework routes and overlay pages dismiss first, and the declarative tab pop applies only when the root navigator has nothing imperative to pop.
    • 修复 ZeroNav.popFrom(context) 在 expanded 宽度下让应用空白的问题:pane 上下文解析到 root navigator(此宽度未挂载 branch navigator),旧守卫 nav.canPop() 对唯一一条 shell route 永远为真,于是 nav.pop() 移除 shell route 而非收起 detail pane。root 分支现在与 maybePopFrom 一致——优先关闭框架级路由与 overlay 页,仅当 root navigator 没有可关闭的命令式路由时才走声明式 tab pop。

Changed / 优化 #

  • ZeroLink is now keyboard- and screen-reader-accessible: it uses FocusableActionDetector (focusable, Enter/Space activates) and exposes a semanticLabel, so it no longer needs a Material ancestor and reads as a link. The hand cursor is unchanged on web / desktop.
    • ZeroLink 现在支持键盘与屏幕阅读器:改用 FocusableActionDetector(可聚焦、Enter/Space 激活)并暴露 semanticLabel,不再需要 Material 祖先,且被识别为链接。web / 桌面的手型光标保持不变。
  • The default error page now follows the surrounding Theme / Directionality (instead of hard-coded dark text on a fixed background) and is easier to read on both light and dark themes.
    • 默认错误页现在遵循周围的 Theme / Directionality(不再是固定背景上的硬编码深色文字),在浅色与深色主题下都更易读。
  • The web hash provider now de-duplicates popstate + hashchange (some browsers fire both for one navigation) via a Uri equality guard, avoiding a spurious duplicate resolve.
    • Web hash provider 现在对 popstate + hashchange(部分浏览器一次导航会同时触发两者)做去重(以 Uri 相等性守卫),避免多余的重复解析。
  • ZeroLink is now configurable like the imperative verbs: add mode (push, replacement, popAndPush, fullscreen) and tabIndex to open a location in a specific tab, or fullscreen to cover the shell. The onTap override still wins when provided.
    • ZeroLink 现在可像命令式动词一样配置:新增 mode(push、replacement、popAndPush、fullscreen)与 tabIndex,可在指定 tab 打开某 location,或以 fullscreen 覆盖 shell。onTap 覆盖仍优先。

Added / 新增 #

  • Added ZeroRouter.onNavigation: a callback fired after every successful location change (in-app navigation, browser back / forward, deep links), for analytics and side effects, without a runtime dependency.
    • 新增 ZeroRouter.onNavigation:每次成功的 location 变化(应用内导航、浏览器前进 / 后退、深链)后触发的回调,可用于埋点与副作用,零运行时依赖。
  • Added ZeroNav.showDetail(location) / hideDetail() / isDetailOpen so non-tap scenarios (keyboard shortcuts, initial URL, programmatic flows) can open and close the right pane directly, plus a ZeroBackButton widget that shows itself only when there is something to pop and adapts its behavior to the breakpoint (collapses the pane on expanded, pops the page otherwise).
    • 新增 ZeroNav.showDetail(location) / hideDetail() / isDetailOpen,使非点击场景(键盘快捷键、初始 URL、命令式流程)也能直接开合右栏;并新增 ZeroBackButton 组件,仅在可 pop 时显示,并随断点自适应(expanded 收起 pane,否则 pop 页面)。
  • Added ZeroRoute.loader: an optional Future that resolves route arguments before the page builds. While pending the pane / page shows loadingBuilder (default spinner); on error it shows errorBuilder. This lets the adaptive layer own the data round-trip instead of every page wiring its own FutureBuilder.
    • 新增 ZeroRoute.loader:在页面构建前解析路由参数的可选 Future。等待期间 pane / 页面显示 loadingBuilder(默认 spinner),出错时显示 errorBuilder。自适应层由此包办数据往返,无需每个页面各自接 FutureBuilder。
  • Added swipe-to-dismiss for the detail pane on expanded widths: a left-to-right swipe on the detail pane collapses it (mirroring iOS split-view dismissal), in addition to the existing resize-handle drag.
    • expanded 宽度下新增右栏滑动收起:在 detail pane 上从左向右滑即可收起(与 iOS split view 一致),原有拖拽分割线改比例仍保留。
  • Added showBreadcrumbsOnBranch to ZeroRouter (default false): when true, the breadcrumb bar also renders inside the compact / medium branch AppBar, so the three widths stay consistent instead of only showing breadcrumbs on expanded.
    • 新增 ZeroRouter.showBreadcrumbsOnBranch(默认 false):为 true 时面包屑栏也会渲染进 compact / medium 的 branch AppBar,使三档宽度表现一致,而非仅在 expanded 显示。
  • Added ZeroNavigationChrome, a responsive shell chrome that switches between a NavigationRail (expanded) and a bottom NavigationBar (compact / medium) automatically from the window width, so applications no longer have to hand-wire the two themselves.
    • 新增 ZeroNavigationChrome:根据窗口宽度在 NavigationRail(expanded)与底部 NavigationBar(compact / medium)之间自动切换的响应式 shell chrome,应用无需再手写两种。
  • Added preferredTab to ZeroNav.pushNamed / pushReplacementNamed (and the matching ZeroLink.tabIndex) so a location that exists in multiple tabs can be opened in an explicit tab instead of always falling back to tab 0.
    • 新增 ZeroNav.pushNamed / pushReplacementNamed 的 preferredTab(以及对应的 ZeroLink.tabIndex),使同一 pattern 存在于多 tab 时可显式指定打开哪个 tab,而非总回退到 tab 0。

0.3.0 #

Fixed / 修复 #

  • Fixed system back (and the Escape shortcut, maybePop, popRoute) popping the page beneath an open dialog or bottom sheet: framework routes live on the root navigator above the shell route, and the delegate used to consult the branch navigator first, which cannot see them — the dialog stayed floating while the page left. The root navigator is now consulted first, without consulting route hooks, so the dialog dismisses and the page survives.
    • 修复对话框或 bottom sheet 打开时,系统返回(以及 Escape 快捷键、maybePop、popRoute)会 pop 掉其下方页面的问题:框架级路由位于 root navigator、处于 shell route 之上,而 delegate 过去先询问看不到它们的 branch navigator——结果是对话框悬浮原地而页面已被 pop。现在优先询问 root navigator 且不询问路由钩子,对话框正常关闭、页面保留。
  • Fixed ZeroNav.popFrom(context) (and popFrom paths through the root navigator) popping the page beneath instead of dismissing the dialog it was called from: the branch conflated "the root navigator" with "our overlay stack". The navigator's own topmost route (framework route or overlay page) is now popped first, and the declarative tab pop applies only when the root navigator has nothing to pop.
    • 修复 ZeroNav.popFrom(context)(及经由 root navigator 的 popFrom 路径)pop 掉下方页面而非关闭所在对话框的问题:该分支把「root navigator」等同于「我们的 overlay 栈」。现在优先 pop navigator 自己的栈顶路由(框架级路由或 overlay 页),只有当 root navigator 无可 pop 内容时才走声明式 tab pop。
  • Fixed an async navigation race: two navigations fired in quick succession used to apply their resolutions in completion order, so a slower (async-redirect) resolution could land last and win — leaving the UI on a stale location. Every navigation now carries a generation stamp and a superseded resolution is dropped, so the last requested location always wins.
    • 修复异步导航竞态:短时间内发出的两次导航过去按解析完成顺序应用,慢(异步重定向)的解析可能最后落地并胜出——让界面停留在过期的 location 上。现在每次导航都带序号戳,被取代的解析会被丢弃,最后请求的 location 始终获胜。
  • Fixed pushReplacementNamed stacking on top of a branch root instead of replacing it (the length > 1 guard skipped the removal when the stack held only the root). At a single-entry stack the root entry itself is now replaced, matching Navigator semantics and external (deep-link) navigation.
    • 修复 pushReplacementNamed 在 branch 根节点上压栈而非替换的问题(length > 1 守卫在栈中只有根条目时跳过了移除)。单条目栈现在替换根本身,与 Navigator 语义及外部(深链)导航一致。
  • Fixed the first pane expansion having no slide animation: the reveal controller starts at 1, so a bare forward() on the 1 → 2 transition was a no-op and the detail pane appeared instantly. It now starts hidden and slides in.
    • 修复首次 pane 展开没有滑入动画的问题:reveal controller 初始为 1,1 → 2 转换时直接 forward() 是空操作,detail pane 瞬间出现。现在从隐藏状态开始滑入。

Changed / 优化 #

  • Page content is now keyed with a stable per-page GlobalKey (ZeroRouteState.pageKey), so when the window width crosses a breakpoint the same subtree is handed over in the same frame: compact / medium pages and expanded panes swap structures without recreating the content, and scroll offsets, text input and other element state survive. The key is public so applications can key their own content the same way.
    • 页面内容现在以稳定的每页面 GlobalKey(ZeroRouteState.pageKey)标记,窗口宽度跨越断点时于同帧交接同一子树:compact / medium 页面与 expanded pane 互换结构而不重建内容,滚动偏移、文本输入等元素状态得以保留。该键公开,应用可用同样的方式为自己的内容加键。
  • SlidingPanes now plays a one-column viewport shift when the master pane is replaced: a deeper push slides the viewport left (the replaced master exits on its side, the new pair slides in from the detail side, widths morphing so both ends line up), and a pop slides it back. The empty-detail hint moved from a second child to a dedicated placeholder parameter, so the 1 ↔ 2 child count again drives the expand / collapse transition (the router's placeholder used to mask it, which suppressed the slide entirely). Replacing only the detail still updates in place.
    • SlidingPanes 现在在 master pane 被替换时播放一列视口平移:更深层级 push 使视口左移(被替换的 master 向自己一侧退出,新的一对从 detail 一侧滑入,宽度渐变使两端精确衔接),pop 则反向移回。空详情提示从第二个 child 改为独立的 placeholder 参数,1 ↔ 2 的子项计数重新驱动展开 / 收起转场(此前的占位 child 会掩盖它,导致滑动完全失效)。仅替换 detail 仍原地更新。
  • ZeroRouteState is no longer const-constructible: it now carries the stable pageKey, which cannot be a constant expression. Constructing a state by hand (rare — it is normally produced by matching) still works, just without const.
    • ZeroRouteState 不再支持 const 构造:它现在携带稳定的 pageKey,后者不是常量表达式。手动构造状态(罕见——通常由匹配产生)仍然可行,只是不能加 const。
  • Added ZeroNav.goTab(index, {initialLocation}) for imperative tab switching, mirroring ZeroShellState.goTab.
    • 新增 ZeroNav.goTab(index, {initialLocation}) 用于命令式切换 tab,与 ZeroShellState.goTab 等价。
  • Duplicate route names now fail with a friendly assert (Duplicate route name ...) instead of the last registration silently winning; the same name mapped to the same path stays allowed.
    • 重名路由现在以友好断言(Duplicate route name ...)失败,而非后注册者静默生效;同名且同路径的重复注册仍然允许。
  • Removed a duplicated comment block in the ZeroRouterDelegate constructor and documented two caveats: keep placeholders free of a Key (the second pane's key drives the expand / collapse transition), and dialogs / menus opened inside a pane are clipped to the pane unless they use the root navigator (useRootNavigator: ZeroPaneScope.maybeOf(context) != null).
    • 移除了 ZeroRouterDelegate 构造函数中重复粘贴的注释块,并补充两处注意事项:占位内容不要设置 Key(第二个 pane 的键驱动展开 / 收起转场);从 pane 内部打开的对话框 / 菜单会被裁剪到 pane 内,除非使用 root navigator(useRootNavigator: ZeroPaneScope.maybeOf(context) != null)。

Added / 新增 #

  • Added ZeroRouteState.pageKey: a stable GlobalKey for the page's content, used by the plugin for the breakpoint handoff and readable by applications for their own keyed subtrees.
    • 新增 ZeroRouteState.pageKey:页面内容的稳定 GlobalKey,插件以其完成断点交接,应用也可读取它为自己的子树加键。
  • Added pane transition coverage to the test suite: expand / deeper-push / pop / collapse transitions, dialog-vs-back regressions (system back, Escape, maybePop, popFrom, maybePopFrom, a dialog over a fullscreen overlay), the async race, the root replacement, the breakpoint-crossing state handoff (both directions), pageKey stability and ZeroNav.goTab.
    • 为测试套件补充了 pane 转场覆盖:展开 / 深层 push / pop / 收起转场、dialog 与返回的交互回归(系统返回、Escape、maybePop、popFrom、maybePopFrom、fullscreen 覆盖层上的对话框)、异步竞态、根节点替换、跨断点状态交接(双向)、pageKey 稳定性与 ZeroNav.goTab。

0.2.0 #

Fixed / 修复 #

  • Fixed ZeroRoute.barrierDismissible being silently ignored: the value was captured into the route config but never passed to PageRoute, whose private final field defaults to false. Tapping the barrier of a fullscreen route with barrierDismissible: true now dismisses it, as documented.
    • 修复 ZeroRoute.barrierDismissible 被静默忽略:该值被采集进路由配置,却从未传给 PageRoute——父类的私有 final 字段默认 false。现在点击 barrierDismissible: true 的 fullscreen 路由屏障会如文档所述关闭它。
  • Fixed ZeroRoute.fullscreenDialog being silently ignored for the same reason: the created route now reports fullscreenDialog == true, so the full-screen dialog transition applies and the back-swipe gesture is disabled.
    • 修复 ZeroRoute.fullscreenDialog 因同样原因被静默忽略:创建的 route 现在报告 fullscreenDialog == true,全屏对话框转场生效,侧滑返回被禁用。
  • Fixed a leaked pushNamed future for fullscreen routes: clearing the overlay stack (a new push, a deep link, or an unmatched location while an overlay was open) dropped the entries without completing their futures, so await ZeroNav.open(...) hung forever. Every discarded overlay entry's future is now completed with null.
    • 修复 fullscreen 路由 pushNamed Future 泄漏:清空覆盖栈(覆盖层打开时再次 push、收到深链、或 location 失配)会丢弃条目而不补完其 Future,await ZeroNav.open(...) 因此永久挂起。现在每个被遗弃的覆盖层条目的 Future 都会以 null 补完。
  • Fixed percent-encoded path parameters being rewritten by matching: Uri.parse decodes path segments and the matcher re-emitted them raw, so /products/a%20b became the location /products/a b (desyncing the URL bar, namedLocation and push de-duplication). Segments are now re-encoded, and locations round-trip unchanged.
    • 修复匹配过程改写百分号编码的路径参数:Uri.parse 会解码路径片段,而 matcher 原样拼回,导致 /products/a%20b 的 location 变成 /products/a b(与地址栏、namedLocation、push 去重脱节)。现在片段会重新编码,location 往返不变。
  • Fixed bare StateError: No element crashes for degenerate configurations: an empty routes list threw before the assert could run, and an empty ZeroTab crashed the first goTab / deep-link fallback. All three cases now fail with friendly asserts (At least one ZeroShell is required, Exactly one ZeroShell is supported in 0.x, at least one ZeroTab, at least one ZeroRoute).
    • 修复退化配置下的裸 StateError: No element 崩溃:空 routes 列表会在 assert 执行前就抛错,空 ZeroTab 会在首次 goTab / 深链回退时崩溃。这三种情况现在都会给出友好断言(At least one ZeroShell is required、Exactly one ZeroShell is supported in 0.x、at least one ZeroTab、at least one ZeroRoute)。
  • Fixed the web hash parser merging the host page's query into the location: /?utm_source=x#/products/42 used to become /products/42?utm_source=x. The query inside the fragment (the app's own) is still kept.
    • 修复 Web hash 解析器把宿主页面的 query 合并进 location:/?utm_source=x#/products/42 过去会变成 /products/42?utm_source=x。fragment 内部的 query(应用自身的)仍会保留。
  • Fixed the misleading restoreRouteInformation doc comment (it claimed to restore a fragment URI; the URI must stay fragment-free so the provider re-adds the #).
    • 修正 restoreRouteInformation 误导性的文档注释(它声称还原为 fragment URI;URI 必须不带 fragment,由 provider 重新加上 #)。

Changed / 优化 #

  • The Escape shortcut (escapePops, on by default) now wraps the root navigator instead of the shell content, so it also reaches fullscreen overlay pages — which render above the shell route and could never see a Shortcuts ancestor inside it.
    • Escape 快捷键(escapePops,默认开启)现在包裹根 navigator 而非 shell 内容,因此也能作用于 fullscreen 覆盖页——它们渲染在 shell route 之上,看不到其内部的 Shortcuts 祖先。
  • ZeroShellState is now reused across rebuilds when none of its observable fields changed, so an unrelated delegate rebuild no longer notifies every shell-scope dependent.
    • ZeroShellState 现在在可观察字段均未变化时跨重建复用,delegate 的不相关重建不再通知所有 shell scope 依赖者。
  • The resize handle drag no longer misreads a drag started at global x == 0 as "not dragging" (which let a widget update overwrite the fraction mid-drag); a dedicated flag tracks the gesture.
    • 拖拽分割线不再把在全局 x == 0 处开始的拖拽误判为「未在拖拽」(组件更新会在拖拽中途覆盖比例);改用专用标志跟踪手势。

Added / 新增 #

  • Added SlidingPanes.onLeftPaneFractionDragEnd: a once-per-drag commit callback, wired by ZeroRouter to a single rebuild so ZeroShellState.leftPaneFraction catches up after a handle drag (live dragging still streams through onLeftPaneFractionChanged).
    • 新增 SlidingPanes.onLeftPaneFractionDragEnd:每轮拖拽触发一次的提交回调,由 ZeroRouter 接入一次重建,使 ZeroShellState.leftPaneFraction 在拖拽分割线后跟上(实时拖拽仍走 onLeftPaneFractionChanged 逐帧回调)。

0.1.3 #

Fixed / 修复 #

  • Fixed paneSideListenable being a no-op at runtime: the delegate's listener closure assigned the new side to the paneSide constructor parameter (which shadows the instance setter of the same name) instead of the instance setter, so _paneSide never updated and the expanded layout never flipped when the listenable changed. The example's "Expand left / right" toggle now actually mirrors the detail pane. Added regression tests (test/pane_side_test.dart, test/expand_side_test.dart).
    • 修复 paneSideListenable 运行时无效:delegate 的 listener 闭包把新 side 赋给了同名的 paneSide 构造形参(遮蔽了实例 setter),而不是实例 setter,导致 _paneSide 永远不更新、展开布局在 listenable 变化时从不翻转。示例里的「Expand left / right」切换现在能真正镜像 detail pane。新增回归测试(test/pane_side_test.dart、test/expand_side_test.dart)。

0.1.2 #

Fixed / 修复 #

  • Fixed the resize-handle drag stalling / drifting: the gesture now tracks the pointer's true travel (globalPosition) instead of its position relative to the handle, which moves with the pane during the drag.
    • 修复拖拽分割线卡顿 / 漂移:手势改用指针的真实行程(globalPosition)而非相对 handle 的局部坐标——后者会在拖拽时随 pane 移动而自我反馈。
  • Fixed a listener leak: the paneSideListenable listener registered by ZeroRouterDelegate is now removed in dispose, so a long-lived listenable no longer holds the delegate after disposal (which could fire notifyListeners on a dead object).
    • 修复监听器泄漏:ZeroRouterDelegate 注册的 paneSideListenable listener 现在会在 dispose 中移除,长生命周期的 listenable 不再在 delegate 销毁后持有它(避免对已销毁对象触发 notifyListeners)。

0.1.1 #

Fixed / 修复 #

  • Fixed the published package links: homepage and repository now point at the GitHub repository (zero-adaptive-link), and documentation points at the GitHub Pages site, so the links shown on pub.dev resolve instead of returning 404.
    • 修复已发布包的链接:homepage 与 repository 现在指向 GitHub 仓库(zero-adaptive-link),documentation 指向 GitHub Pages 站点,pub.dev 上展示的链接可正常访问而不再返回 404。
  • Fixed the documentation site's basePath and assetPrefix to match the Pages project path, so the site's CSS and JavaScript load instead of 404-ing (which left the pages unstyled).
    • 修复文档站的 basePath 与 assetPrefix 以匹配 Pages 项目路径,使站点的 CSS 与 JavaScript 能正常加载而不再 404(此前会导致页面无样式)。

0.1.0 #

Added / 新增 #

  • Added the ZeroLink widget: one declarative tap target whose behavior adapts to the window width — push a new page on compact / medium, expand or update the right sidebar pane on expanded, and focus an already visible pane instead of duplicating it.
    • 新增 ZeroLink 组件:一套声明式点击目标,行为随窗口宽度自适应——compact / medium 推入新页面,expanded 展开或更新右侧侧栏 pane,目标 pane 已可见时聚焦而非重复展开。
  • Added ZeroNav, the imperative entry point with the same verbs as NavigatorState (pushNamed, pushReplacementNamed, pushNamedAndRemoveUntil, popAndPushNamed, pop, maybePop, popFrom, maybePopFrom, popUntil, canPop), plus namedLocation and refresh helpers.
    • 新增 ZeroNav 命令式入口,导航动词与 NavigatorState 同名同签名(pushNamed、pushReplacementNamed、pushNamedAndRemoveUntil、popAndPushNamed、pop、maybePop、popFrom、maybePopFrom、popUntil、canPop),并提供 namedLocation 与 refresh 辅助方法。
  • Added the declarative route table: ZeroRouter, ZeroShell, ZeroTab and ZeroRoute with nested routes, :param segments, name, title, route-level and router-level redirect (with a redirectLimit of 5), onExit, fullscreen / fullscreenDialog, opaque, barrierColor, barrierDismissible, transitionsBuilder and errorBuilder.
    • 新增声明式路由表:ZeroRouter、ZeroShell、ZeroTab 与 ZeroRoute,支持嵌套路由、:param 片段、name、title、路由级与路由表级 redirect(redirectLimit 默认 5)、onExit、fullscreen / fullscreenDialog、opaque、barrierColor、barrierDismissible、transitionsBuilder 与 errorBuilder。
  • Added the master-detail pane semantics: SlidingPanes (1/2 columns, slide-in detail with parallax master, draggable resize handle), SlidingPane, Breadcrumbs, Breakpoints and BreakpointClass — all usable without the router.
    • 新增 master-detail pane 语义:SlidingPanes(单列 / 双列、detail 右滑入带 master 视差、可拖拽分割线)、SlidingPane、Breadcrumbs、Breakpoints 与 BreakpointClass——均可脱离路由单独使用。
  • Added configurable pane expansion direction: SlidingPanesSide plus the side / paneSide / paneSideListenable options, so the detail pane expands to the right (default, master on the left) or to the left (master on the right) — and paneSideListenable flips it at runtime without rebuilding the router.
    • 新增可配置的展开方向:SlidingPanesSide 及 side / paneSide / paneSideListenable 选项,使 detail pane 可向右(默认,master 在左)或向左(master 在右)展开;paneSideListenable 可在运行时切换而无需重建路由。
  • Added configurable pane sizing: leftPaneFraction on ZeroRouter (the initial master pane fraction, previously fixed at 0.4) and maxLeftPaneWidth on ZeroRouter / SlidingPanes — a pixel ceiling so the master pane still scales with the window but stops at a sane width on ultra-wide displays, with the detail pane absorbing the remainder. The ceiling applies to dragging too.
    • 新增可配置的 pane 尺寸:ZeroRouter 上的 leftPaneFraction(master pane 初始占比,此前固定 0.4)与 ZeroRouter / SlidingPanes 上的 maxLeftPaneWidth——像素上限,使 master pane 仍随窗口缩放,但在超宽屏上停在合理宽度,剩余空间由 detail pane 吸收;拖拽同样受该上限约束。
  • Added window-width breakpoints (600 / 840) decoupled from the device type, so foldables, small desktop windows and browser zoom all classify correctly.
    • 新增基于窗口宽度的断点(600 / 840),与设备类型解耦,折叠屏、桌面小窗与浏览器缩放都能正确归类。
  • Added URL addressability and deep links: every screen is in the route table, the web defaults to the hash strategy (/#/products/42) so GitHub Pages needs no 404 fallback, and browser back, refresh and deep links share the same location pipeline as in-app navigation.
    • 新增 URL 可寻址与深链:每个页面都入表,Web 默认 hash 策略(/#/products/42),GitHub Pages 无需 404 fallback;浏览器返回、刷新、深链与应用内导航走同一条 location 管道。
  • Added ZeroShellChrome for the compact bottom NavigationBar rendered inside branch pages, so modal bottom sheets opened with useRootNavigator: false can cover it; pushed pages hide it by default (hidesBottomBarWhenPushed).
    • 新增 ZeroShellChrome:compact 底部 NavigationBar 渲染进 branch 页面内部,useRootNavigator: false 打开的 bottom sheet 可覆盖它;push 的页面默认隐藏底部栏(hidesBottomBarWhenPushed)。
  • Added ZeroShellScope, ZeroShellState, ZeroPaneScope, ZeroRouteState and ZeroRouteStateScope for reading shell state, pane titles, path / query parameters and arguments from anywhere in the tree.
    • 新增 ZeroShellScope、ZeroShellState、ZeroPaneScope、ZeroRouteState 与 ZeroRouteStateScope,可在树中任意位置读取 shell 状态、pane 标题、路径 / 查询参数与 arguments。
  • Added ZeroNav.locationListenable, a ValueListenable<String> for reactive UI via ValueListenableBuilder (zero runtime dependencies, no signals).
    • 新增 ZeroNav.locationListenable:ValueListenable<String>,可通过 ValueListenableBuilder 做响应式 UI(零运行时依赖,不用 signals)。
0
likes
160
points
355
downloads

Documentation

Documentation
API reference

Publisher

verified publisherzerolabsco.com

Weekly Downloads

Adaptive navigation for Flutter: one onTap, the right behavior everywhere.

Repository (GitHub)
View/report issues
Contributing

Topics

#navigation #router #adaptive #responsive #master-detail

License

MPL-2.0 (license)

Dependencies

flutter

More

Packages that depend on zero_adaptive_link