Skip to content

Releases: baiwumm/vue3-okr-tree

v1.16.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 04:27

1.16.0(2026-09-26)

  • 新增 virtual 虚拟滚动:同层可见兄弟数 ≥ 50 的行只渲染视口内窗口,DOM 数量与滚动流畅度不再随总数增长(1 父 + 10000 平铺子节点实测渲染节点 10001 → 13)。实现要点:未渲染兄弟的位置由等尺寸占位块顶住(float 行总宽与每个渲染节点的坐标和全量渲染逐像素一致),占位块自带连线段续接横线,行首 / 行末的边界帽(:first-child / :last-child 的去线与圆角)语义由占位块自然继承;展开行的子容器按宽度模型显式定宽(float 的 shrink-to-fit 取 min(max(min-content, 可用宽), max-content),单个巨宽占位块会把容器钉在 min-content 上、把渲染节点挤到第二行折断连线);折叠行不渲染占位块,折叠宽度与全量渲染一致。aria(aria-setsize / aria-posinset)、show-node-num 计数、getVisibleNodes() 全部按全量可见列表输出;scrollToNode 与键盘漫游对窗口外目标先揭示再定位(逐条推进不跳焦)。要求数字型 label-width(horizontal 布局还要求 label-height),auto 尺寸下达标行退回全量渲染并警告;创建期快照,运行时变更输出警告。已知边界:万级数据首帧成本主要在 store 构建(1 万节点约 2.9s,与 virtual 无关、全量渲染同样存在),virtual 消除的是 DOM 数量与滚动 / 展开时的渲染卡顿;压缩后产物 +2.1 kB gzip(ESM / UMD 预算上调至 21 kB)。姊妹包 react-okr-tree 同批同形。

v1.15.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 16:44

1.15.0(2026-09-26)

一个功能 minor:Vue Devtools 面板(dev only,roadmap #16 最后一项,做完 #16 整项清空)与 DEFAULT_PROPS 导出补齐(两仓导出面最后一个不对称清零)。两项都是纯增量,无任何行为变化。姊妹包 react-okr-tree 同号跟随(DEFAULT_PROPS 侧早已导出、Devtools 面板无对等物,详见其 CHANGELOG)。

  • 新增 Vue Devtools 面板(dev only):开发环境自动向 Vue Devtools 注册 OkrTree 面板——树实例列表(根节点文案 + 注册表节点数 tag,OKR 模式带标记)、概要(节点数 / 展开数 / 当前节点 / 勾选与半选计数)与右树 / 左树的节点注册表全量转储(文案 / 层级 / 展开 / 可见 / 勾选 / 半选 / 子节点数),数据按需拉取、不占渲染路径。实现零依赖:不引 @vue/devtools-api,直接按其 v6 线协议与 window.__VUE_DEVTOOLS_GLOBAL_HOOK__ 握手(devtools-plugin:setup 事件与 __VUE_DEVTOOLS_PLUGINS__ 排队条目形状逐字同源,api 由 Devtools 后端回调传入)。门控与开发期警告同一套(运行时 process.env.NODE_ENV,使用方打包器替换后整段消除,SSR 与无 process 的 UMD 场景视为生产环境不注册)——npm 产物增大约 1.5 kB gzip(ESM 16.31 → 17.81 / 预算 19),不会进入消费方的生产包,与 Pinia / Vue Router 内置 Devtools 集成同一模型。姊妹包 react-okr-tree 无对应物(React DevTools 不提供第三方自定义面板 API)。
  • 补导出 DEFAULT_PROPS:字段映射的默认值常量({ children: 'children', label: 'label', disabled: 'disabled' })此前只在内部使用,而姊妹包 react-okr-tree 侧已导出——这是两仓导出面审计记录的最后一个不对称,本次清零。宿主自定义字段映射时可以 { ...DEFAULT_PROPS, label: 'name' } 而不必写全所有字段。纯增量,无任何行为变化。

v1.14.2

Choose a tag to compare

@github-actions github-actions released this 25 Sep 12:08

1.14.2(2026-09-25)

四条修复的一批:Demo 交互层批次(G8)实测出来的三处库语义缺口 + 一处画布交互卡死。对外 API 形状零变化,按「修复 +1 patch」定档。其中 default-checked-keys 一条改的是可观察行为(运行时重放的判据从按引用改成按内容),唯一会感知到差异的用法是「传一个等值新数组来强制清空勾选」——那等于依赖每次渲染回滚用户操作,故仍按 patch 走,但如果你确实这么写,请改用 setCheckedKeys()。姊妹包 react-okr-tree 同号跟随。

修复

  • node-drag-end 在成功放置后不再报 null 载荷:handleDrop 先清掉 dragOverNode / dragOverType(指示线不能留在屏幕上),而 node-drag-end 是 drop 之后才派发的,于是这条事件的 dropNode / dropType 恒为 null——文档站的拖拽用例每次成功拖动都记一句「未完成放置」。现在改为在 drop 里就地发出 node-drag-end 并收尾手势(同时清 draggingNode,让真到达的那次 dragend 被守卫短路,不会补一条重复事件),载荷与 node-drop 一致;取消或被拒的拖拽仍按语义报 null。选这条路线而不是「在 dragend 里读落点备份」:跨父级移动会把源元素卸载重建,浏览器那次 dragend 落在已脱离文档的节点上,宿主侧收不到(react 侧正是这种形态)。
  • 过滤词只命中 OKR 左子树时,整棵树不再从 DOM 消失:共用的根节点自身不匹配、右树侧零命中时被判不可见,而节点根元素是 v-if="node.visible"——刚命中的左子树跟着被卸载,页面空掉(getVisibleNodes() 读 0)。Q1「父节点保持可见」当年只修通了右树这一侧;现在左树命中也会把根保住(OKR 下 filter 先右后左的调用顺序是承重的,已写进注释)。
  • default-checked-keys 运行时按内容比较,不再按引用重放:宿主每次渲染新建一个等值数组(计算属性、漏了 useMemo 的派生表达式都会这样),原先被当成「默认勾选变了」,先清空全部勾选再重放列表,把用户刚勾掉的、刚勾上的整片抹回去。现在只有列表内容真的变了才重放(String(key) 归一去重后比对,与 getCheckedKeys 同口径),undefined 与 [] 视作同一份「没有默认勾选」。API 表与文档站措辞同步更正。
  • 画布平移把手势甩出画布边界再松手,会卡住平移态并让悬停继续拖动画布:OkrTreeViewport 的 pointerup / pointercancel 只挂在画布根元素上(既没有 setPointerCapture,也没有 window 级监听),指针在画布外松开时这两个处理器根本不执行——is-panning 留在原地、panStart 也不清,于是之后不带按键的悬停移动仍按 panStart 继续改写偏移(实测从 translate(125px, -379.5px) 一路走到 translate(290px, 0px))。现在由一个挂载期注册、卸载时摘掉的常驻 window 监听收尾(常驻而不是按次添加,免得 1.14.1 修掉的监听堆叠换个形式回来);这条收尾不武装「吞掉一次 click」——松手在画布外时浏览器不会在画布里派发那次 click,武装了就会吃掉用户回到画布里的第一次正常点击。姊妹包 react-okr-tree 同批同形。

v1.14.1: ci: 四个 action 升到不再跑在 Node 20 上的第一个大版本

Choose a tag to compare

@github-actions github-actions released this 24 Sep 14:18

1.14.1(2026-09-24)

对外 API 零变化的一批:修掉 7 个真实缺陷(组对齐宽度被首量钉死、contains 未递归左子树导致可成环、换绑 data 把整棵后代摘出注册表、zoomIn / zoomOut 锚点取错、平移后吞点击堆积监听、产物丢失三家打包器的 ignore 注释、connector="svg" 稳态自持重排),另有 3 项性能收敛、10 条门禁补强与两站文档对齐。姊妹包 react-okr-tree 同号跟随。

性能

  • aria-setsize / aria-posinset 改为按层算一次下发:旧实现是每个节点一个 computed,各自读 parent.childNodes 做 filter + indexOf ⇒ 同层 s 个节点扫两遍、O(s²)。新增 src/lib/okr-tree/aria-set.ts 的 setPositions(list),由父节点(含根层的 OkrTree)在渲染子列表时算好 {size,pos} 作为 props 传下去;不可见节点仍不输出这两个属性(props 为 undefined),左右两树各自成组,口径与旧实现一致。react 侧本就是父下发形状,同批把其 map 内的 indexOf 换成同一套单遍计算。
  • 复选框一次点击从 4 次全树遍历降到 1 次:check 事件的 payload 原先由 getCheckedNodes() / getCheckedKeys() / getHalfCheckedNodes() / getHalfCheckedKeys() 四次调用拼成,而两个 key 版内部各自还要再调一次节点版 ⇒ 一次点击要走 4 遍全树(含整棵 OKR 左树)。新增 collectCheckState(leafOnly) 一次遍历算齐四份,四个公开方法原样保留。语义逐字不变:String(key) 去重、遍历顺序、跳过空 key、checked 的节点不进半选列表。
  • 同层整批换引用时 updateChildren 的 key 回退降为线性:回退原本是 oldNodes.find(n => !used.has(n) && n.key === k),同层 s 项全部换引用时第 i 项平均要扫 i 次 ⇒ 该层退化到 O(s²)。现改成一次建好的 Map<key, TreeNode[]> 索引。实测(把 key getter 包住计数):s=3200 整轮换引用时 key 访问 16,005 次(=5s),而旧实现按公式是 5,121,600 次(s(s+1)/2),setData 耗时从 35.9ms 降到 15.0ms。两处语义刻意保住——键不做 String 归一(原判断是 ===,11 与 '11' 不该互配)、桶存数组而非单值(同层重复 key 时第二项要能命中第二个旧节点),各有一条用例钉住,换成朴素的 Map<string, TreeNode> 就当场红。

修复

  • zoomIn / zoomOut 的锚点改用可视区尺寸:原先取 getBoundingClientRect().width / 2,而 fitToScreen 与 react 侧都取 clientWidth / 2——视口内出现滚动条时两者相差半条滚动条宽,同一个包的两条路径与姊妹包之间会各偏一点。现统一走新增的 viewportCenter()(clientWidth / clientHeight),与 react 侧的 center() 同形。

  • contains 把 OKR 左子树算进子树范围:moveNode 的自环硬守卫与 dropValid 都靠 TreeStore.contains() 回答「目标是不是被拖节点的后代」,但它只递归 childNodes,而 OKR 左子树挂在 leftChildNodes 上——于是 moveNode(OKR 根, 其左子树内的节点, 'inner') 放行,根与左子树互相指向,getVisibleNodes 这类同时走两侧的遍历不再收敛。现一并递归 leftChildNodes;同时钉一条「右树节点仍可移进左子树」的用例,防止把 reassignSide 那条合法的跨侧路径一起堵死。

  • connector="svg" 稳态不再自持重排:redrawConnectors 结尾原先无条件把新数组写进 connectorEdges,于是「写 ref → 重渲染 → onUpdated 再排一帧 → 再写」闭成环——空载页面也以每秒一帧的节奏重排全树、逐节点读一遍 getBoundingClientRect(react 版实测同规模约 10,400 次/秒)。现改为逐条比对 d,完全相同就保持原引用,与 react 版的 sameEdges 短路同形。顺带补上这条环原先兜着的缺口:onUpdated 其实指望不上——节点的 expanded 只被 OkrTreeNode 读,父组件不重渲染就不触发它,所以展开态变更改走新增的 onExpansionChanged()(同步受控 keys + 显式排一帧重绘),同时覆盖节点点击与 expandNode / collapseNode 两条路径;实测空闲 12 帧之后再收起节点,实体边仍会正确替换成收起残枝。

  • 换绑 data 引用不再把整棵后代摘出注册表:data 数组引用保持不变、只把某一层对象换成同 key 的新对象(轮询接口的典型局部更新)时,TreeNode.updateChildren() 的换绑分支原先调递归版 store.deregisterNode()——它连带删掉该节点全部后代在 nodesMap 里的登记,而复用路径不会重新登记,于是这些后代的 getNode / getNodePath / setCurrentKey / remove / moveNode 等按 key 的公开方法一律静默失效,而节点仍照常渲染、仍可点击。改用新增的 deregisterNodeSelf()(只摘本节点):该分支的匹配条件本就是 key 相等,后代的实例与 key 都没变,留在注册表里才是正确状态;真正被移除的节点仍由尾部注销循环递归清理。姊妹包 react-okr-tree 同批同形修复。

  • 平移后吞点击不再往视口元素上堆监听:handlePointerUp 原先每次平移结束都 addEventListener('click', …, { capture: true, once: true }),而触摸平移压根不派发 click——监听于是按平移次数累积挂在元素上,直到某一次真出现 click 才被一次性摘掉(组件卸载时仍挂着)。现改记一个 swallowNextClick 标志,由模板上常驻的 @click.capture 处理判断并消费;对外语义与改动前逐字一致(平移后紧跟的那一次 click 被吞,第二次照常送到节点),只是不再残留注册。两条新用例分别钉「吞一次且只吞一次」与「平移过程中元素上 click 注册数为 0」——把实现还原成 once 监听、或把标志赋值摘掉,各打红其中一条。与姊妹包 react-okr-tree 同批同形。

  • 产物真的保住 html-to-image 的三条 ignore 注释(并把压缩器换成 Terser):可选 peer 靠「变量说明符的动态 import」避开打包,但消费者的打包器只认注释——@vite-ignore 管 Vite/Rollup,Next 16 的 Turbopack 只认 webpackIgnore / turbopackIgnore,缺了就是下游构建期 Module not found(本包能发出去、对面装不上;文档站是第一个撞上的真实消费者)。此前源码只有 @vite-ignore 一条,而且就算补齐也没用:scripts/post-build.mjs 会用 esbuild 把 ES 产物补压一次,连注释一起吃掉。实测 esbuild 四档压缩(minifyWhitespace 单开 / legalComments: 'inline' / 把注释写成 legal 形态 / 全量压缩)没有一档保留这三条。现改 build.minify: 'terser' + format.comments: /vite-ignore|webpackIgnore|turbopackIgnore/,并删掉 post-build 那道补压(顺带 ES 的 .map 不再被删,与产物行号对齐)。体积不升反降:ESM gzip 16.77 → 16.12 kB、UMD 16.64 → 16.23 kB(Terser 比 esbuild 更小),三项预算余量一起变宽。scripts/verify-dist.mjs 补 7 条门禁:ESM / .cjs / .umd 各断「未静态引入可选 peer」+「三条注释齐全」,另断 ESM 仍有 import( 调用点——verify:dist 34 → 41 条。回归验证(把历史形态装回去):重新加上 post-build 的 esbuild 补压后,门禁当场红 FAILED: ESM 保留可选 peer 的三家打包器 ignore 注释。新增 devDependency terser。

  • 组对齐宽度不再被首量钉死(is-measuring 此前从未落到 DOM 上):OkrTreeGroup.measure() 原先在同一个同步块里「measuring = true → 读 rect → false」,而这个类是绑在响应式状态上的、DOM 要到下一个 tick 才更新,于是临时测量态压根没生效,读到的一直是当前分配宽度;偏偏 .is-measured 又把左容器宽度钉成 var(--okr-group-left-width),结果首量之后再也涨不上去——实测 320px 容器里首量得 140px,放宽到 1280px 仍是 140px;组里先放一棵窄树、再加入一棵左子树宽得多的成员,var 仍停在首量值(refresh() 走同一条 measure,救不了)。现改为测量期间直接操作 DOM classList:摘 is-measured → 加 is-measuring → 读 → 复原。两条缺一不可:只加不摘等于没加,因为 style.css 里 .is-measured 的钉宽规则排在 .is-measuring 的 max-content 之后且特异度相同(这条是踩出来的——先只做「加类」时新增的浏览器用例在变异下仍然全绿)。刻意不走 await nextTick():那会让测量跨帧,真被渲染出来的测量态触发一次组件更新 → 子树 onUpdated 再请求测量,容易绕回自持环;同步 add → 读(读 rect 自带强制布局)→ 复原全程在一个任务内,浏览器不会绘制中间态,也不闪。回归两条:a11y-group.spec.ts 的测量用例新增「读 rect 那一刻 is-measuring 必须在 DOM 上」(摘掉类操作 → expected [false, false] to equal [true, true]);新增浏览器级 tests/visual/group-align.spec.ts 断「后加入更宽成员时对齐宽度要涨」(同一变异当场红)。视觉基线 17 → 18 条全过、无需重拍。与姊妹包 react-okr-tree 同批同形。

工程化(无对外行为变更)

  • CSS 几何常量钉进 verify:dist(与 react 侧 G17 同批同形):连接线的几何值全是相互咬合的硬编码,改一个就错位,而组件层没有任何断言能发现它。新增 21 条断言:六个变量(--okr-gap-level:20px / --okr-gap-sibling:5px / --okr-line-width:1px / --okr-line-radius:5px / --okr-btn-size:20px / --okr-gap-node-y:10px)各断「每处使用都带兜底」+「兜底值处处同值」;左子树短头 width:12px / height:10px / left:calc(100% - 11px) 与两处 -1px / !important 修正各断恰好出现一次(两次=有人复制规则没删原件,同特异度下后者说了算);okr-unstyled 的中和规则断为五类选择器且基础 + :hover 共两处;再断 .is-measuring 排在 .is-measured 之前——组对齐修复的承重前提正是这条同特异度顺序,颠倒之后 measure() 无论怎么改都会读回被钉住的宽度。匹配前先归一两种形态:声明体抹掉全部空白(绕开压缩器「逗号后有无空格」的差异),选择器只把空白折成单空格(.a b 压成 .ab 就走形了)。顺带说明为什么不做「两仓 CSS 逐字 diff」:两仓 src 的 style.css 实测只差头注释与 @import 路径两处、transition.css 全等,但产物由两套压缩器各写一遍(本仓 esbuild、react 走 rolldown 内置那套),会合并同声明体的相邻规则、重排声明、transparent→0 0、.3s height→height .3s、颜色折成 #fffffff0,逐字比必然假红。五条变异在两仓各跑一遍、全部打红(兜底值 20px→24px、规则顺序颠倒、五类降四类、-11px→-12px、12px→14px)。CSS 段现两端各 33 条、逐条同序同字面(此前两端各缺一条:本仓少「含打印与减弱动效块」、react 少「连接线颜色无残留硬编码」,现已补齐)。verify:dist 41 → 62 条 ok。
  • 缺 node-key 的受控 prop 警告族补齐三条断言(与 react 侧 G4 同批同形):OkrTree.vue:312-321 有四条「需要同时设置 node-key」的开发期警告,controlled.spec.ts 此前只在一次 pooled 断言里命中了 expanded-keys 与 current-key 两条文案,default-expanded-keys / default-checked-keys 两支从未被断过,currentNodeKey 那一支也只是顺带过的——它的消息写着「current-key / current-node-key」,只传 currentNodeKey 时靠子串也能命中,把源码里的 || props.currentNodeKey !== undefined 摘掉都不会红。现新增一条用例:三个 prop 各单独挂载一次、每次都断「这一次的消息集合」,另加一条反向守卫(补齐 node-key 后三条都不许出现)。反向守卫一开始是永真的:warn() 默认按文案去重,第四次挂载前没清表,消息被前三次吃掉,实测把 if (!props.nodeKey) 改成无条件警告后这条守卫照样绿(红的只是文件里另一条老用例)——现每次挂载前 resetWarnings(),改无条件后两条用例一起红。三条变异全部实测只红新用例(驱动 _scratch/probe-warn-mutation.mjs,自带未变异基线、锚点存在性自检与 finally 还原)。单测 257 → 258 条。
  • 受控锁定态补用例(与 react 侧 G8 同批同形):requirements 与第 1 轮报告都把「传值但不传回调」写成一种锁定,react 侧给的判据是「点 +/- 后断言视图不变」。照写会得到一条红用例——本包实测并不冻结视图:展开态的渲染源是 store,expanded-keys 只在创建期与宿主传入值变化时回灌,宿主不回写就没有第二次同步,点击照常折叠(react 侧同样三种写法逐字测过,结论一致,所以这不是复刻偏差而是两仓共同语义)。现按真实语义钉两条:① 只传 prop 不接 update:expanded-keys → 不报错不警告、点击生效;② 接了监听但监听什么都不做 → 监听照样收到新值(收起根节点即 [])、视图不被拉回。三条变异验证判据有牙:V1 摘掉 emit 红 ②;V2 在 emit 后以 prop 为准 setExpandedKeys 拉回(=真冻结)红这两条;V3 去掉 node-key 守卫让锁定态也警告红 ①。V3 一开始是白断的:warn() 按文案去重、去重表是模块级的,本文件前面的用例已经把那条文案发掉,不自己 resetWarnings() 的话 not.toHaveBeenCalled() 恒真(实测改无条件警告时它照样绿)。单测 258 → 260 条。
  • 拖拽悬停的 DOM 写入落点判据(与 react 侧 G9 同批):「拖拽指示只更新相关节点」这句承诺两仓都只是实现、没有断言——把 handleDragEnter 改成顺手写 dragOverNode、dragend 不清指示、或给每个 label 都挂一个「正在拖拽」的类,draggable.spec.ts 的 11 条功能用例照样全绿。新增 tests/components/local-update.spec.ts(与 react 同名文件对称),用 MutationObserver 按事件顺序断「被写了 class 的元素」恰好是谁:dragstart 0 处 → 首次悬停 1 处(label:branch-1#drop-inner)→ 同节点同分区重复 dragover 0 处 → 换目标 2 处(旧 label 清空 + 新 label 挂上)→ 同节点换分区 1 处 → dragEnter 0 处 → dragend 1 处。判据落点与 react 不同是机制决定的,不是偷懒:react 每个节点订阅自己的版本号,断「谁被 bump」;本包的 dragOverNode 是 OkrTree.vue provide 下来的 shallowRef,18 个节点的 labelWrapperClass 都读它,实测换一次目标全部重新求值(计数探针 _scratch/probe-recompute-count.mjs),但只有值真变了的 2 个元素被写入 DOM——所以这里钉的是 DOM 写入落点。五条变异逐个跑过、全部只红这条(摘 dragend 的清理 / dragEnter 顺手挂指示 / dragstart 就标成放置目标 / 全员加 is-hovered / 把 drop-* 从 label 外层挪到节点元素上;驱动 _scratch/probe-drag-mutation-vue3.mjs,自带基线绿跑、锚点唯一性自检与 finally 还原)。踩到一条 jsdom 陷阱:MutationObserver 的回调按微任务派发,await nextTick() 之后直接 takeRecords() 会在「回调已经把记录取走」与「回调还没跑」之间随机拿到空数组——第一版探针因此把整棵树的 class 写入读成 0 条,看着像「实现本来就局部」的假绿。现收记录前先等一个宏任务边界,回调数组与 takeRecords() 两边都取。单测 260 → 261 条。
  • OKR 根卡片「展开 / 收起不被推位」补几何断言(与 react 侧 G14 同批):align-root 的全部作用就是这一句,此前只有那条 CSS、align-root 类名与两张展开态的像素基线,收起这个动作序列本身没有几何断言守着。tests/visual/visual.spec.ts 新增一条:对 #demo-10 第一棵树的根卡片量 getBoundingClientRect(),右子树收起 → 重新展开 → 左子树收起 → 重新展开,四次 toBeCloseTo(x, 0) + 两次宽度比对,每步同时断 -children / -left-children 上 is-hidden 的确切出现与消失(否则「坐标没变」可能只是按钮没生效)。量的是相对 .org-chart-container 的水平偏移而不是绝对 left:点击时 Playwright 会把目标滚进视口,绝对坐标跟着滚动位置走(react 侧实测同一动作让绝对 left 从 962 跳到 591),拿绝对坐标只会得到一条与几何无关的红。只加断言、没加截图基线(png 仍是 28 张,视觉用例 18 → 19 条)。本仓配置没有 react 那句 reducedMotion: 'reduce',收起仍走 200ms 过渡(animate-duration 默认值),故每次切换后等 320ms 再量,避免一条只在机器慢时才红的用例。三条变异改的是 playground/dist 那份产物 CSS(gitignored,跑完逐字还原),射程按实测记:给 .is-hidden 追加 display:none → 本条红、两张 OKR 像素基线也红;flex:1 1 0 → 0 0 auto 与根节点 width:100% → auto → 本条与两张基线都绿,是 group-align.spec.ts 把它们打红的。即这条守的是「收起不推根节点」,不是 align-root 的静态形状。与姊妹包 react-okr-tree 同批同形。
  • 焦点环补计算样式断言(与 react 侧 G13 的不依赖像素那一半同批):环此前只有类名与人眼看图,视觉套件里没有任何计算样式断言守着。新增一条:page.keyboard.press('Tab') 循环走到第一个 .org-chart-node(上限 80 次,走不到即判失败——否则后面的环断言全在空转),断该节点卡片本体的计算 outlineStyle='solid' / outlineWidth='2px' / 颜色非透明,并断焦点元素自身 outlineStyle='none'。读的元素不是聚焦元素:style.css:686-695 把 .org-chart-node:focus 清成 outline: none,真正的环挂在 .org-chart-node:focus-visible > .org-chart-node-label > .org-chart-node-label-inner,姊妹...
Read more

v1.14.0

Choose a tag to compare

@github-actions github-actions released this 22 Sep 09:08

1.14.0(2026-09-22)

对外只多一个导出(BUILT_IN_THEMES),其余全是发布前收口的测试与门禁断言。本版本同时是第一个由 CI 通过 OIDC Trusted Publishing 真实发包的版本。

新增

  • 导出 BUILT_IN_THEMES:内置主题名清单(default / feishu / dark / auto / minimal / colorful)。此前它只用于 theme prop 的校验告警、未从包入口导出,而姊妹包 react-okr-tree 已导出——本次补齐两端导出面对齐。需要枚举主题名的场景(主题选择器、设置面板)不再得硬编码字符串数组。

工程化

  • verify:dist 补 3 条 .cjs 断言(对应验收表缺口 Q9 / G5):本包是 "type": "module",Node 会把 .umd.js 按 ESM 解析,require() 只能走 .cjs 这份产物,而这条路径此前全靠人工验证、构建端把 exports 条件写坏要到发包后才被发现。现在用 createRequire 真实加载产物,断言组件导出指向同一实现、BUILT_IN_THEMES 为 6 项、createTypedOkrTree / TreeStore 可取。
  • shared/api.ts 的 Methods 表补 getNodeKey 与 store / root 两行,README 随之重新生成。getNodeKey 早在 defineExpose 里,但表上漏记,导致 README、文档站 API 页与 playground 三处同时查不到这个方法——react 侧审计的 §6.3 一度指出过,本包未修。
  • 新增 tests/api-surface.spec.ts:API 表与 defineExpose 的双向防漂移(表→实例、实例→表、行数与成员数一致),与 react 侧 tests/api-surface.spec.tsx 同构。上面的漏记正是这条用例存在的理由。
  • 新增 tests/model/framework-boundary.spec.ts:模型层无 Vue 2 残留写法(new Vue( / eventBus / $on $emit $set $children $refs / Vue.prototype),且从 vue 只引入响应式 API(收口 Q7)。与 react 侧同名文件命名一致但内容不同——react 断的是「模型层不引用框架」,本包的 node.ts 刻意用了 shallowReactive,照搬会写成假测试。
  • 过渡相关补三组断言(收口 Q6 / Q8):transition-robustness.spec.ts 用 it.each 逐个断六种内置 animateName 的 okr-anim-<name> 接线(此前只钉 okr-fade-in 一种),并新增「点击 +/- 收起时子容器切 is-hidden 而非卸载、再点恢复」的用例;verify:dist 的 CSS 侧由「只钉一组」改为六种逐个断 enter-active / leave-active。
  • theme.spec.ts 补 [vue3-okr-tree] 警告前缀断言(此前只断文案,前缀本身零覆盖)。
  • vite.config.ts 的 test.include 加 tests/*.spec.ts,使根级 api-surface 用例被收集。
  • 门禁数字:单测 226 → 242(21 → 23 个文件),覆盖率 90.85 / 81.81 / 88.94 / 93.56,verify:dist 实跑 34 条 ok。
  • 新增 docs/acceptance.md 验收证据表,结构与 react-okr-tree 的同名文档对齐:§7 五条验收项与 Q1–Q9 逐条给到 文件:行 + 用例名,并记入与 react 侧的 props / 导出面双向差集实测结果。
  • docs/requirements.md 与 docs/development-plan.md 的 Demo 用例数由 20 更正为 24(playground/components/demos/ 实际文件数)。

v1.13.0

Choose a tag to compare

@github-actions github-actions released this 21 Sep 08:41

1.13.0

新增

  • unstyled prop(2.x #13):去掉节点卡片的外观(背景 / 边框 / 圆角 / 阴影,含 :hover 态),只保留布局与连接线,供 Tailwind 或自有设计系统接管——此前唯一的退路是覆写全部 --okr-node-* 变量,而主题类会重新填回这些值。内边距、字号与文字色刻意不动:改 padding 会移动节点盒并牵动连接线的伪元素几何,需要调整请继续用 --okr-node-* 变量或 label-class-name。
    • 实现上是一个 okr-unstyled 容器类 + 一小段中和规则;选择器需要 5 个类才能压过方向专属规则(.org-chart-container .vertical .org-chart-node-label .org-chart-node-label-inner 同为特异度且位于其后,同特异度时后者胜)。Visual 套件补了一条计算样式断言同时校验「阴影被清掉」与「节点盒尺寸不变」——写第一版时正因漏了 .org-chart-node 一层而被该断言当场抓到。
    • 样式 gzip 3.83 → 3.88 kB(预算 4 kB,余量约 3%)。

变更

  • html-to-image 以可选 peerDependency 声明(^1.11.0 + peerDependenciesMeta.optional):exportImage 的这项外部依赖此前只写在文档和运行时报错里,包管理器侧没有任何声明可循;仍不进 dependencies,用不到导出能力的消费者不会被拖进来。
  • 视觉门禁端口可覆盖(OKR_VISUAL_PORT,默认仍是 4173):Windows 的 TCP 排除端口区间(netsh int ipv4 show excludedportrange protocol=tcp)会把 4173 整段保留,vite preview 直接 EACCES,此前在这类机器上无法本地复现视觉门禁。