Skip to content

Latest commit

 

History

History
294 lines (207 loc) · 78.7 KB

CHANGELOG.md

File metadata and controls

294 lines (207 loc) · 78.7 KB

Unreleased

  • SplitContainer(containers)修 分隔条拖一下就卡死:拖动起点记在 build() 的局部 late double dragOrigin 里,而每个 DragUpdate 都 setState 重建,GestureDetector 会把在途识别器的回调就地换成新闭包——新闭包捕获的是本次构建的局部量,它的 onDragStart 永远不会被调用,于是第二个事件读未初始化的 dragOrigin 抛 LateInitializationError: Local 'dragOrigin' has not been initialized。宿主表现是「键值浏览页上下两栏的分隔条只能拖约 10px,之后鼠标拖着走、栏不动」,异常只进日志不上屏。现在拖动起点(首块像素尺寸 + 指针全局坐标)记在 State 字段上,更新按绝对坐标算增量,重建换闭包不再影响在途拖动;同时补上 onDragEnd / onDragCancel 收尾(原先松手后起点状态残留)。回归测试见 test/split_container_drag_test.dart(横 / 竖两向,分多次小步拖动要求累计位移与指针位移 1:1;另测拖过 minFirst 后反向拖能立刻跟手)。

  • DataGridView(lists)修 右键只弹菜单、不改选中:右键分支原先在 onCellContext 之后直接 return,把选中逻辑留在了它后面,于是「右键落在哪个格」和「菜单作用于哪个格」是两件事——宿主菜单里的「置空 / 置为 NULL / 复制」跟着上一次的左键选区走,用户看着高亮框点右键,操作却打在别的格上。现在右键先让落点成为选中目标再弹菜单:落在选区外收缩为该单元格(行号列同理为该行为唯一选中),落在选区内保持整个集合不动,所以「置 NULL N 格 / 复制 N 行」这类批量口径不受影响。仍在同一条 Listener.onPointerDown 路径上完成,按下即生效、零延迟,也不触发 onCellTap(右键不进就地编辑)。onCellContext 的契约据此更新:宿主可直接读当前选中态来组织菜单项的单数/复数文案,不必自己补一次选中。

  • TabControl(containers)的 TabItem 新增可选 tooltip:非空时标签头包一层 WinToolTip(500ms 延迟,桌面悬浮习惯),鼠标悬停显示完整对象路径——宿主用它区分同名表(不同库 / 模式的 organizations 标签标题相同,只有悬浮才看得见 表名 @ 库名(连接名)- 分类)。null / 空 = 不显示,行为与旧版一致;包 WinToolTip 在 header 外层、不改标签宽度测量(_headerWidth 只量 label),故纯标签条自适应排布不受影响。

  • 新增 ImeSuppression(foundation / ime.dart,barrel 导出):一个宿主注入的关输入法钩子,Input 在 obscureText 密码框获焦时调 handler(true)、失焦时调 handler(false)。base-ui 自身零平台代码,钩子默认 null(不接线时行为与旧版逐字一致)。解决的是 Flutter/Windows 的硬伤:没有「按字段禁用系统输入法」的 API(open issue flutter/flutter#181487),中文输入法会把未上屏的拼音也塞进 obscureText 的圆点计数里——宿主实测「打 bx 显示三个点、回车上屏变两个点」,圆点数对不上真实输入、还弹候选窗。有了这个钩子,桌面宿主可把密码框获焦期间彻底关成裸字符输入。Input 侧记住 _imeSuppressed 状态保证 suppress / restore 成对,并在 dispose(获焦时窗口被关)补一次还原,避免输入法被永久解绑。回归测试见 test/input_ime_test.dart。宿主接线见 daro lib/app/ime_suppressor.dart + windows/runner 的 daro/ime 通道(ImmAssociateContext)。

  • ToolStrip(menus)修 trailing 根本没钉在右缘:左侧按钮组用的是 Flexible(fit: loose),而 loose 不吸收主轴余量,于是 Row 把空量留在末尾,trailing 仍紧贴按钮尾巴、整条右半空着(注释里承诺的「把 trailing 钉在右缘」从未发生)。改成 Expanded 后按钮组吃掉余量,trailing 真正贴右;按钮多到放不下时照旧横向滚动,不会撑爆报 overflow。回归测试见 test/tool_strip_trailing_test.dart(窄按钮组时 trailing 与右缘对齐 / 12 个按钮不溢出)。

  • ExpandableSearch(form)展开态改为跟随外部 controller 的初始内容:controller.text 非空时直接以输入框起步,不再恒从放大镜开始。宿主把过滤词存在跨页面存活的状态对象里(daro 的对象面板搜索:切去表数据页会让面板整棵子树销毁),旧行为是内容其实还在、却被藏进放大镜,看着就像「搜索被清空了」。不传 controller 时行为不变(自建空 controller → 收起态)。

  • ListPickerDialog(dialogs)按宿主参考工具(Navicat 表设计器「继承自」)的实测形状重做,由裸勾选清单改成带表头的单列网格:① 新增 itemHeader(缺省 名称)——列表上方一条 secondaryColor 表头,候选只有一列;② 行首加 16px「当前行」槽,打开时第 0 行为当前行,单击行即把 ▶ 移过去(Listener.onPointerDown,零延迟),勾选状态不受影响——点行=选行、点框=勾选,两套语义分开(原实现整行 onTap 即勾选,鼠标想确认看哪一行就顺手改了选择);③ 底部左侧新增 ↑ / ↓(IconBtn,边界行自动置灰),移动当前行;④ 确定后按当前行序回传,不再是候选列表顺序。第 ④ 条是行为变更而非装饰:调用方要的是「用户排出来的顺序」(INHERITS (父表…) 就按这个顺序写),按候选顺序回传等于把 ↑↓ 白做。行渲染内置(不再走 CheckedListBox),尺寸 / 配色全部仍从 DesktopTokens 取。回归测试见 test/list_picker_dialog_test.dart。

  • 新增 TextDiffView(data / text_diff_view.dart,barrel 导出):左右分栏的「之前 / 之后」逐行对比。diffTextLines(a, b) 是顶层纯函数(先掐公共前后缀、中段跑 LCS,> 600 行退化为整段增删,避免打开页面卡在计算上),返回两侧行数相同的对齐行,故两栏共用一条垂直滚动、行高天然对齐;紧邻的「删除段 + 新增段」一对一配对成 replaced,改动行在两侧同一行上同色,而不是左一条红杠右一条绿杠各说各话。配色按 token 派生并随明暗自适应(亮色加深、暗色提亮),空槽(该侧没有这一行)用中性灰与「有内容但没变」区分。宿主用它复刻参考工具(Navicat)视图设计器 SQL 预览的 DDL 对比页。回归测试见 test/text_diff_view_test.dart。

  • 新增 gridCellTokens(t)(lists / grid_metrics.dart,barrel 导出):表格与属性面板的紧凑尺寸档——fontSize ≤ 12、controlHeight ≤ 20、controlPaddingX ≤ 5(实测参考工具的设计器:行高 20.5、属性字段高 19.5、单元格文字左内边距 5)。与 menuPanelTokens 同一套约定:按 min 上限收,故幂等(宿主重复套不会越缩越小)、且用户把字号调得更小时保持用户的更小值;只动尺寸,不碰颜色。宿主用法是把整块区域包进 TokenScope,区域内的 Input / ComboBox 一起落档,不必逐控件传 height(ComboBox 本来也没有 height 形参)。

  • ComboBox(common)两处: ① 新增 showBorder(默认 true):传 false 得到贴在宿主网格上的扁平单元格——不描边、不填底,文字直接落在网格线上。与既有 Input.showBorder 同一约定;daro 的表设计器网格静止态每格都不该有框,只有 1px 网格线。 ② 修每次重建都白造一整套候选项 widget:build() 里无条件把 items 映射成 DropdownMenuItem(每项一个 Text)列表,而这份列表只有 _buildEditable 的一个从未使用的形参在收——即下拉没打开也在按选项数造 widget。宿主把设计器网格的类型列(40+ 个类型候选)做成常开编辑器后,这直接进到了每次敲字的重建成本里。现在随参数一并删除。 ③ 新增 onTextChanged(仅 editable 模式生效):用户在输入框里敲字时回调原文。onChanged 只在从下拉列表里选中一项时触发,手打的自由文本(如类型单元格里直接敲 varchar(50))从不经它——需要留下用户输入值的宿主必须同时接这个,否则 typed 的值静默丢失。

  • CheckBox(common)新增 size:方框边长,缺省仍是 controlHeight * 0.5。宿主把行高压到 20 之后,按比例算出的方框只剩 10px,比参考工具实测的 13px 小一圈;勾选框是命中目标,不该跟着行高缩。

  • ToolbarButton(menus)两处: ① 新增 paddingX(缺省 compactSpacing * 2 = 8)。纯图标按钮的点击块宽 = 图标 + 2 × 内边距,参考工具实测那一档是 25(14 图标 + 5.5 × 2);只给 width 不改内边距的话,内容固有宽 30 > 外框 25 会直接溢出报错。 ② 修 tooltip 与 width 互斥:Tooltip 原先包的是内层 content,于是设了 width 的按钮一旦带 tooltip,定宽那层 SizedBox 就被丢掉、按钮退回内容宽。现在 Tooltip 包在最外层。

  • ToolbarButton(menus)新增 filled / caretAtEnd / width,Popover(overlay)透传 toggleOnTap:给「白底定宽下拉框 + 拆分按钮」用的三个正交开关。filled = WinForms ComboBox 的静态字段外观(backgroundColor 白底、borderColor 恒灰描边,hover / pressed 不变色不变底——下拉框是输入区不是按钮,跟随 hover 会误导可点性);caretAtEnd 把尾部 ▾ 钉到控件右端、文本吃掉剩余宽度并省略号截断(需配合 width,缺 width 时退化为普通间距,避免 Spacer 在无界宽度下抛断言);width 固定总宽。Popover.toggleOnTap: false 让触发区点击不再开合弹层、纯由 controller 驱动——拆分按钮(主体按下即执行、尾部小箭头单独开菜单,如 daro 查询页「▷ 运行 ▾」)需要这种分工,AnchoredOverlay 早有此参数只是 Popover 没露出来。

  • Button(common)ghost 变体的聚焦态不再铺底色,只保留强调色描边。原先 ghost 聚焦会叠一层 primaryColor 14% 的浅蓝底,而宿主工具条 / ribbon 上「当前模式」的选中态通常是同一族浅色染色(daro 的 ribbon 用 accent 16% 叠 control)——两档颜色肉眼几乎分不出,于是点了「新建查询」再切分类,同一排会出现两个看着都被点中的按钮。焦点是输入焦点、选中是状态,两套语义不能共用一种画法;现在聚焦只画一圈描边(Tab 键可达性不变),底色让给宿主的选中态。

  • TabControl(containers)标签条按 Navicat 实测重做溢出与配色: ① 新增 pinnedCount——条首前 N 个标签排在滚动视口之外,永不随滚动位移(宿主用它钉住主入口页)。固定标签照常参与选中与键盘导航,_ensureVisible 对它们直接跳过;判定「要不要出箭头」时先把它们的宽度从可用宽度里扣掉,否则固定块会被算进可滚动内容、标签稍多就误判溢出。 ② 修标签多到溢出时两个箭头一个都不出现(整条标签再也滚不到):两端可用性原先只挂在滚动监听上,而监听要等用户已经滚过才触发。现在溢出判定与两端可用性统一由测宽回调 _syncScrollMetrics 结算(滚动监听只刷新箭头),并且只要溢出就恒定画出两个箭头、滚不动的一侧置灰——按「能不能滚」决定显隐会让箭头在触底时突然消失,整条标签左右抽搐 24px。左箭头紧跟在固定块右侧,不摆到整条最左端。 ③ 滚轮压在标签条上即横向滚动(Listener.onPointerSignal,不必去够那对小箭头);键盘 / 右键菜单切到被裁掉的标签时自动 _ensureVisible 滚进可视区(延到下一帧,重排尚未完成)。 ④ 新增 unselectedTabColor:未选中标签底色可显式钉死。缺省仍是「条底向 surfaceColor 提亮一档」,但宿主 surfaceColor == background 且要求白色标签条时,提亮结果会落在 #FCFCFC~#FDFDFD 这类近白上、整条发脏——纯白底必须直接传纯白。 ⑤ 底线不再叠成 2px:带正文的标签条由 TabControl 画一条横贯全宽的发丝线,未选中标签不再自画底线(_TabHeader.stripBottomLine);纯标签条没有那条全宽线,每个格子才自己补,否则一排标签悬在白底下沿全无交代。标签条底线与页面面板轮廓改用 buttonBorderColor(比通用细线深一档)——面色是白的时候用 borderColor 会糊成一片,与 Button「面色变白后补回轮廓感」同一条规则。回归测试见 test/tab_control_pinned_test.dart(固定标签不随滚动位移 / 不设 pinnedCount 时逐字节等价旧版 / 固定宽度不计入可滚动内容故不误判溢出 / 箭头格有顶边与底边)与 test/tab_control_chrome_test.dart(纯标签条只给未选中标签画底线、带正文的标签条不重复画)。

  • 日期时间选择器按 Navicat 重排,并把日历升级为三级快选: ① MonthCalendar(dialogs)顶栏标题改为可点——日视图点标题进月份快选(4×3),月视图点标题进年份快选(12 年一档),再点回日视图;左右箭头按当前视图步进一档(月 / 年 / 12 年)。日格固定铺满 6 周,月外日子按参考图画成灰显且可点(选中该日并翻到所属月),底部补一行「今天: yyyy/m/d」图例。weekdayLabels 参数取消,统一改走 labels。 ② 新增 TimeField(form):单行 HH:MM:SS + 右缘竖排上下按钮,替掉弹窗里「时 / 分 / 秒」三行 NumericUpDown。三段各自可点为当前段(强调色底),上下按钮 / 滚轮 / ↑↓ 只作用在当前段并按 24 / 60 进制回环;← → 切段,Home / End 跳两端,数字键累加(装不下第二位时自动前进到下一段,拼不出合法值时以新数字重启该段),Backspace 退回上一段并清零。刻意不用 TextField:IME 与选区会搅乱「哪一段是当前段」,而取值永远是定宽三段。 ③ DateTimePickerLabels 破坏性调整:去掉 time / hour / minute / second(三行微调没了),新增 today / monthNames / monthTitle / yearTitle / yearRangeTitle。三个标题是模板而非格式化函数({year} / {month} / {monthName} / {from} / {to} 在渲染时由 fill() 替换),const 构造因此仍然成立,中文 '{year}年{month}月' 与英文 '{monthName} {year}' 的语序差异各说各话。宿主侧注意:gen-l10n 的 ARB 不允许正文出现裸 {}(会当占位符解析),故 daro 的 ARB 用 [year] 方括号书写、由宿主换成花括号。 ④ 三个弹窗(date / time / dateTime)改用共用的 _PickerShell(264 / 200 定宽、controlColor 底、compactSpacing * 2 内边距)与居中的「确定 + 取消」动作行,与居中的「确定 + 取消」动作行,与参考图留白一致。回归测试见 test/month_calendar_test.dart(三级下钻与回退 / 箭头按视图步进 / 邻月灰显日可点并翻月 / 区间把整月整年一起禁用)、test/time_field_test.dart(段命中 / 回环 / 累加前进 / Backspace / 滚轮 / 禁用态),以及 test/inline_editor_date_picker_test.dart 里新增的整弹窗用例(打开时显示值所在的月、标题下钻选月、TimeField 改分,确认后的合并值 2022-03-25 20:14:06 三项各自归位、未动的秒沿用原值)。演示页 calendar.quickPickHint 补了一句「点标题可快速选月 / 年」。

  • DataGridView(lists)新增可选横向虚拟化 horizontalScrollController + horizontalViewportWidth:宽表把整个网格放进外层横向 SingleChildScrollView 时,每一行的 Row 原先会把所有列都建成真实 widget(哪怕横向滚出视口),于是「勾选列 / 选择 / 拖拽改列宽」等任何触发网格重建的操作,成本 ∝ 可见行 × 全部列(daro 表数据页 21 列 × 约 36 行 ≈ 750 格 / 帧,勾选时肉眼可见掉帧)。同时传入横向滚动控制器与视口宽后,数据行只渲染与视口相交的列,用左右占位条撑出等宽(横向滚动范围、_colAtX 命中测试、选中坐标均不受影响),把每帧重建量降到 ∝ 可见行 × 视口内列。默认关闭——不传这两个参数时逐字节等价于旧版,表头始终整行渲染(列宽调整 / 排序手柄需常驻,且仅 1 行成本可忽略)。回归测试见 test/data_grid_hvirtual_test.dart(视口外列不建 widget / 横向滚动换窗 / 换窗后点击命中正确列 / 行号列随内容滚出 / 无视口宽回退整行)。

  • Input(common)修字段内按钮点不动:trailing(行内编辑器的日历/时钟按钮)与 obscureToggle(密码眼睛)此前直接挂在 Row 里,落在 TextField 自带的 TextFieldTapRegion 之外——按下那一下被 EditableText 判成「点到框外」,默认行为是直接失焦。宿主只要把「失焦」当提交(InlineEditor 就是),编辑器会在抬起之前被拆掉,按钮的 onTap 永远收不到,表现为「点日历没反应」。表格里按下必然伴随宿主选中重绘(多出一帧),所以只在单元格内稳定复现、单独摆一个编辑器反而正常。现在两者都包进 TextFieldTapRegion,与输入框同属一个点击区。回归测试见 test/inline_editor_date_picker_test.dart(按下 → 渲染一帧 → 抬起的真实节奏下弹窗照常打开、且不触发失焦提交;去掉包装即红)。

  • 新增 buildTextBoxContextMenu(context, editable, {tokens})(menus)与 ContextMenuPanel:Input 的右键菜单不再用 Flutter 自带的 Material 选择工具条(圆角浮层 + 图标按钮,和全库的 Win10 菜单不是一套),改走本库面板渲染。剪切 / 复制 / 粘贴 / 全选恒定列出,当前做不了的置灰而不是隐藏(可用性仍取自 EditableTextState.contextMenuButtonItems,它才知道只读框不能粘贴、无选区不能复制),快捷键标在右缘,菜单左上角落在鼠标按下处并在屏幕边缘折回;标签取 MaterialLocalizations(cutButtonLabel 等,因此跟随宿主语言),动作与收起都交回 EditableTextState(onPressed / hideToolbar)。粘贴项可用性依赖异步回来的剪贴板状态,故面板包一层 ValueListenableBuilder(clipboardStatus),状态到达后自动从置灰变可用。ContextMenuPanel 是从 showContextMenu 抽出的面板本体(边框 + 条目列,不含定位与点击外部关闭的屏障),两处共用同一套绘制。回归测试见 test/text_box_context_menu_test.dart(弹的是本库面板且四项全在 / 点「全选」真的全选并收起;去掉 contextMenuBuilder 即红)。

  • ScrollBar(scroll)新增 notificationPredicate(透传给 Material Scrollbar):修纵向条挂在横向滚动区外面时整条不显示。Material 的 Scrollbar 默认只接收 depth == 0 的滚动通知,宽表网格的标准摆法(纵向条包住横向 SingleChildScrollView,内层再放纵向 ListView)中,内层通知冒泡经过横向 Scrollable 会被记为 depth 1、全被默认过滤器拒收,纵向条因永远拿不到尺寸而不绘制。宿主传 notificationPredicate: (n) => n.metrics.axis == Axis.vertical 按轴过滤即可。回归测试见 test/scroll_bar_test.dart(嵌套结构下断言右缘画出轨道/滑块矩形;去掉 predicate 即红)。

  • DataGridView(lists)单元格内容改为在列内居中:column.alignment 此前是把整格包一层 Align,右对齐列的容器会按文字宽度收缩——竖向网格线和选中底色跟着文字走而不是贴着列缘;且默认 centerLeft 分支根本不包,文字被拉成整行高并贴着行顶(行高一密就明显看出没居中)。现在对齐落在装饰容器内部的 Align 上,容器恒占满列宽,两个轴都由 column.alignment 说话(数值列传 Alignment.centerRight)。编辑态不受影响(编辑器仍撑满整格)。回归测试见 test/data_grid_cell_alignment_test.dart(左/右对齐的文字中线与单元格中线重合、右对齐列容器仍等于列宽)。

  • Input(common)新增 height:控件高度,缺省仍取 controlHeight(28)。表格行做密集后(22px)行内编辑器会撑破行——原先 Input 把高度写死成令牌值,宿主无法压低;现在内部垂直留白按此高度推导(contentPadding 为自定义值时只追加垂直分量,横向仍归宿主)。InlineEditor(form)随之将自身 height 透传给 Input,并新增 textAlign:数值列右对齐时编辑态与显示态同向,Enter 进编辑文字不跳位。

  • CheckBox(common)勾选态改为实心:选中 = primaryColor 填充 + accentForegroundColor 白色勾号 + 3px 圆角,未选中仍是描边空框,禁用勾选为 controlDisabledColor 底 + 禁用勾号。原「透明底 + 边框 + 前景色勾号」的传统 WinForms 画法在密集列表(字段勾选、导入候选)里视觉重量太低,扫读时不易分辨勾没勾。配套:CheckedListBox(lists)此前违规直接使用 Material Checkbox 自绘实心样式,现改为复用本组件(onChanged 置空 = 被动指示器,点击仍由整行 onTap 结算,无双切换手),全库勾选框收敛为一种画法。

  • TreeView(lists)新增 rowBuilder 与 framed:前者让宿主接管行内容(图标 / 次级灰字后缀 / 徽标这类内置「一行一个标签」画不出来的行),行盒的高度、缩进、命中区仍由组件负责,宿主通过 TreeRowContext 拿到 depth / selected / expanded / hasChildren / tokens 和 toggleExpand;提供 rowBuilder 时组件不再绘制实心强调色选中底(自带图标与次级文字的行通常要的是浅色染色 + 描边,实心蓝会把图标吞掉),不传时行为与旧版逐像素一致。framed: false 去掉外框与底色,供宿主面板自身已经有边框 / 内边距时使用(原先这类场景只能把边框留在那里叠成双线)。典型用法见 daro 的 PostgreSQL 依赖页(「使用 / 被使用」:schema.name + 灰色 KIND (DEGREE) + 外键下挂内部触发器子项)。

  • 日期时间选择弹窗改为可独立复用的入口:新增顶层 showDateTimePickerDialog(context, {mode, value, minDate, maxDate, labels}),返回确认后的 DateTime?(取消为 null)。DateTimePicker 自身的三种模式全部改走该入口,三个私有弹窗从「外部可变闭包 + 回调」改为 Navigator.pop(结果),宿主想在自己的字段右缘挂一个「…」选择按钮时可直接调用,不必复制弹窗结构。合并规则不变:date 只换日期保留时间、time 只换时间保留日期。 配套:① 新增 DateTimePickerLabels(ok / cancel / time / selectTime / hour / minute / second / weekdayLabels),库内默认英文,宿主按 ComboBox.searchHint 的同一约定传自己语言的文案;DateTimePicker 新增 labels 字段。② MonthCalendar 新增 weekdayLabels(周一开头 7 项,null 用内置 Mo…Su)——星期表头原先写死在 State 里,中文宿主无法本地化。③ 修 time 模式丢失已有秒数:_TimePickDialog 的秒固定从 0 起算(只取了 TimeOfDay 的时/分),确认后把原值的秒清掉了;现在初值直接收 DateTime,秒沿用。另导出 formatDateTimeByMode(dt, mode) 与 parseDateTimeField(text)(接受 2022-12-12 20:13:06 这类带空格、DateTime.tryParse 不认的库内格式),供宿主做「文本 ↔ 值」往返。裸时间 20:13:06 也认(锚到今天,只为取回时分秒),否则 time 列一打开就掉到当前时刻。 另修一处实测缺陷:日历原先永远开在当前月——_DatePickDialog / _DateTimePickDialog 只传 selectedDate 不传 displayMonth,MonthCalendar 于是回落到 DateTime.now();编辑一个 2022 年的值,弹层显示的是当前月,选中日既看不见也点不到,随手点「确定」还把年份改掉了。两处现在都传 displayMonth: 选中值。回归测试见 test/inline_editor_date_picker_test.dart。

  • Input 新增 trailing(common):渲染在边框内右缘的附加控件(「…」浏览、日历按钮这类字段内动作),与密码 obscureToggle 的眼睛可共存(眼睛在前、trailing 最右);两者都为空时渲染结构与旧版完全一致。 InlineEditor(form)据此新增 datePickerMode / datePickerLabels:传入模式即在字段右缘挂一个日历(date / dateTime)或时钟(time)按钮,点击弹出 showDateTimePickerDialog,确认后按该模式的默认格式写回文本(yyyy-MM-dd / HH:mm:ss / 两者),onChanged 照常触发,Enter / 失焦提交与 Esc 取消语义不变。关键守卫:弹窗会抢走焦点,原先「失焦即提交」会在打开弹窗那一刻带着旧文本结算掉编辑器,故新增 _picking 标记,选值期间的失焦不算离开编辑器,弹窗关闭后把焦点还给输入框。

  • LinkLabel(common)新增 underline(默认 true,行为与旧版一致):可关掉下划线,只保留链接色。桌面详情面板(如 Navicat 的库 / 表信息页)把「共享」这类动作渲染成蓝色文字但无下划线,硬编码的下划线会让它和同排的普通文字抢视觉重量。取色与禁用态不变(primaryColor / disabledForegroundColor),hover 手型也保留——去掉下划线不改变它是可点的。

  • Surface(common)去掉 hover / pressed 的 120ms 颜色渐变(AnimatedContainer → Container)。未选中态底色是 transparent(即 0x00000000,RGB 通道为 0),向浅灰插值时通道会先经过半透明的深灰——鼠标进入一个无边框 / 透明底的可交互面(Toggle、菜单行、列表行)会看到「先黑一下、再变浅」的两段跳色,而不是直接落到悬浮色。顺带符合本库的快节奏约定:悬浮反馈无动画(WinForms 语义)。所有以透明为常态底色的组件同时受益,无需各自绕路。

  • Toggle(common)新增 ToggleVariant.ghost:与 default_ 一样无边框,但选中态取 outline 的淡强调色染色(accentColor 16% 压在 controlColor 上)而非实心强调底,前景保持主文字色——供「图标 + 文字」这类自带颜色的开关使用,实心蓝会把图标线稿的蓝色强调吞掉。多个 ghost 开关紧邻排列即为工具条分段样式。未选中态的悬浮底色同时从 mutedColor 改为 controlHoverColor(winForm 预设 #E1E1E1):mutedColor(#F4F4F4) 是行号槽那类近白底色,悬停在纸白工具条上几乎看不出来。回归测试见 test/modern_components_test.dart(hover 一帧内落定悬浮色 / ghost 选中染色且无边框)。

  • ComboBox(common)新增 searchable(默认 false):只读下拉的面板顶部多一条搜索行(放大镜 + 单行输入,文案走 searchHint / noMatchText,缺省英文、中文由宿主传入),输入即按 itemToString 做大小写不敏感的子串过滤,无匹配时留一行占位文案(面板不塌)。输入只是过滤、不是取值 —— 这一点与 editable(允许提交 items 之外的自定义值)刻意分开:连接 / 库 / 模式这类「值必须来自列表」的选择器可以放心开输入搜索,敲错的查询永远提交不上去(Enter 取第一个匹配项,Escape 关面板,面板每次打开都从「无筛选」开始)。面板高度随过滤结果收缩(最多 10 行),搜索行严格等于 controlHeight、由独立一层 1px 分隔线收口。 同时修掉两处面板刷新缺陷(旧代码里都存在):① 候选列表 / 选中下标原先在 _buildOverlayEntry 里捕获,而 OverlayEntry 刷新时只重跑自己的 builder —— 过滤与 hover 高亮都会拿着「打开那一刻」的旧值不放(症状就是输入没反应、鼠标划过不高亮),现在一律在 builder 内现算,刷新统一走 markNeedsBuild;② 面板外层 Container 的 decoration 边框会被 Container 当作内边距用,子项可用高度比 maxHeight 少掉两条边框 —— 一旦把列表换成固定高度就稳定溢出 2px,故去掉 constraints(各行高度本就算死,不需要兜底)。回归测试见 test/widgets_test.dart(输入窄化列表 / Enter 取首个匹配 / 无匹配查询绝不提交 / 只读模式无搜索行)。

  • TabControl 标签头改为按内容自适应(对齐 Navicat 的紧凑标签条):高度 = 标签行高 + compactSpacing * 0.75 * 2 + 边框(winForm 令牌下未选中 20.65 / 选中 23.65,Navicat 实测 20.5 / 23),宽度 = 实测文本宽 + compactSpacing * 2 * 2(下限 compactSpacing * 11 = 44)。barHeight / tabWidth 只在调用方显式传参时才固定宽度/高度,原先各宿主硬编码的 24/26/30/32 与 56/62/72/76/82/96 一类数字全部可以删掉 —— 长度不一的标题(「消息 / 结果 1 / 结果 12」)不再被压成省略号,短标题也不再白占一整格。测量文本必须用 DefaultTextStyle.of(context).style.merge(标签样式):Material 的默认文本样式带 letterSpacing,拿裸 TextStyle 量会偏窄、长标题被压成省略号;可关闭标签(TabItem.onClose)在自动宽度里额外预留 20px 关闭按钮位(按钮 hover 才出现,不预留会挤掉文案)。新增 TabControl.stripHeight(tokens) 静态入口,供宿主计算「标签条 + 页面面板」占掉的高度 —— 对话框里原先硬编码的 _kTabChromeHeight = 32 之类已无必要(组件度量一改就会静默错位)。

  • TabControl 标签条 chrome 修正:每个标签都画顶边 + 右侧 1px 分隔线,但左边线只在「标签条与正文构成闭合框」时才画(drawLeftEdge = hasBody && i == 0,供对话框封左边框);纯标签条场景(所有 TabItem.child 为 null,如文档标签条)不画 —— 它悬在背景上,画出来就是面板左边框旁凭空多出一条 1px 竖线。未选中标签底色 = 向 surfaceColor 提亮 22%。

  • DesktopTokens 新增按钮专用令牌组:buttonHeight(默认 24)/ buttonMinWidth(默认 73)/ buttonFaceColor / buttonBorderColor / buttonHoverFaceColor / buttonHoverBorderColor / buttonPressedFaceColor / buttonPressedBorderColor(winForm 与 shadcn 两版预设均已给值)。刻意与 controlHeight(28) 分离:桌面工具包的按钮总比单行编辑框矮一档(Navicat 实测按钮 73×24、输入框高 19.5),改按钮不应连带改到输入框 / 下拉 / 复选。Button 的 solid 变体接入:常态面取 buttonFaceColor、边取 buttonBorderColor(比通用控件边线略深一档,补回面色变白后丢掉的轮廓感);hover / pressed 走专用热态令牌,规则是「染强调色」而不是「把中性面色压暗」—— 后者只能叠出灰,越悬停越脏,参考图实测悬浮面 #E0EEF9 + 边 #0078D4、按下再深一档。下边框恒比上 / 左 / 右暗 ~10.5%(桌面按钮 VCL/Aero 的 3D 下缘;参考图常态 #D0D0D0→#BABABA、悬浮 #0078D4→#006BBE 同一比例),由 Color.alphaBlend(0x1B000000, 边色) 组件内现算,不另加令牌。只有 child == null 的纯文字按钮吃 buttonMinWidth(桌面对话框把「确定 / 取消 / 上一步」摆在等宽按钮列上,不会贴着字收紧);带 child 的工具条 / 图标按钮一律按内容自适应,否则窄工具条会被 73 撑破。ghost / primary 变体与禁用态外观不变。

  • 新增 DesktopTokens.withHairlineBorders(BuildContext context):把 borderWidth 按 1 / devicePixelRatio 收窄(下限 0.25),使边框恒定占 1 设备像素。参照物是原生窗口(Navicat / VCL),其边框恒为 1 物理像素、与显示缩放无关,而令牌里的 borderWidth = 1.0 是逻辑像素 —— 200% 缩放下会画成 2 物理像素,比原生窗口粗一倍(实测 daro 截图描边占 2 物理像素、Navicat 占 1)。单 DPI(100%) 下返回 1.0,行为与改前完全一致,只有高 DPI 屏才变。拿不到 MediaQuery 时原样返回。

  • 组件里不再写死线宽:CheckBox 的方框、MarqueeSelector 的选框、StepBar 的连接线(Container(height: 1))、ThemeDesigner 导出页输入框的描边,原先分别写死 width: 1 / height: 1,改为取 t.borderWidth。这些在 200% 屏幕上会明显比周围边框粗,且不收窄的话「1 设备像素边框」策略对它们无效。

  • DialogBox 底部动作条改为浅灰带:底色取 secondaryColor、上方 1px borderColor 分隔线、内边距 10/9(Navicat 实测),整条铺满对话框宽度(内边距由 Container 提供,浅灰底一直顶到对话框边框)。按钮面色朝纸白、压在浅灰条上,层次才出得来 —— 此前按钮与正文同底色,只靠一条空隙分隔,整块读起来是平的。

  • 新增 ThresholdDraggable(lists):只有真的拖了才起手的 Draggable。框架 Draggable 有两条「没拖就先起手」的路径,桌面端单击 / 双击都会闪拖拽特效:① 竞技场默认接受——本识别器是竞技场唯一成员时(桌面端鼠标点一个拖拽源通常就是这种情况,Scrollable 的拖拽识别器默认不接受鼠标),GestureArenaManager.close() 直接把这一手判给它,onDragStarted 在 pointer down 的微任务里就触发了,指针一寸没动而浮层预览、childWhenDragging 与宿主据此点亮的放置区已全部出现,松手再收回;② 鼠标起手容差只有 1px——框架对鼠标硬编码 kPrecisePointerHitSlop(只有触屏 / 触控板才读 MediaQuery.gestureSettings.touchSlop),单击 / 双击时几像素手抖即可判定成拖动。典型症状即「双击打开一行却闪出拖拽浮层」。本组件把阈值提高到 startSlop(默认 kDragStartSlop = 4px,与 Windows 的 SM_CXDRAG 及本库 MarqueeSelector.threshold 同量级),并把「竞技场判给本识别器」与「起手」分开:输了手势竞争不算,赢了但位移没到阈值也只挂起起手回调,位移够了才真正起手、不够就作废(不闪浮层、不触发 onDragStarted)。按下即拖的手感不变(不引入 LongPressDraggable 那种时间延迟),位移累计值在真正起手时一次性补报给浮层,拖起来不跳。构造函数逐字段对齐 Draggable,可直接替换。配套导出 ThresholdMultiDragGestureRecognizer(affinity 一个字段覆盖任意 / 水平 / 垂直三个方向,宿主用自己的 RawGestureDetector 时可直接用)。回归测试见 test/threshold_draggable_test.dart(唯一成员时单纯按下不起手 / 鼠标 3px 手抖不起手 / 位移跨过阈值才起手并落到 DragTarget / 有竞争识别器时同样成立)。

  • DataGridView(lists)行号列右键不再改选中:此前 _buildRowNumberCell 的 Listener.onPointerDown 对左 / 右键一视同仁先触发 onRowSelected 再在右键时补发 onCellContext,导致右键一行会先把多行选中打散成单选,与数据单元格「右键只弹菜单、不动选中」的语义不一致。现改为右键分支直接 return,仅左键(含 Ctrl / Shift 修饰)走 onRowSelected。宿主读修饰键做多行加 / 连选时不再被右键意外重置。

  • DataGridView(lists)新增 selectedRows(Set<int>?):多行选中渲染。集合非空时接管行底色与行号列选中态(rowNumberBuilder 的 rowSelected 参数),此时 selectedRow 被忽略。指针语义不变:onRowSelected 仍只回传点击行号,宿主自行读修饰键(Ctrl 加选 / Shift 连选)更新集合并回传,符合「行为归宿主、绘制归组件」的既有分工。用于表数据浏览页像 Navicat 那样多行选中 + 复制 / 粘贴 / 删除。缺省 null 与旧版一致,既有调用零影响。

  • DataGridView(lists)拖拽框选补上纵向滚动偏移:跟踪指针的 Listener 包在 ListView 外层,其 localPosition.dy 是视口坐标,而 _rowAtY 直接 dy ~/ rowHeight 当成绝对行号 —— 一旦滚动过(含框选到边缘触发的自动滚动),选中的是「可见第几行」而不是指针所在的行(纵向偏移越大错得越多,自动滚动时选区还会反向收缩)。现统一加上 verticalScrollController.offset。横向无需处理:该 Listener 本身在外层横向视口的内容坐标系里。回归测试见 test/data_grid_region_select_test.dart。

  • DataGridView(lists)框选模式下 onCellTap 改在抬起且未发生拖拽时触发:此前它挂在单元格的 onPointerDown 上,而 Listener 模式下选中与「进入就地编辑」必须分家 —— 按下就开编辑器,随后拖出的框选会和一个正在抢焦点的输入框打架。现在按下只更新选中集合(零延迟不变),抬手时若确认没拖动才补发 onCellTap,宿主可放心在此进入编辑;框选 / 拖拽收尾不会误开编辑器,onPointerCancel 同样不发。未传 onCellsSelected 的调用方行为完全不变。

  • InlineEditor(form)新增 selectAll(默认 false):进入编辑时全选初始文本,供节点内联改名等「键入即覆盖」场景使用;true 时 controller 预置全选区并同步 Input.selectAllOnFocus。默认值下行为与旧版完全一致(光标置于文本末尾),既有调用零影响。

  • 修复 Button(common)禁用态吞掉父级点击:onPressed == null 时 onTap / onTapDown / onTapUp 都已置空,唯独 onTapCancel 仍无条件注册,于是 TapGestureRecognizer 照样进入竞技场、并因层级比父级更深而胜出——父级收不到这次点击,按钮自己又什么都不做。现在 disabled 时四个点击回调全为 null,按钮彻底不注册识别器,包裹它的父级触发器(Sheet / Command 的 trigger: Button(...))恢复可用。与 WinForms 一致:禁用控件不吞鼠标消息。回归测试见 test/widgets_test.dart(禁用按钮点父级仍触发)与 test/modern_components_test.dart(SidePanel / Command 经禁用 trigger 打开)。

  • 新增 TabStrip(containers):扁平下划线标签条(浏览器 / Navicat 面板内子标签样式,如设计器「更改 / DDL」切换),TabControl 的轻量对应物。受控组件:宿主持有 index、响应 onChanged;选中项 = primaryColor 文字 + 2px 下划线 + 内容底色衬底,未选中项 hover 淡底。切换走 onTapDown(按下即触发,零延迟,不注册双击手势),零动画、无 Material 水波纹,取色链 tokens ?? TokenScope.maybeOf ?? DesktopTokens.winForm。

  • 新增 InputDialog(dialogs):单行文本 / 密码录入弹窗(「连接需要密码」这类打开前补录凭据的 WinForm 对应物)。由 DialogBox + Input + Button 组合,show 回传输入文本,取消 / 关闭 / Escape 回传 null。password: true 时输入框走 obscureText + 眼睛切换,且空输入禁用确定——调用方可契约式假定非 null 结果必非空;message 为输入框上方的提示文本,initialValue 预填,okText / cancelText 缺省 OK / Cancel(中文由宿主传入)。Enter 提交、零动画、无 Material 水波纹,取色链 tokens ?? TokenScope.maybeOf ?? DesktopTokens.winForm。

  • MessageBox(overlay)底部按钮区调整:去掉正文与按钮之间的 Separator 分割线,按钮行由右对齐改为居中。按钮顺序、自动聚焦(主按钮)、间距均不变。

  • 滚动条改为静止窄条、悬浮加宽:ScrollBar 由无状态改为自绘热区检测——MouseRegion 监听滚动条贴边一带(宽度 = 悬浮态宽度 + 4px),鼠标进入即把传给 Scrollbar.thickness 的宽度从 5px(kScrollBarSlimThickness)切回 8px(kScrollBarExpandedThickness,可用 thumbThickness 覆写,零动画即时切换)。不再依赖 Material 内部的悬浮 WidgetState(实测其在部分场景不可达)。同时新增 scrollbarHoverThickness():按 WidgetState.hovered / dragged 切换厚度的 WidgetStateProperty,供宿主写入全局 ThemeData.scrollbarTheme.thickness,让 Flutter 默认滚动行为为普通 ListView / ScrollView 生成的滚动条也走同一策略。thumbThickness 语义变为「悬浮态宽度」。回归测试见 test/scroll_bar_test.dart(纵向/横向悬浮、自定义宽度、状态解析器)。

  • CheckBox 的 onChanged 改为可选(common):字段本就是 ValueChanged<bool?>?,仅构造器标了 required。传 null 即渲染一个被动的勾选指示器——视觉与可交互态完全一致(边框仍取 foregroundColor,禁用仍走 enabled),只是不注册 tap / 键盘处理。用途:勾选框位于 DataGridView 单元格里时,外层单元格的 GestureDetector(onDoubleTap) 会把勾选框自身的 onTap 扣在约 300ms 的双击判定窗口里,单击看起来「没反应」;宿主改用 Listener.onPointerDown 在按下瞬间结算勾选,CheckBox 只负责显示状态。既有调用全部不受影响。

  • Toggle outline 变体的选中态改浅:不再填充实心 accentColor,改为 accentColor(16% alpha)叠加在 controlColor 上的淡色染色 + accentColor 描边,文字 / 图标前景保持 foregroundColor(不再换成 accentForegroundColor)。原因:宿主工具面板标签是「黑色线稿 + 蓝色强调」的自绘图标,实心蓝底会把图标里的蓝色部分整个吞掉。default_ 变体(加粗 / 斜体这类纯色图标工具栏按钮)仍是实心 accent 填充 + 反色前景,行为不变;outline 未选中态也完全不变。

  • Button 新增 ButtonVariant.primary(common):对话框 / 面板里唯一主操作的实心强调色按钮(确定、应用、保存)。底色 primaryColor、文字 accentForegroundColor,禁用时两者各降不透明度(0.45 / 0.6)而非换成灰色面;描边与底色同色(纯色块无边界感),仅在聚焦时换成 foregroundColor 描边。hover / pressed 仍走叠加色,但因 hoverOverlayColor 在实心色底上几乎不可见(约 4% 黑),两级都改用 pressedOverlayColor 叠加——hover 一层、按下两层,保证快节奏下反馈可辨。零动画、无 Material 水波纹,按下不抢焦点、完整点击才聚焦(与 solid 同一套焦点时机)。默认值不变,既有调用零影响。

  • DataGridView 表头支持两行标题:DataGridViewColumn 新增 subtitle(第二行文本,如列数据类型)与 subtitleGlyph(副标题前的 accent 色小字形,如 # / abc)。任一列带副标题时表头整体加高 14px 并切换为两行布局(标题行 + 14px 副标题行,无副标题的列第二行留空保持对齐);副标题字号比 headerFontSize 小 1.5px、取 mutedForegroundColor。全部列都不带副标题时高度与渲染与旧版完全一致,既有调用零影响。排序箭头仍位于标题行右侧。

  • DataGridViewColumn 新增 subtitleIcon(IconData?):与 subtitleGlyph 同一槽位的前导标记,画 11px 的 accentColor 图标。用于缩写文本表达不清的列类型(如日期时间族的时钟轮廓)。同时给出两者时图标优先、文本字形被忽略;两行的判定(表头加高、hasSubtitle)已把 subtitleIcon 计入。

  • 修复 DataGridView(lists) 数据行缺横向分隔线、最后一行没有下边框:此前每行的 Container 只画背景色,竖线来自单元格的 right 边框,但整表唯一的横线只有表头下边框与最外层 Border.all;当行数不满可视区(末行下方是空白)时末行像是悬空、没有收口线。现给 _DataGridRow 的行容器改用 BoxDecoration,保留原背景色的同时补上 bottom 边框(颜色 gridLineColor、宽度 borderWidth,与竖线一致),使每行都有下边线、最后一行自然收口,符合 WinForms DataGridView 的行网格语义。

  • 修复 ComboBox(common)下拉点击热区塌成文字大小:必须精确点到候选项/触发框的文字才能选中或展开,点行内空白或左右内边距无响应。根因是带 alignment 的 Container 内部走 Align、其命中测试为 deferToChild,背景虽铺满整行但空白区不参与命中;外层 Listener 默认同为 deferToChild,于是整行热区缩到子节点尺寸。现给只读触发框、只读候选项与可编辑候选项(_EditableOption)三处 Listener 补上 behavior: HitTestBehavior.opaque,使整行(含内边距与 Expanded 空白区)均可按下选中,零延迟交互与视觉保持不变。

  • 新增 MarqueeSelector(lists):桌面风格的框选(rubber-band / marquee)行为层。在 child 区域内按住左键拖动、位移超过 threshold(默认 4px,低于它视为普通点击)后进入框选,期间以 onMarqueeUpdate(Rect) 回调视口局部选框并绘制 accent 半透明填充 + 1px 描边浮层,起手触发 onMarqueeStart、松手 / 取消触发 onMarqueeEnd;enabled 可整体关闭,canStart 让宿主排除不该起手的地方(如内容区右缘滚动条命中带)。它不解释命中:把矩形换算成选中项交给宿主——定行高的网格 / 列表由宿主自己按几何算(配合 ScrollController.offset),无需测量渲染对象。指针事件走 Listener 而非手势竞技场:祖先 Listener 在 pointer down 时缓存命中路径,整段拖动都收得到 move/up,既不与子项自己的 onPointerDown 选中抢竞技场,也不会给子项单击引入约 300ms 的双击判定延迟(本项目「零视觉延迟」约束)。零动画、无 Material 水波纹,取色链 tokens ?? TokenScope.maybeOf(context) ?? DesktopTokens.winForm。

  • ComboBox 新增 iconBuilder(common):为候选项绘制前置图标(WinForms owner-draw 下拉的对应能力,如下拉项名前画一个引擎 / 实体图标)。同一个回调同时作用于收起态的当前值与展开态的每一行,图标盒子边长由 controlHeight - 8 推导并夹在 12~18px,与文本之间留 compactSpacing;返回 null 表示该项不画图,缺省不传则完全保持既有纯文本外观。只读与可编辑两种模式都已接入(可编辑模式下图标置于文本框左侧、吃掉一份 controlPaddingX 以与只读模式对齐),零动画、无 Material 水波纹。

  • 新增 ListPickerDialog(dialogs):泛型多选候选对话框——勾选任意个候选项后确定,show 按候选原顺序回传选中项(取消 / 关闭回传 null),自身不写回任何模型。由 daro 表设计器的 StringPickerDialog(选择继承的父表)上收泛化而来,满足「无业务依赖 + Token 驱动 + 可独立复用」的入库条件。由 DialogBox + CheckedListBox + Button 组合,零动画、无 Material 水波纹;okText / cancelText 缺省 OK / Cancel(与 MessageBox 一致,中文由宿主传入);itemToString 自定义行标签而回传的仍是原对象;emptyHint 用于无候选时的引导(宿主可同时保留手输入口)。取色链 tokens ?? TokenScope.maybeOf ?? DesktopTokens.winForm,与其它浮层一样默认走根导航器,故 TokenScope 需位于 Navigator 之上才跟随主题。泛型陷阱:selected 的默认值 const [] 在泛型声明处拿不到 T,运行时实际是 List<Never>,直接 toSet() 会让首次勾选的 addAll 抛 Iterable<Never> 类型错误——内部已改为 Set<T>.from(...)。回归测试见 test/list_picker_dialog_test.dart(按候选顺序回传、预勾选可取消、取消回传 null、空候选提示、T=int 且不传 selected 的组合)。示例画廊 Dialogs 分类新增 ListPickerDialog 页,并计入 example/test/smoke_test.dart。

  • Popover 新增 scrollable / maxHeight:内容过高时在面板内部滚动,而不是把整列铺出屏幕。修复前连接选择器这类下拉(db_lite 查询页「选择连接」有几十个连接)会把全部条目一次性渲染出来——面板高过视口顶部/底部被裁掉,且后面的条目根本选不到。scrollable: true 时滚动视图位于带边框的面板内部(背景与边框固定不动,只有行在动),maxHeight 缺省表示「最多占满视口、绝不超出」,显式给值则按值封顶(仍会与视口取小)。列表用 ListItem、crossAxisAlignment: stretch 的 Column 直接放即可,滚动条沿用控件库 token 化 ScrollBar;零动画、无 Material 水波纹。回归测试见 test/modern_components_test.dart(「Popover 内容过高时在面板内滚动」+ 未开启时的无界行为各一条),示例页新增 Scrollable 分组。

  • AnchoredOverlay 新增 maxHeight(Popover 的底层实现):在布局之前用 MediaQuery 把上限与视口高度取小(double.infinity = 只受视口约束),并把 ConstrainedBox 套在被 _contentKey 测量的那层 Container 上——这样 _remeasure 量到的就是封顶后的尺寸,贴边夹取与 OverlaySide.auto 选边都能基于真实高度正确计算。null(默认)保持既有「无界、可溢出视口」行为,既有调用外观不变。

  • 修复 AnchoredOverlay 测量帧的无限宽崩溃:浮层内容在算出位置前挂在 Offstage(offstage: true) 下,而 RenderOffstage 对隐藏子节点用的是空约束(maxWidth = ∞)。任何依赖有界宽度的内容——DropDownButton 的 Column(crossAxisAlignment: stretch)、ListView 等——在这一帧直接抛 BoxConstraints forces an infinite width,调试模式下弹层根本打不开。现给被测量的那层套 ConstrainedBox(maxWidth: 视口宽 - 2×8)(视口宽取自 MediaQuery,取不到则不设限),使测量帧与定位后的约束一致。修复 DropDownButton 两条既有测试(opens menu / closes after selecting an item)与宿主「导出向导」底部三个下拉。

  • 修复 DataGridView 在 rowCount == 0(仅表头)时的越界行号:拖拽多选经 Listener 命中空白数据区时,_rowAtY 原会返回 rowCount - 1(即 -1),使宿主收到 (-1, col) 这类不存在的单元格。现在 rowCount <= 0 时直接返回 null,空白区不再产生任何选中回调。宿主可放心用「rowCount: 0 + 只有表头」表示空结果集(如 db_lite 查询页 0 行结果、表数据页空表)。

  • Empty(overlay) 新增 maxWidth 参数:把内容列限制在给定宽度内,长文本(例如数据库返回的错误原文)在该宽度内换行并保持居中,action 按钮紧随其下。此前宿主若用「Row(mainAxisSize.min) + Flexible(Text) + 按钮」手绘居中提示,Flexible 会把整行撑到容器全宽——文字被挤成一行省略号、按钮贴到容器最右缘甚至被裁掉。默认 null 不限制,既有调用行为不变。

  • 修复 TabControl 页面面板拿到无界高度导致整帧布局中断:自 Flutter 3.47 起,竖向 Column 的非 flex 子项不再被夹到剩余空间,而是拿到 maxHeight = infinity(旧版本在有界时夹逼到剩余高度)。标签页内容只要要求显式高度就必然在 performLayout 断言——例如放 re_editor 代码编辑器的页签会抛 CodeLineNumber should have an explicit height;断言中断布局后渲染树半残,之后每次鼠标移动都命中未布局的盒子,MouseTracker 的 _debugDuringDeviceUpdate 因异常跳出而永久置位 → 控制台无限刷屏 !_debugDuringDeviceUpdate + RenderBox was not laid out,界面表现为彻底卡死。现将页面面板包进 Flexible(fit: FlexFit.loose):控件自身高度有界时面板填满剩余高度(即 WinForms DisplayRectangle 语义,与 3.47 之前的观感一致,页面底色/边框不再塌陷),置于 DialogBox 的 IntrinsicHeight、滚动容器等无界场景时仍按内容自适应且不触发 flex 断言。回归测试见 test/tab_control_body_test.dart。

  • DataGridView 表头新增拖拽排序:onHeaderSort(按住列头标题横向拖动、松手即按该列排序,向右=升序、向左=降序)、sortColumn / sortAscending(在当前排序列标题右侧渲染 accent 色 ▲/▼ 箭头)。判定用「按下点 → 松开点」的横向总距离,不与起手阈值叠加,不足 8px 视为按住抖动不触发。拖动过程中箭头实时预示松手后将应用的方向;标题区光标为 click、列头右缘内侧 8px 为 resizeColumn(沿用 columnWidths / onColumnResize 改列宽),两者互不干扰。零动画、无 Material 水波纹。

  • DataGridView 表头两种拖拽(拖标题排序 / 拖边框改列宽)改由 Listener 直接跟指针结算,不再依赖 GestureDetector 的拖拽回调。原因:真机上「按住列头左右拖」没有任何反应,而同样的操作在 widget 测试里(斜拖、起手先纵向抖一下、拖出整个网格、按下停顿 300ms、1px 慢拖 60 步)全部能结算——差异只可能出在手势竞技场的归属上。Listener 的命中路径在 pointer down 时缓存,整段拖动都收得到事件,与谁赢竞技场无关。每个拖拽区仍保留一层只注册空 onHorizontalDragStart 的 GestureDetector,唯一作用是占住竞技场,使拖列头不会连带外层横向 SingleChildScrollView 一起滚。顺带把改列宽从「逐帧 delta.dx 累加」换成「按下时列宽 + 按下点起算的总位移」,事件被合并 / 丢弃时宽度不再漂移;预示箭头改为位移达到阈值时才出现,且仅在预示状态真的变化时 setState。

  • 修复 DataGridView 列宽拖拽命中区过小:resize 手柄原先用 Positioned(right: -3) + 6px 让手柄探出列头单元格右缘,但 RenderBox.hitTest 要求触点先落在父盒子尺寸内,探出的半边永远点不到——实测只有紧贴边框内侧约 2px 能拖动。现改为贴右缘内侧 right: 0 + 8px,整条命中区都可点。

  • 修复 ToolStrip 在窄面板 / trailing 展开时 RenderFlex overflowed ... on the right(如 db_lite 对象面板把中间栏拖窄,工具栏按钮 + 右侧 ExpandableSearch 总宽超出容器):左侧按钮组原与右锚 trailing 同处一个不换行 Row,靠 Spacer 撑开,空间不足即溢出被裁。现将左侧按钮组放进 Flexible(child: 横向 SingleChildScrollView)——trailing 仍保持自然宽度钉在右缘、按钮组撑满剩余空间(视觉上与旧的 Spacer 完全一致),空间不够时按钮组横向滚动而非溢出;滚动区用 ScrollConfiguration(...copyWith(scrollbars: false)) 隐藏桌面滚动条,外观不变。

  • 新增 Splitter(containers):独立的可拖动分隔条(WinForm Splitter 对应物)。与自带比例状态、只管两栏的 SplitContainer 不同,它只上报沿分割轴的像素增量(onDrag)配合 onDragStart / onDragEnd,由宿主决定改哪一栏、改多少,因此可直接用于三栏外壳、停靠面板等宽度由外部状态掌控的布局。默认 5px 宽的命中区内居中画 1px 发丝线,静止用 borderColor、hover / 拖动时用 primaryColor,光标随方向为 resizeLeftRight / resizeUpDown;零动画、无 Material 水波纹,取色链 tokens ?? TokenScope.maybeOf(context) ?? DesktopTokens.winForm。

  • Splitter 新增两个正交的外观开关(默认 true,既有调用外观不变):showHairline 管静止态是否画 1px 发丝线,false 供「面板贴合」布局使用——分隔条不再插进 Row / Column 里占掉 5px 布局宽度,而是由宿主以浮层(Positioned)压在两栏拼缝上且不画线,拼缝既不会被看成间隙,也不会让中间面板两侧多出一条像边框的线;showHoverHighlight 管悬浮 / 拖动时是否换成 primaryColor 高亮,false 时发丝线保持静止色(showHairline: true)或任何状态都不着色(showHairline: false),并且不注册鼠标进出回调 → 悬停零重建。手柄始终保留 resizeLeftRight / resizeUpDown 光标与完整命中区,照样能拖。回归测试见 test/splitter_test.dart(四种组合各一条)。

  • 新增 StepBar(misc):向导式横向步骤条(编号圆标 + 步骤标题 + 连接短线),三态渲染(已完成=描边、当前=accent 实心、未到达=灰化),供导入 / 导出向导一类多页对话框标示当前进度;纯展示组件,翻页仍由宿主对话框按钮控制。零动画、无 Material 水波纹,取色链 tokens ?? TokenScope.maybeOf(context) ?? DesktopTokens.winForm。

  • ProgressBar 新增 barColor(misc):覆盖进度条前景色。用于长任务对话框需要按结果着色的场景(如导出向导完成时整条转成功绿、失败转红),缺省 null 时仍取 DesktopTokens.primaryColor,既有调用外观不变。色值由宿主作为构造参数传入,控件本身仍不硬编码任何颜色,marquee 模式同样生效。

  • 新增 PageNavigator(data):输入跳页型分页器——首页 / 上一页 / 页码输入框 / 下一页 / 尾页 + 可选「共 N 页」标签,仅一个输入框输入页码回车跳转,无页码按钮阵列;输入框自动过滤非数字字符,非法输入回弹当前页。页码输入框的垂直 padding 沿用 Input 默认居中算法((controlHeight - fontSize)/2),避免 isDense 下 textAlignVertical 失效导致文字贴顶。pageCount 可为 null(总页数未知,按需 COUNT 模式):「共 N 页」显示为「共 ? 页」,下一页/尾页保持可点,尾页按钮改触发 onGoLast 回调(由调用方执行 COUNT 后跳转)。与页码阵列型 Pagination 并存。

  • Input 新增 textAlign 参数:文本对齐方式透传给文本域(如页码输入框居中显示),默认 TextAlign.start 保持原行为。

  • 移除重复组件 Item(common)与 ListBox(lists):两者分别是 ListItem / WinListView 的功能子集,一并删除。

    • Item → ListItem:DropDownButton.items 公共类型改为 List<ListItem>(选中仍按下即触发,菜单关合逻辑不变);Item 的 text 参数对应 ListItem.title,示例页 / quick_overview / 测试同步迁移;键盘激活回归测试改直接测 Surface。
    • ListBox → WinListView:list 模式参数完全一致,WinListView 额外提供 details/icon 模式、builder 模式、onItemActivated 双击激活与零延迟选中;删除 list_box_page.dart 示例页及其 main.dart / smoke_test 注册与三语 l10n 键;CheckedListBox 文档不再引用 ListBox。
  • 修复 FieldRow 在 debug 下崩溃 / 示例页空白:Row 对非 flex 子项(非 stretch 对齐)不约束最大宽度,直接放 Input(TextField) 会触发 "InputDecorator cannot have an unbounded width" 断言。FieldRow 现将 child 包进松约束 Flexible,子项获得有界最大宽度且不被强制拉伸——固定宽度写法(如 SizedBox(width: 280, child: Input(...)))保持原布局。

  • 修复 InlineEditor 进入编辑时全选文本:桌面平台(Win/Linux/macOS)TextField.selectAllOnFocus 默认 true,聚焦即全选,预设 collapsed 选区挡不住;Input 新增 selectAllOnFocus 参数透传(默认 null 跟随平台),InlineEditor 显式传 false 并保留 controller 预设末尾光标,首次单击进入编辑时光标直接置于内容末尾,再次点击编辑器内文本可将光标定位到点击位置。

  • TabControl 可关闭标签(TabItem.onClose)的关闭按钮固定到标签最右缘:悬停时出现在右缘(不再跟在文字后面),图标+文字改为左对齐,Expanded 文字吸收宽度变化,按钮出现/消失时文字位置不跳动;非可关闭标签保持原有居中布局。

  • Input 新增 obscureToggle 参数:配合 obscureText 时在输入框右缘渲染自绘眼睛按钮,点击在掩码点与明文之间切换(密码可见性);hover / pressed 由 hoverOverlayColor / pressedOverlayColor 基于控件底色派生(明暗自适应),无 Material 水波纹与点击动画,点击不抢占输入框焦点;外部关闭 obscureText 时自动重置切换状态。

  • TabControl 重绘为经典 WinForms 样式:控件色(control)标签条 + 底部发丝线;选中标签用 surface 底色、比未选中高 2px 且下探 1px 压住发丝线,与下方带边框的页面面板无缝连成一体(面板不画顶边,顶边由标签条底线 + 选中标签覆盖);未选中标签融入条底色,hover 由条底色派生(明暗自适应)。标签外形改自绘 _TabChrome(圆角顶 + 三边描边),文本恢复常规字重,移除 accent 下划线。移除 showUnderline 参数(WinForms 无下划线语义);纯标签条场景(所有 TabItem.child 为 null)不再渲染页面面板与底线,仅保留标签条。

  • 修复 ComboBox 嵌入 DialogBox 时崩溃:内部 LayoutBuilder 与 DialogBox 的 IntrinsicHeight 冲突("LayoutBuilder does not support returning intrinsic dimensions",如 db_lite 新建连接 SQL Server 表单)。改为 GlobalKey 按需测量实际渲染宽度(下拉面板只在布局完成后才会打开,测量安全),顺带修复无界宽度约束下弹层宽度变为无穷大的隐患。

  • 新增 ToolbarButton(menus):独立可用的工具栏按钮(图标 + 文本 / 仅图标),自绘 hover / pressed / 禁用态,支持 iconColor 功能强调色、showCaret 下拉箭头、outlined 边框触发器样式、textMaxWidth 窄条省略,无 Material 水波纹与点击动画。区别于数据模型 ToolStripButton,可挂在任意布局中。

  • IconBtn 重写为自绘实现(不再委托 Button):新增 child(任意内容,如 CustomPaint 图标)、selected / selectedColor(accent 淡底选中态)、outline(边框)、size(固定命中区)参数,保留原 API 兼容;含 Focus + Enter/Space 键盘激活。

  • 新增 ListItem(lists):高密度列表行(前置图标 + 标题 + 尾随),selectedColor 支持浅底选中(文字保持前景色,树形场景),选中由 Listener.onPointerDown 零延迟触发,双击单独挂 GestureDetector。

  • 新增 SelectableCard(common):可选卡片(内容 + 选中淡底 + 右上对勾圆标),禁用时整体降透明并显示 disabledLabel 角标,PointerDown 选中 + 双击动作。

  • 新增 ExpandableSearch(form):可展开搜索框(收起为放大镜按钮 → 展开输入框),失焦且内容为空自动收起。

  • 新增 InlineEditor(form):单元格内联编辑器(自动聚焦,Enter / 失焦提交,Esc 取消,防双触发);新增 onChanged 回调,每次文本变化时触发(可用于实时标记 dirty)。

  • TabControl 增强:TabItem 新增 onClose(悬浮显示关闭按钮)/ width(固定宽度)/ contextMenuItems(逐标签右键菜单);TabControl 新增 tabBarColor / selectedTabColor / hoverTabColor / showUnderline(可关) / barHeight / tabWidth / scrollStep,标签溢出时两侧滚动箭头,选中下划线去掉 AnimatedContainer 动画。

  • DataGridView 增强:新增 showRowNumbers / rowNumberWidth / rowNumberBuilder(行号列,按下选中整行)、selectedCell / onCellSelected / onCellTap / onCellDoubleTap / onCellContext(单元格选中 / 单击 / 双击 / 右键,选中与单击由 Listener.onPointerDown 零延迟触发)、headerColor / gridLineColor / selectedTextColor / cellPaddingX / headerFontSize / rowHoverColor(行 hover 自持,避免整页重建)。

  • ListItem 新增 borderRadius 参数(默认 cornerRadius 圆角,可传 BorderRadius.zero 用于高密度直角列表 / 对象面板)。

  • TabControl 新增 contentPadding 参数(可关掉默认 8px 内容内边距,适配纯标签条场景,如 db_lite 对象视图标签栏)。

  • SelectableCard 覆盖层(选中淡底 / 对勾圆标 / 禁用角标)由 Stack 改为 CustomPaint 自绘:Stack 在无界约束下无法布局(如 DialogBox 的 IntrinsicHeight 尺寸计算会崩溃),自绘让组件在任意约束下正常渲染,且不引入额外渲染层级。

  • Textarea 新增 expands(填满可用空间,用于代码编辑器)、style(覆盖文本样式,如 monospace 字体)与 showBorder(关闭边框,供嵌入面板的编辑器使用)参数;expands: true 时自动置空 minLines / maxLines 并透传 TextField.expands。

  • ComboBox 可编辑(editable)模式下拉面板移除 Material(elevation) 阴影与 InkWell 水波纹:改为纯 Container 边框面板 + Listener.onPointerDown 按下即选中 + MouseRegion hover 高亮(与只读模式下拉一致),消除阴影 shader 编译与墨水动画开销。

  • 新增 DialogBox:通用对话框外壳(标题栏+正文+可选 footer),承载自定义内容的模态窗口;标题栏用 surfaceColor 底色 + IconBtn 关闭按钮,正文用窗口底色,扁平 WinForm 风格(无外边框、无 Material 阴影),自带 DefaultTextStyle 干净基线。命名避开 Flutter Material 的同名 Dialog 冲突。配合 showDialog 使用,模态行为(遮罩/Esc/返回值)仍由调用方掌控。

  • ToolStripButton / ToolStripDropDownButton 新增可选 iconColor 参数,支持为工具条按钮图标指定语义强调色(如新建=绿、删除=红),默认仍使用 DesktopTokens.foregroundColor。

  • ToolStrip 下拉面板移除 Material(elevation) 与冗余双重边框,改为纯 Container 扁平 WinForm 风格,避免首次展开阴影 shader 编译延迟。

  • ToolStripDropDownButton 支持分离式(split)按钮:新增可选 onPressed,赋值时按钮主体(图标+文字)点击触发 onPressed,右侧独立箭头点击才打开下拉菜单,主体与箭头之间用细分隔线隔开;不赋值时行为与旧版一致(整钮打开下拉)。

  • ToolStripButton / ToolStripDropDownButton 按钮体优化:内容容器由「仅水平 compactSpacing 且无固定高度」改为撑满 controlHeight 高度(垂直居中)并水平方向给到 compactSpacing * 2 内边距,hover/按下高亮带不再贴着文字、图标文字不再紧贴,整条观感更舒展。split 模式的下拉箭头容器同步撑满 controlHeight。

  • 修复 ToolStrip 下拉菜单项文本继承应用级 DefaultTextStyle 的 decoration: double/yellow + fontWeight: bold 样式(去掉 Material 兜底后触发):_ToolStripDropDownEntryWidget 的文本显式声明 decoration: TextDecoration.none + fontWeight: FontWeight.w400,消除菜单项黄色双下划线与加粗。

  • 优化 ToolStripDropDownButton 分离式(split)按钮的渲染:原先主体与下拉箭头是两颗独立 pill(各自 hover 背景 + 圆角),悬浮时整体观感"变宽"且中间分割线被同色 hover 底色淹没而不可见。现改为整颗做成"统一的一颗按钮"——悬浮时整体一个 hover 背景,主体与箭头之间用一条常驻 1px 占位(非悬浮时为透明)、仅悬浮时才着色的细分隔线隔开,既消除悬浮变宽、又让分割线在统一底色上清晰可见。

  • 修复 split 按钮分割线在明亮主题下不可见:分割线颜色由固定 borderColor(亮色下与 hover 底色几乎同色)改为基于 hover 底色 Color.alphaBlend 的明暗自适应(暗底提亮叠白、亮底加深叠黑),符合项目"hover/选中色必须明暗自适应"规范,两套主题下均可见。

  • CheckRow 新增 trailing 参数:行尾可渲染任意 widget(如状态标注),便于在选项列表中标示不可用/未实现的条目。

  • ContextMenuStrip 新增静态入口 showContextMenu(context, items, position):无需包裹子树,可在右键时刻动态构建菜单内容后直接弹出(如表格单元格右键菜单,命中哪格决定了菜单作用于哪格)。同时菜单弹出位置增加屏幕边界夹取,右键在屏幕右/下缘时面板自动收回屏幕内,不再溢出不可见。

  • ComboBox 只读模式下拉重写:原实现基于 Flutter DropdownButton,弹出带 Material 淡入/滑动动画,不符合传统桌面习惯。现改为自绘 WinForm 风格即时展开下拉列表:Listener.onPointerDown 触发、OverlayEntry + CompositedTransformFollower 定位、无动画即时显示、hover 高亮、选中项主色填充、点击外部或选项后即时关闭。

  • ToolStrip 增强:新增 trailing(右侧任意 widget,如 Pagination)与 trailingItems(右侧条目)支持左右分区布局;新增 borderOnTop(分隔线画在顶部,适配底部停靠)与 openUpward(下拉面板向上弹出,适配底部工具栏,并夹取面板位置避免溢出屏幕右缘)。ToolStripDropDownButton.text 改为可选,支持纯图标下拉按钮(隐藏下拉箭头)。

  • Pagination 尺寸调整:页码/箭头按钮边长由 controlHeight * 1.2 改为 controlHeight,可直接嵌入 ToolStrip 等紧凑容器不溢出。

  • ContextMenuStrip / MenuStrip 关闭遮罩修复:遮罩原为 GestureDetector(translucent, onTap, ColoredBox),但 ColoredBox 的渲染对象是 opaque 命中,遮罩子树命中测试返回 true 后 Stack 即停止向下探测——底部控件完全收不到事件,菜单打开时第一次点击只被用来关菜单(浪费一次点击,右键换菜单同样被吃掉)。现改为无子节点的半透明 Listener + onPointerDown:命中测试返回 false(事件穿透到底部控件),但自身仍在命中列表中(按下瞬间即关菜单)——同一次点击既关菜单又落在下方控件上,与原生桌面行为一致。

  • ContextMenuStrip 弹出位置修复:PointerEvent.position 本身就是全局坐标,旧代码又对它做了一次 box.localToGlobal() 转换,把触发控件自身的窗口偏移重复叠加,导致菜单向右下偏移。现直接传入 event.position,菜单精确出现在光标处。

  • ListView 行选中延迟修复:onTap 与 onDoubleTap 同注册会让单击被双击判定窗口 hold 约 300ms。选中改为 Listener.onPointerDown(按下瞬间触发、零延迟),双击激活单独由 GestureDetector.onDoubleTap 处理。

  • MenuStrip 显式关闭菜单项文字下划线并恢复常规字重:之前为优化首屏速度把下拉面板的 Material 替换为 Container,但 Text 不再有 Material 的 DefaultTextStyle 兜底,会继承应用级某个带 decoration: underline / TextDecorationStyle.double / color: yellow 且 fontWeight: bold 的样式,导致下拉菜单项文字下方出现两条黄线、字体加粗。已在 _MenuTopItem / _MenuDropDownItem 的 Text 显式 decoration: TextDecoration.none + fontWeight: FontWeight.w400 覆盖。

  • MenuStrip 顶层菜单项高亮修复:行内 crossAxisAlignment 改为 stretch,hover/打开态背景填满整行高度(此前只包住文字形成一条窄横带,视觉上像菜单项上的"横线")。

  • MenuStrip 下拉面板性能优化:弃用 Material(elevation)(阴影首次计算 / shader 编译是"首次展开慢、之后快"的主因)与冗余的 CompositedTransformTarget,改纯 Container(扁平 WinForm 风格),首次展开更跟手。

  • 新增 FieldRow:横向表单行(左 label 右对齐固定宽 + 右侧控件),经典桌面(WinForms)表单布局;label 缺省时渲染同宽占位保持对齐。

  • 新增 IconBtn:轻量无边框图标按钮(工具栏/标题栏),悬停 ghost 高亮,可选 tooltip。命名避开 Flutter Material 的同名 IconButton 冲突。

  • Input 新增 obscureText 参数,支持密码框。

  • CheckBox 重写:弃用 Flutter Checkbox(自带勾选动画、无法关闭),改为自绘方框 + 勾号,勾选状态瞬间切换、无动画(对齐 WinForms 快节奏手感)。API 不变,保留 label 点击切换、Focus/键盘(Enter/Space)切换与 disabled 视觉。

  • Button 重写聚焦行为:弃用 TextButton(其 InkWell.canRequestFocus 会在按下瞬间请求焦点,导致长按/按住移走鼠标也显示焦点边框),改为 GestureDetector + MouseRegion + Focus 手绘实现——按下只显示 pressed 视觉,完整点击(松开)才 requestFocus() 显示焦点边框,长按移走(tap 取消)不聚焦;Tab 导航聚焦正常,焦点在按钮上按 Enter/Space 可激活。视觉逻辑(hover/pressed/disabled/ghost)与 token 取色全部保留。

  • DesktopTokens 默认(WinForm)控件密度调整:controlHeight 24→28、fontSize 12→13、controlPaddingX 8→12,使按钮/输入框/复选框等统一变大,更贴合桌面应用的舒适点击尺寸。

  • MenuStrip 悬停行为修正:bar 级 Listener 现在仅在已有菜单打开时才随悬停切换顶层菜单(_onBarHover 在 _openIndex == -1 时直接返回)。即 WinForm 经典行为——必须先点击打开菜单,之后悬停才切换;未打开任何菜单时,单纯悬停不会自动展开。单项的 MouseRegion 仅保留悬停高亮,点击仍由 GestureDetector.onTap 开关。

  • MenuStrip 悬停展开改为 bar 级 Listener 驱动:原先依赖每个顶层项的 MouseRegion.onEnter 来悬停打开/切换,但该回调在"尚未打开过任何菜单"的首次悬停时可能不触发(默认 deferToChild 命中问题),表现为悬停不展开。现改为在菜单栏包裹一层 Listener(behavior: HitTestBehavior.opaque, onPointerHover),按指针全局 x 坐标命中对应顶层项并打开,首次悬停与已展开后切换都稳定生效;单项的 MouseRegion 仅保留悬停高亮。

  • MenuStrip 修复:下拉遮罩(_MenuDropDown 的 dismiss scrim)原本为全屏 Positioned.fill, 会拦截覆盖在菜单栏顶部区域的指针事件,导致"菜单展开后悬停其它顶层菜单不会自动切换"的行为失效。 现改为从菜单栏底边(position.dy)开始向下覆盖,顶部菜单栏区域保持裸露, 悬停切换恢复正常工作(点击空白处关闭的行为不受影响)。

  • Button 增强:新增 [ButtonVariant](solid 默认 / ghost 无边框),并将内容参数化—— 新增 child(Widget?)以支持任意内容(如图标 + 文字列),text 变为可选语义标签。 ghost 变体使用透明背景,悬停 / 按下态以 hoverOverlayColor / pressedOverlayColor 混合 controlColor,适合工具栏 / ribbon 的无边框按钮组。

0.5.0

  • 以 shadcn/ui 组件清单为参考,原生补充 43 个缺失组件(不做 shadcn 风格化集合, 沿用 headless + DesktopTokens 架构;命名用 WinForm 语义名 / 裸名)。
  • 新增 DesktopTokens.shadcn 现代预设,并扩展语义色 token: muted/secondary/accent/destructive/card/popover/ring/barrier、圆角刻度、 阴影与图表色板(TokenColor 扩展提供 hover/pressed/disabled 派生色)。
  • 新增浮层基础设施:OverlayController、AnchoredOverlay、ModalOverlay、 FocusTrap(锚定定位 / 模态遮罩 / 焦点圈闭),以及 Surface 交互表面基元。
  • 新增通用补充组件:TypeStyle、Kbd、Separator、Tag、Field、Item、 Marker、ButtonGroup、InputGroup、Textarea、Toggle、ToggleGroup、 ToggleSwitch、InputOtp。
  • 新增容器组件:GroupBox(Card)、TabControl(Tabs)、SplitContainer (Resizable)、Accordion、Collapsible、Sheet、SidePanel(Drawer)、 Sidebar、Carousel。
  • 新增浮层组件:Popover、HoverCard、DropDownButton(DropdownMenu)、 MessageBox(Dialog / AlertDialog,含 MessageBox.show 与 WinForm 按钮组合)、 Command、Toast/ToastHost、Direction、Empty。
  • 新增数据与杂项组件:Chart(柱/折线/环图,无第三方依赖)、Pagination、 Alert、Attachment、Avatar、Breadcrumb、Bubble、Message、 MessageScroller、Questionnaire、Skeleton、Spinner。
  • 组件画廊新增 Supplements / Containers / Overlay 分类与 43 个演示页。
  • 更新 components.md 第八节(shadcn 参考映射:新增 43 / 已覆盖 21)。

0.1.0

  • Initial scaffold: DesktopTokens with a WinForm-style default preset.
  • Added TokenScope for app-level token theming.
  • Added WinForm-style Button, Input, and Label widgets.
  • Added CheckBox — WinForm-style check box with label support.
  • Added RadioButton<T> — WinForm-style radio button with mutual exclusion group.
  • Added ComboBox<T> — WinForm-style drop-down combo box (editable / read-only).
  • Added ListBox<T> — WinForm-style list box with single / multi-select.
  • Added WinListView<T> — WinForm-style list view with Details / icon / multi-select modes.
  • Added TreeView<T> — WinForm-style tree view with expand / collapse / select.
  • Added NumericUpDown — WinForm-style numeric up/down control.
  • Added DateTimePicker — WinForm-style date / time picker.
  • Added ProgressBar — WinForm-style progress bar (determinate / marquee).
  • Added MenuStrip — WinForm-style main menu bar with drop-down sub-menus.
  • Added ContextMenuStrip — WinForm-style right-click context menu (reuses MenuModel).
  • Added ToolStrip — WinForm-style toolbar (buttons / separators / labels / drop-downs).
  • Added StatusStrip — WinForm-style status bar with panels.
  • Added Control — headless control base class (focus / disabled / semantics contract).
  • Added ControlSemantics — accessibility wrapper for custom controls.
  • Added DataGridView — WinForm-style data grid with virtual scrolling & CellDirtyTracker.
  • Added ScrollBar / StandaloneScrollBar — WinForm-style scroll bars (H/V).
  • Added TrackBar — WinForm-style track bar / slider.
  • Added ScrollableControl — headless scrollable container.
  • Added LinkLabel — WinForm-style hyperlink label.
  • Added MaskedTextBox — WinForm-style masked text input.
  • Added RichTextBox — WinForm-style multi-line text editor.
  • Added MonthCalendar — WinForm-style month calendar.
  • Added CheckedListBox<T> — WinForm-style checked list box.
  • Added DomainUpDown<T> — WinForm-style domain up/down.
  • Added PropertyGrid — WinForm-style property grid with categories.
  • Added ColorDialog — WinForm-style colour picker dialog.
  • Added BindingNavigator — WinForm-style data binding navigator.
  • Added WinToolTip — WinForm-style tool tip.
  • Added ErrorProvider — WinForm-style form validation indicator.
  • Added RovingTabindex — declarative keyboard focus state machine.
  • Added ResponsiveTokenScope — media-query-aware token switching.