arco_design 0.1.0
arco_design: ^0.1.0 copied to clipboard
Arco Design for Flutter — a faithful port of arco-design v2.66.16 design tokens, theme system and component set.
Unreleased #
Menu 带箭头行文字偏上 ~10px 修复(2026-09-19) #
- 修复「箭头没有与文字垂直对齐」(用户复检截图:水平菜单浮层「媒体库」
行箭头明显低于文字)。上一轮把箭头改为
Stack+Positioned后引入新问题:Stack对非Positioned子项给的是松约束,Padding(Row)收缩到文字 自然行盒(Web 思源宋体 ~20px)并贴顶,文字中心落在行内 10px 处; 而箭头走Positioned(top: 0, bottom: 0)占满 40px 行高居中——两者相差 ~10px。修法:内容层包Positioned.fill吃满 tight 高度,Row 才能在 40px 行内交叉轴居中。影响面:所有垂直带箭头行(浮层子菜单行、pop 顶层 子菜单头、内联子菜单头部)。 - Web 截图像素量测复核:「媒体库」文字墨迹中心与箭头墨迹中心同为 y≈376 (差 0.5px);箭头墨迹 5×10(官方同款),右缘距浮层右缘 ~25px(官方 ~24)。
- 回归用例:「浮层:子菜单项箭头右缘距行右缘 12」新增两条断言 —— 文字中心与行中心对齐、箭头中心与行中心对齐(回滚修复即红,已验证 判别力)。
Menu 菜单项右侧箭头位置与浮层宽度对齐官方(2026-09-19) #
- 修复「item 右侧图标与右侧边距太大」(用户反馈截图:水平菜单「内容管理」
浮层里的「媒体库」行被截成「媒…」、箭头离浮层右缘很远)。官方垂直菜单里
带子菜单的行是
padding-right: 28px+ 箭头绝对定位 (.arco-menu-vertical .arco-menu-icon-suffix { position: absolute; right: 12px; top: 50% }),箭头压在右侧留白里、不参与行内布局。 本库初版把箭头当 Row 的兄弟节点、用Spacer顶到右侧——Expanded(文字) 与Spacer同为flex: 1,把剩余空间对半分,于是同时错两处: ① 文字可用宽度只剩 28px(应为行宽 − 40),「媒体库」被截成 1 字 + 省略号; ② 箭头墨迹右缘离浮层右缘 32px(官方 24px)。现改为Stack+Positioned(right: 12)叠加,等价 CSS 绝对定位。 - 菜单图标尺寸统一为官方
1em:.arco-icon { width: 1em; height: 1em }, 菜单字号 14px → 所有图标 14×14(前置图标曾写 16、子菜单箭头曾写 12)。 - 浮层宽度改为官方盒模型:
12(左) + [图标 14 + 间距 16] + 文字 + 12/28(右), 去掉旧公式的+ 60、+ 20 × 层级与 100px 下限;量测改用实渲染样式 (含环境DefaultTextStyle继承的letterSpacing)并跟随选中行weight500,避免量窄导致截断。官方对照:3 项浮层(文章/评论/媒体库) 盒宽 98(修复前 124)、嵌套浮层(图片/视频)68。 - 折叠态:官方
.arco-menu-collapse .arco-menu-icon-suffix { display: none }→ 不再渲染箭头;折叠行内边距改为左右对称 13(官方图标margin-left: 1px后正好居中于 40px 方格内,原先右侧 28px 会把居中图标顶偏 14px)。 - 回归用例:
test/menu_test.dart新增 2 项 ——「浮层:子菜单项箭头右缘距 行右缘 12、不挤占文字宽度」(含didExceedMaxLines == false与 浮层宽度 = 文字 + 40)、「菜单图标一律官方 1em(14px)」。
Menu 菜单项文字垂直居中修复(2026-09-19) #
- 修复浮层/行内菜单项文字整体下沉 ~6px(用户反馈「menu 文字垂直居中」,
浮层子菜单里表现为图标居中、文字明显偏低):菜单标签曾写
height: 40 / 14想表达官方line-height: 40px(水平 30px),但 Flutter 的height倍率是直接缩放字体的 ascent/descent(探针实测: Ahem 下 40px 行盒基线 = 30 = 0.75×40),基线落在 ascent 占比处; 思源宋体 hhea ascent 占比 ~78%,文字遂沉到行底。CSS 的line-height则是定高行盒 + 自然字形半行距居中。现改为不写 height:文字取自然 行盒,由定高lineHeight的行容器经 Row 交叉轴居中,才是等价实现。 注意TextLeadingDistribution.even对此无效(该倍率下行盒内没有 多余 leading 可分配),实测 Web 截图逐字节不变。 - 回归用例:行盒契约(文字盒 < 30、与行容器中心对齐、行容器 tight 40/30)、 pop 浮层内行几何(打开浮层后断言文字盒高度与中心对齐)。
Table 树形/展开列修复 + checkStrictly 默认值对齐(2026-09-19) #
- 展开图标补上官方「14×14 圆角灰底按钮」(用户反馈「树形的颜色有差异」):
树形首列
+/-与展开列caret原先只画裸图标,缺.arco-table-cell-expand-icon button/.arco-table-expand-icon-cell button的14×14+border-radius: 2px+background-color: neutral-3+color: text-2,以及:hover → neutral-4 / text-1。现抽出共用的_ExpandButton供两处复用(树形minus/plus、展开列caret-down/caret-right)。 - 修复展开列按钮被压窄:展开列
width: 40px,单元格若沿用 16px 横向 内边距,Flutter 会把 14px 按钮压成 8×14(CSS 里按钮溢出内容盒后 由text-align: center居中,不受影响)。该列改用横向零内边距 (_expandCellPadding),视觉与官方一致。 ArcoTableRowSelection.checkStrictly默认值改为true(严格): 对齐官方 README(|checkStrictly|…|boolean|true|)与hooks/useRowSelection.tsx(typeof checkStrictly === 'boolean' ? !checkStrictly : false,未传即严格)。此前默认false(父子联动) 与官方相反,依赖「不传即联动」的调用方需显式传checkStrictly: false。- 示例「Table 树形数据展示」分区:
checkStrictly标签可点、新增模式实时 回显(严格 / 联动),并在描述中写明「开关只作用于之后的勾选动作、表格 画面本身不会变化」,避免「checkStrictly 没有作用」的误判。 - 回归用例:
test/table_test.dart新增 3 项(树形展开图标 / 展开列 caret 的 14×14 灰底按钮,以及「未传 checkStrictly = 官方严格」)。
图标字体化与界面字体(2026-09-19) #
ArcoIcon改为官方图标字体渲染:由自绘CustomPainter路径改为把字形 当字符交给Text渲染(与 Web 端::before+ 图标字体的做法同构)。 字体为lib/assets/arco_design_icons.ttf(familyArcoDesignIcons, 257 个图标,码点 U+E800–U+E900 连续,upem 1000 / ascender 850 / descender 150,自然行高恰为 1.0em;实测tool/inspect_font.py)。 行高显式写死1.0、外层SizedBox.square锁尺寸,避免 Web 端 fallback 字体度量撑高行盒导致图标错位。ArcoIcons常量表改为从字体 cmap 生成 (tool/gen_icon_font.py,标记区段原地替换):257 个常量、byName注册表、all列表。既有 48 个公开标识符与仓库内 284 处引用 全部保持不变;生成器内置「既有公开名一个都不能丢」的校验。ArcoIconData字段调整:name改为官方 kebab-case 名(与官方IconXxx组件一一对应),新增identifier(驼峰常量名)与codePoint;draw回调移除。新增ArcoIconFont(family/package/resolvedFamily)描述字体元信息。- 图标字体在库自身
pubspec.yaml声明,宿主应用无需另行声明。 - 界面正文字体可整体替换:
ArcoTheme.light/dark与ArcoThemeData新增fontFamily/fontFamilyFallback。库内 33 个组件文件共 76 处 硬编码的ArcoTypography.fontFamily全部改为读主题 (context.arco.fontFamily),因此浮层内重建的完整文本基线也会同步换字体 —— 这是此前「组件绕过主题直接写死字体」导致换字体不生效的根因。 - 示例应用在
example/pubspec.yaml声明正文字体并注入主题 (ArcoTheme.light/dark(fontFamily:));图标浏览页改为展示全部 257 个图标(显示官方名、点击复制ArcoIcons.<驼峰名>)。 字体先声明为Microsoft YaHei Mono(MSYHMONO.ttf,28953 个码点), 随后整体替换为思源宋体 CN(SourceHanSerifCN-*.otf共 7 个字重, CFF 轮廓,各 3 万余码点)。新字体按 CSS 字重阶梯声明200/300/400/500/600/700/900(字体内部 ExtraLight 的usWeightClass是 250,不直接照抄;见docs/HANDOFF.md坑 12), 并统一到 ASCII 族名Source Han Serif CN(见坑 13)。 实测新字体自然行盒 1.437 em(旧字体 1.171 em), 因库内文本普遍显式带height,三页截图位移判定为 0 px; 定高行盒内的文字基线下移 2.66 px 属字体固有行为(坑 11)。 - 修复换字体引出的标注截断:示例里色块(
DemoSwatch)的名称与十六进制 标注原本按色块宽度写死(56 / 96),只挂了fontFamilyFallback: codeFontFamily。Flutter 的fontFamilyFallback是 逐字形回退,正文字体含数字与#时永不生效,所以标注一直是用正文字体 渲染的——换字体前正文字体恰好是等宽体,问题被掩盖;换成比例字体后同样 7 个字符的#FDCDC5比#A1151E宽近 20%,成片出现#FDCD⋯/secondary-hover→secon…。改为按DefaultTextStyle.of(context).style.merge(标注样式)用TextPainter实测整组最宽的一条、整组共用(色块本体仍定宽,网格仍对齐)。 注意必须用合并后的完整样式去量:Text渲染时会把style合并进环境DefaultTextStyle(Material 的bodyMedium带letterSpacing: 0.25), 漏掉继承字距会让测量比实际窄,照样截断。 - 新增两个验收工具:
tool/shot_shift.py(截图行剖面互相关,判定 「零位移 / 一次性台阶 / 逐行漂移」,--window定位台阶) 与tool/check_glyph_coverage.py(源码非 ASCII 字符 → 字体cmap覆盖率扫描;当前 1078 个字符未覆盖 0 个,防豆腐块)。 - 新增
tool/inspect_font.py:纯标准库的 TTF/OTF cmap / post 解析工具, 是图标码点表的唯一真值来源(--csv可导出逐条核对)。
在本版本中加入 P1(基础通用)、P2(表单域)与 P3(反馈浮层与导航)三个分期的
组件,累计 49 个组件目录 / 460 项测试。所有几何与配色逐条对照官方 2.66.16
编译产物 arco.css 实现,并在注释中标出对应的官方选择器。
Tree 拖拽修复与几何保真(2026-09-19) #
示例应用的 Tree 页与官方 React 版观感差异较大,且拖拽完全无反应。
逐条对照官方 Tree/index.tsx、node.tsx 与编译产物 arco.css 修复:
- 拖拽失效的根因是节点索引的重建语义:官方
needUpdateTreeData只在treeData/ 相关 props 引用变化时重建key2nodeProps,不做深比较。 此前本库按「逐元素深比较」判断相等,于是官方与示例里最常见的写法 ——const data = [...treeData](顶层换新数组)配合嵌套children原地增删,再setTreeData([...data])——会被判成「内容相同」→ 索引不重建 → drop 时_key2node查不到目标节点,表现为「拖了没反应」。现改为 引用比较,并在build()里补一条 O(顶层) 陈旧检测(顶层 keys 变化, 或顶层列表已不是同一实例)兜底。 - 拖拽把手恒占位:官方
.arco-tree-node-drag-icon { color: primary-6; opacity: 0; margin-left: 120px },把手始终在 DOM 中,那 120px 留白始终 参与标题宽度,hover 只把opacity切到 1;blockNode下改为position: absolute; right: 12px(margin-left: unset,不再占留白)。 此前实现「hover 才挂载把手」,会让标题宽度在悬停时跳变。 - 拖拽落点提示线改为 2px +
border-radius: 1px的圆角容器 (官方-title-gap-top/bottom::before),不再是无圆角矩形。 - showLine 的「非末尾叶子」补肘线:官方
.arco-tree-node-is-leaf:not(.arco-tree-node-is-tail) .arco-tree-node-indent::after——叶子没有箭头位,必须自己补一段竖线连到下一个兄弟,否则连接线在叶子处 断开;末尾叶子(is-tail)不补。 - 复选框掩码左缘 → 标题文字实测 24px(官方 checkbox
margin-right: 10px- title
margin-left: -4px; padding-left: 4px;ArcoCheckbox盒内自带 4px hover padding,故 Tree 侧只需 2px 间距)。
- title
- 示例页属性对齐官方
__demo__:basic(defaultExpandedKeys: ['0-0-0']defaultSelectedKeys: ['0-0-0','0-0-1'])、checkboxTree(受控checkedKeys+checkStrictly)、line、blocknode + size、loadmore、drag。 这是观感差异的最大来源:官方getInitExpandedKeys在autoExpandParent(默认 true)且未传expandedKeys时展开全部父节点, 而此前示例只展开一级。
- 示例的拖拽重排改为「返回新树」:
_extract/_insert递归 +_copy逐层复制,不再原地改写children——ArcoTreeNodeData.children默认是 不可变const [],原地push会抛错且不触发重建。 - 测试:包内新增「索引重建(官方 needUpdateTreeData 语义)」2 项与
「官方几何保真」2 项;示例套件按新导航结构重写后 8 项全绿
(原断言仍指向导航重构前的分组名,且侧栏视口外的条目直接
tap打不中, 需先ensureVisible),并新增一项端到端拖拽用例:在示例页上真实拖动 节点,断言重排后的行序与缩进层级。
Table 溢出修复与能力补齐(2026-09-19) #
- 修复窄容器溢出(图一:示例数据展示页两张表格
RenderFlex overflowed by 268 pixels)。根因是官方table-layout: fixed语义未实现:Table/table.tsx在tableLayoutFixed、scroll.x/y、任一列ellipsis三者之一命中时给<table>加.arco-table-layout-fixed, 配合table { min-width: 100%; width: 100%; table-layout: fixed }, 此时表格宽度恒等于容器宽、不被内容撑开(官方 README:「列宽不会被内容 撑开超出 100%」)。本库原先只有「按内容固有宽等比摊满」一种模式,故带ellipsis: true的末列「住址」在窄容器里把表撑爆。现按官方分三档解析列宽 (scroll.x→ 固有宽 + 横向滚动;fixed 语义 → 容器宽并压缩数据列、剩余 均分给弹性列;否则内容等比摊满),新增ArcoTable.tableLayoutFixed显式 开关。示例两张表改用Row+Expanded等分,不再靠SizedBox(360)硬塞。 - 嵌套子表格(图二,官方
__demo__/expand-sub-table):expandedRowRender返回ArcoTable时,子表要贴到外层单元格边—— 官方用.arco-table-expand-content .arco-table-td .arco-table { margin: -9px -16px calc(-9px - 1px) -16px }(按 size:default -9 / middle -7 / small -5 / mini -2)负 margin 实现;Flutter 的Padding不支持负值, 改用等价「左内边距收窄indentSize - 16」,展开区底色--color-fill-1。 示例新增「Table 嵌套子表格」分区。 - 树形数据 +
checkStrictly父子联动(图三,官方__demo__/data-children):新增ArcoTableRowSelection.checkStrictly。 非严格(默认)时勾选级联全部后代(官方getSelectedKeys),并沿祖先链 回算父行「全选 / 半选 / 不选」(官方updateParent);selectedRows按 拍平整棵树(含未展开后代)取交集。严格模式只切自己。派生 UI 状态 (_displaySelectedKeys/_isIndeterminate)实时推导、不另存,避免受控 值与非受控态不同步。示例新增「Table 树形数据展示」分区,配ArcoSwitch实时切换checkStrictly。 - 树形缩进对齐官方
td.tsx:叶子行无图标元素,用paddingLeft += 16 + 4 = 20;节点行用 14px 展开图标 +margin-right: 4。 - 修复「带行选择的树形表格」无缩进、无展开图标(视觉验收时发现):
官方
td.tsx的判据是haveTreeData && column.$$isFirstColumn——首列即columns[0],与它落在哪个分组无关;而本库原先只在 fixed-left 组里判首列,rowSelection的选择列又默认fixed: true、会占住该组,数据首列于是落进 中间滚动组(那里硬编码isTreeFirst: false),导致缩进与展开图标整体不渲染。 抽出_isTreeFirstColumn(cw)后 left / scrollable / right 三组统一判定。 - 测试:包内新增 9 项(
table-layout: fixed窄容器不溢出 3 项、checkStrictly父子联动 3 项、嵌套子表格贴边 2 项、树形首列回归 1 项), 累计 766 项全绿;示例套件删除「只放行 RenderFlex overflowed」白名单, 溢出回归即失败(示例 8 项全绿、build web --release通过)。
数据展示与导航(P3 收尾) #
ArcoList/ArcoListItem/ArcoListItemMeta:dataSource+render或children、header/footer、size(small/default/large)、bordered、split、 hoverable、loading(Spin)、grid(column/span/gutter)、scrollLoading、 noDataElement、onReachBottom、内嵌pagination(内部切片 + 右下分页器)。ArcoPagination:total/current/pageSize(受控 + 默认值)、sizeOptions 与 sizeCanChange、simple、showTotal、showJumper、bufferSize 折叠算法、 disabled/hideOnSinglePage、itemRender 与自定义图标。
修复 #
ArcoSteps箭头模式:右箭头尖(官方::after,z-index:2)此前被 Row 中 后绘制的兄弟块覆盖,改为父级 Stack 最后统一绘制,几何与官方逐像素对齐 (箭头尖压住下一块左侧 32px、仅露 ~4px 背景色细缝);可点击项悬停时 标题与描述变主色(原DefaultTextStyle.merge对显式样式无效)。
基础通用(P1) #
- 布局与排版:
ArcoDivider、ArcoSpace、ArcoRow/ArcoCol、ArcoLayout(含Sider/Header/Content/Footer)、ArcoTitle/ArcoText/ArcoParagraph/ArcoLink。 - 展示类:
ArcoTag、ArcoBadge、ArcoAvatar、ArcoCard、ArcoEmpty、ArcoResult、ArcoSkeleton。 - 反馈类:
ArcoSpin、ArcoProgress、ArcoAlert。 - 展示与导航补充:
ArcoCollapse(手风琴 / 受控 /expandIconPosition/lazyload/destroyOnHide/triggerRegion,200ms 展开动画)、ArcoTimeline(left/right/alternate、pending 幽灵节点、reverse、 标签relative双列布局、虚线连接线)、ArcoSteps(default / arrow / dot / navigation 四型、small、垂直、labelPlacement、lineless、onChange可点击、error + next-error 红线)。 - 基座:自绘矢量图标
ArcoIcon(28 个图标,按官方 48 viewBox SVG 换算)、ArcoConfigProvider。
表单域(P2) #
- 输入类:
ArcoInput/ArcoTextArea(4 尺寸、状态色、前后缀、addon、 字数统计)、ArcoInputNumber、ArcoInputTag(回车成签、tokenSeparators分词、saveOnBlur、maxTagCount折叠)、ArcoAutoComplete(聚焦展开、 按value筛选、命中高亮)、ArcoSelect(单/多选、分组、搜索高亮、allowCreate)、ArcoCascader(多列面板、changeOnSelect)、ArcoDatePicker(月/年面板、disabledDate、今天快捷键)、ArcoTimePicker(时/分/秒三列、确定/此刻)。 - 选择类:
ArcoCheckbox(+Group,含半选)、ArcoRadio(+Group,描边/填充)、ArcoSwitch(circle/round/line)、ArcoSlider(range/刻度/纵向)、ArcoRate(半星/分级/只读)。 - 容器:
ArcoForm/ArcoFormItem(水平/垂直/行内三种布局、必填星标、ArcoFormRule校验规则、ArcoFormController取值/校验/重置/提交)。
反馈、浮层与导航(P3) #
- 浮层基础设施:
ArcoPortal(Overlay 等价 React Portal)、ArcoTrigger(12 方位、视口越界自动翻转、箭头夹取、popupAlign微调)、ArcoOverlayTextBaseline(浮层文本基线,见下)。 - 浮层:
ArcoTooltip、ArcoPopover、ArcoDropdown/ArcoDroplist、ArcoPopconfirm(支持Future型onOk自动 loading)。 - 阻断式反馈:
ArcoModal、ArcoDrawer(四方位)。 - 全局提示:
ArcoMessage、ArcoNotification(四方位堆叠、按对象身份关闭)。 - 导航:
ArcoMenu(vertical内联 /pop浮层 /horizontal三种模式, 另支持collapse折叠、accordion、水平选中指示条与悬停桥)、ArcoTabs(六种类型 +tabPosition上下左右含竖向标签栏、可编辑)。
数据展示与导航(P3 收尾) #
ArcoList/ArcoListItem/ArcoListItemMeta:dataSource+render或children、header/footer、size(small/default/large)、bordered、split、 hoverable、loading(Spin)、grid(column/span/gutter)、scrollLoading、 noDataElement、onReachBottom、内嵌pagination(内部切片 + 右下分页器)。ArcoPagination:total/current/pageSize(受控 + 默认值)、sizeOptions 与 sizeCanChange、simple、showTotal、showJumper、bufferSize 折叠算法、 disabled/hideOnSinglePage、itemRender 与自定义图标。
修复 #
- 浮层文本样式泄漏:
MaterialApp最外层DefaultTextStyle是_errorTextStyle(红色 48px 等宽 + 黄色双下划线),浮层位于Material之上拿不到覆盖,导致浮层文字带黄色下划线、异常加粗。新增ArcoOverlayTextBaseline在 Portal 与消息队列根部重建完整文本基线, 浮层内部局部样式统一改用DefaultTextStyle.merge。 - InputTag:有标签时输入文本不可见(宽度未随输入重算);悬停时空槽位 参与布局导致高度反复闪动(槽位改为常驻、hover 仅切换图标可见性)。
- TimePicker:面板缺少定宽约束导致弹层被撑到可用宽度。
- Modal / Drawer:
onOk仅支持同步调用,「异步确认」无法接管关闭时机, 签名放宽为FutureOr<void>(返回Future时按钮自动 loading、完成后关闭)。 - Message:关闭回调捕获构建期下标,多条消息堆叠时越界导致剩余消息 永久滞留,改为按对象身份删除。
- Menu:浮层内容
Column默认MainAxisSize.max,在浮层的松约束下 撑满可用高度(水平下拉高达满屏),改为按内容收缩。 - 主题:补齐
body[arco-theme='dark']段的暗色覆盖(如 Tabs 胶囊型选中项 为fill-3)。
工程 #
- 示例应用扩展为 9 个展示页(概览、设计令牌、Button、布局与排版、展示组件、
反馈组件、浮层组件、表单组件、导航组件),支持亮暗主题、主色切换与
#p=<序号|标题>[&dark]深链。 - 测试扩展至 460 项(28 个测试文件),含令牌逐值比对、组件结构/状态机/ 交互、以及固化为断言的官方几何量测。
- 新增
docs/HANDOFF.md:交接快照(进度、环境命令、门禁与截图流程、踩坑记录)。
0.1.0 #
首个可用版本:完成令牌层、主题层与 Button 组件。
令牌层 #
- 移植
@arco-design/color@0.4.0的动态色阶算法,与官方发布产物逐值一致。 - 内置 14 组预设色板(13 组有彩 + neutral),亮/暗两套共 280 个色值。
- 语义颜色令牌:
text/fill/bg/border/secondary/primary/success/warning/danger/link/*-light/data等。 - 与主题无关的令牌:尺寸、间距、圆角、边框、不透明度、阴影、字体、动效、层级。
主题层 #
ArcoThemeData以ThemeExtension挂载,支持插值动画。ArcoTheme.light()/ArcoTheme.dark()直接产出ThemeData。- 支持传入自定义主色并推导完整 10 阶色板。
context.arco语法糖读取令牌。
组件 #
ArcoButton:5 种类型、4 种状态、4 种尺寸、3 种形状, 支持icon/loading/loadingFixedWidth/iconOnly/long/tooltip/ 键盘操作与Semantics。ArcoButtonGroup:相邻按钮拼合,外侧保留圆角、中间为直角。
工程 #
- 示例应用:概览、设计令牌、Button 展示页,支持亮暗主题与主色实时切换。
- 测试:色板算法逐值比对、主题令牌、Button 渲染与交互,共 30 项。
- 代码生成:
tool/refresh_official_palette.py与tool/gen_palette_presets.py。