ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenPencil ColorPickerRoot 无样式颜色选择器实战:插槽驱动 HSV 取色与取消回滚机制

OpenPencil ColorPickerRoot 无样式颜色选择器实战:插槽驱动 HSV 取色与取消回滚机制 前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载ColorPickerRoot是 OpenPencil 设计编辑器 SDKopen-pencil/vue中面向自定义 UI 的无样式headless颜色选择器根组件它负责统筹 HSV 色相、透明度与十六进制输入的完整交互逻辑而把外观swatch 触发器与 popover 面板完全交给调用方的插槽。本篇文章将基于官方 SDK 文档与仓库源码packages/vue/src/primitives/ColorPicker/ColorPickerRoot.vue等讲解它的 Props/Events/Slots 契约、与ColorInputRoot、useColorModel、BindableValue的协作方式并给出可复制运行的 Vue 3 示例。一、ColorPickerRoot 是什么逻辑与展示分离的取色器根组件在 OpenPencil 中ColorPickerRoot被设计成一个逻辑控制器 无外观外壳组件。它自身的职责只有两件事协调取色交互的状态机把 HSV 色相、透明度、十六进制输入统一收敛为一个底层色彩模型提供弹出层生命周期借助 popover 面板承载选色界面并向外广播打开/关闭、取消等交互边界事件。而长什么样完全由使用方决定——应用如 OpenPencil 编辑器主程序通过插槽注入自己的 swatch 按钮样式与 popover 内容布局从而实现任意品牌皮肤、任意交互形态的取色器。官方文档的原话是Composes a color swatch trigger with a popover surface while leaving the editor UI to its slots.组合一个色块触发器与弹出层表面同时把编辑器 UI 完全交给插槽。这正是 headless 组件无头组件的典型价值需要取色器的全部逻辑但不需要 OpenPencil 应用的既定样式时ColorPickerRoot就是为这个场景而生的。源码位置一览内容仓库路径组件实现packages/vue/src/primitives/ColorPicker/ColorPickerRoot.vue配套组件packages/vue/src/primitives/ColorPicker/ColorInputRoot.vue导出入口packages/vue/src/primitives/ColorPicker/index.tsSDK 顶层导出packages/vue/src/index.ts官方 API 文档packages/docs/programmable/sdk/api/components/color-picker-root.md组件内部还使用了useRetainedPopup位于src/app/...的生命周期弹层逻辑源码见#vue/lifecycle/retention/popup用于在取消时统一回滚弹出层状态。二、组件契约Props、Events 与插槽ColorPickerRoot的完整契约如下与源码defineProps/defineEmits一一对应。Props名称类型必填说明colorColor是当前场景图颜色值RGBA。Color类型定义在 packages/scene-graph/src/primitives.ts为{ r, g, b, a }四个0–1浮点通道labelstring否swatch 按钮的无障碍标签aria-label默认值为Edit coloruiColorPickerUI否样式类注入结构为{ content?: string; swatch?: string }分别作用于 popover 内容与 swatch 按钮的 class。Events名称载荷语义updatecolor: Color颜色发生变化时发出用户在面板中调完色后触发。注意仅打开或聚焦取色器不会触发 updateopenChangeopen: boolean报告完整的取色器交互边界打开true与关闭false。官方文档称其为the complete picker interaction boundarycancel无在按下 Escape 关闭弹出层之前触发供消费者把变量解绑 涂色更新一起回滚详见第四节。插槽名称作用域语义trigger{ style: { background: string } }接收当前 swatch 的背景 CSS 样式由colorToCSS(color)计算而来插槽内放置自定义触发器若不提供默认渲染一个typebutton、带aria-label的色块按钮default{ color: Color }接收当前场景图颜色插槽内渲染弹出层的内容色相条、透明度滑条、Hex 输入等。下面这段来自官方文档的完整示例展示了双插槽的用法——触发器实时显示当前颜色弹出层内用output展示 RGBA 分量script setup langts import { ref } from vue import type { Color } from open-pencil/scene-graph import { ColorPickerRoot } from open-pencil/vue const color refColor({ r: 0.2, g: 0.5, b: 0.9, a: 1 }) /script template ColorPickerRoot :colorcolor updatecolor $event open-changeopen console.log(open) cancelconsole.log(cancel) template #trigger{ style } button :stylestyle aria-labelEdit color / /template template #default{ color: currentColor } output{{ currentColor.r }}, {{ currentColor.g }}, {{ currentColor.b }}/output /template /ColorPickerRoot /template三、底层实现popover 组合、色板样式与 Escape 拦截打开 ColorPickerRoot.vue 可以看到它的实现非常精简核心由三部分拼装而成。1. Reka UI 的 Popover 三件套import { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from reka-ui组件把reka-ui的PopoverRoot/PopoverTrigger/PopoverPortal/PopoverContent组合为取色弹出层PopoverRoot用v-model:openpopupOpen双向控制开合并在update:open时同步转发openChange事件PopoverTrigger以as-child方式把插槽内的自定义触发器当作触发元素保证焦点管理与点击外关闭dismiss行为PopoverContent通过PopoverPortal挂载设置sideleft、side-offset4即弹出层默认靠左偏移 4px展开并带data-picker-content标记便于测试与 CSS 定位。2. swatch 背景色的计算const swatchBg computed(() colorToCSS(color))触发器插槽暴露的style对象即来源于colorToCSS()——这个函数来自open-pencil/scene-graph/color把场景图的 RGBAColor序列化为 CSS 颜色字符串。因此插槽中拿到的{ background: rgba(...) }永远与当前取色状态同步不需要调用方自己维护 swatch 样式。3. Escape 取消cancelFromEscapefunction cancelFromEscape(event: KeyboardEvent) { event.stopPropagation() emit(cancel) }PopoverContent的escape-key-down事件被专门拦截先发出cancel事件再由上层执行关闭动作。源码里还通过useRetainedPopup的回调在关闭弹出层时同时发出cancel与openChange(false)确保取色器被 Escape 或外部点击关闭时消费者能拿到一致的取消语义。这也是取消先于关闭这一时间顺序的来源。四、cancel 与 BindableValue变量解绑与涂色更新的原子回滚官方文档特别强调了一个设计细节cancelfires before an Escape close, allowing BindableValue consumers to roll back a variable detach and paint update together. cancel在 Escape 关闭之前触发使BindableValue消费者能够把变量解绑与涂色更新作为一个整体回滚。翻译成实际场景就是在 OpenPencil 编辑器中填充/描边颜色可能绑定着设计变量variable。当用户打开取色器、临时把变量**解绑detach**并就地调色此时若按下 Escape 表示取消本次操作编辑器需要把两件事同时还原恢复之前绑定的变量引用撤销 detach撤销临时产生的颜色改动撤销 paint update。ColorPickerRoot的cancel事件正是这个原子回滚的触发点——它在关闭发生前同步发出让BindableValue的消费者有机会先执行回滚再让弹出层关闭。相关 API 见官方文档 BindableValue。值得注意的是打开取色器或仅仅聚焦它并不会产生任何颜色更新事件——update只在你真正改动了颜色后才触发。这个约束保证了只看不动不会污染场景图的撤销栈。五、协作链路ColorPickerRoot ↔ ColorInputRoot ↔ useColorModel单个ColorPickerRoot并不负责 Hex 解析或 HSV 通道换算它的左右手是ColorInputRoot与useColorModel。1. ColorInputRootHex 输入的 headless 助手ColorInputRoot 与ColorPickerRoot一样是无样式组件源码在 packages/vue/src/primitives/ColorPicker/ColorInputRoot.vue它做的事情是从Color派生出一个可展示的hex 字符串model.hex.value暴露两个更新助手updateFromHex(value)十六进制输入保留当前 alpha与updateColor(color)整色更新通过editableprop 告知调用方当前值是否可编辑。把它放进ColorPickerRoot的默认插槽即可构成弹出面板内嵌 Hex 输入框的取色器ColorPickerRoot :colorcolor updatecolor $event template #default ColorInputRoot :colorcolor updatecolor $event v-slot{ hex, updateFromHex } input :valuehex inputupdateFromHex(($event.target as HTMLInputElement).value) / /ColorInputRoot /template /ColorPickerRoot2. useColorModel跨色域的响应式颜色内核ColorInputRoot内部实际由 useColorModel 驱动——它是 OpenPencil 提供给自定义取色器的共享颜色状态与转换层接受场景图Color对外暴露 Reka 兼容的rgb/hsl/hsb响应式值以及hex、rekaColor等 computed ref内置格式标识符hex、rgb、hsl、hsb、okhcl类型可扩展支持defaultFormat与受控的format状态可选的OkHCL intent场景图颜色本身只是可渲染的 RGBA无法保留超出色域out-of-gamut的 OkHCL 来源因此useColorModel允许通过okhcl与onUpdateOkHCL单独传递/持久化 OkHCL 意图转换与色域映射复用 OpenPencil 基于 culori 的核心颜色 API更新行为有明确约定RGB 用0–255展示、HSL/HSB 饱和度与明度用0–100、OkHCL 明度与 alpha 用0–1、色相在0–360环绕alpha 跨色域转换时保留空操作不触发变更回调。import { ref } from vue import { useColorModel } from open-pencil/vue import type { Color } from open-pencil/scene-graph const color refColor({ r: 0.25, g: 0.5, b: 0.9, a: 1 }) const model useColorModel({ color, onUpdate: (nextColor) { color.value nextColor }, }) model.updateHSLChannel(s, 72) // 改饱和度 model.updateAlpha(0.8) // 改透明度 model.updateHex(#6F8FE0) // Hex 输入保留 alpha3. useOkHCL需要持久化到编辑器时才使用如果上述取色结果需要写入 OpenPencil 场景图带撤销应改用编辑器感知的适配器 useOkHCL它按 fill/stroke 读取已存储的 OkHCL 意图、更新节点并进撤销栈、报告预览色域信息{ previewColorSpace, clipped }并记忆每个填充/描边选中的字段格式。import { useOkHCL } from open-pencil/vue const okhcl useOkHCL() const color okhcl.getFillOkHCLColor(node, 0) okhcl.updateFillOkHCL(node, 0, { c: 0.2 }) const preview okhcl.getFillPreviewInfo(node, 0) // { previewColorSpace, clipped }分层关系可以概括为useColorModel与框架/编辑器无关的转换、通道编辑与滑条展示数据ColorInputRoot在useColorModel之上封装 Hex 派生与更新助手ColorPickerRoot在 popover 生命周期之上组合触发器与面板插槽并广播update/openChange/canceluseOkHCL仅当需要把 OkHCL 编辑持久化到 OpenPencil 编辑器时引入。六、在 OpenPencil 编辑器主程序中的实际用法从源码检索看OpenPencil 编辑器主程序在 src/components/ColorPicker/ColorPicker.vue 中引用了ColorPickerRoot并在packages/vue的 SDK 入口packages/vue/src/index.ts中对外导出。也就是说这套 headless 组件既服务于编辑器自带的取色 UI也完整开放给第三方 SDK 使用者——你可以在自己的 Vue 应用中用完全自定义的皮肤实现同款取色交互。一个更贴近生产的最小组合示例把自定义弹层面板替换为你的品牌组件script setup langts import { ref } from vue import type { Color } from open-pencil/scene-graph import { ColorPickerRoot, ColorInputRoot } from open-pencil/vue const color refColor({ r: 0.9, g: 0.2, b: 0.1, a: 1 }) function onCancel() { // 在这里执行 BindableValue 的变量解绑 涂色回滚 console.log(picker cancelled: rollback detach paint) } /script template ColorPickerRoot :colorcolor :ui{ swatch: my-swatch, content: my-panel } updatecolor $event cancelonCancel template #trigger{ style } button :stylestyle classmy-swatch aria-labelPick color / /template template #default{ color: c } div classmy-panel ColorInputRoot :colorc updatecolor $event v-slot{ hex, updateFromHex } input :valuehex inputupdateFromHex(($event.target as HTMLInputElement).value) / /ColorInputRoot /div /template /ColorPickerRoot /template七、相关 API 与延伸阅读ColorPickerRoot不是孤立的组件官方文档列出了三个强关联 API均可从仓库根目录的相对路径查阅ColorInputRootHex 派生与更新助手作为默认插槽内容使用useColorModel跨 RGB/HSL/HSB/OkHCL 的响应式颜色内核useOkHCLOkHCL 意图的编辑器持久化适配器组件 API 总览packages/docs/programmable/sdk/api/components/index.md。对应的可读源码packages/vue/src/primitives/ColorPicker/ColorPickerRoot.vue本文核心packages/vue/src/primitives/ColorPicker/ColorInputRoot.vuepackages/scene-graph/src/primitives.tsColor类型定义src/components/ColorPicker/ColorPicker.vue编辑器主程序内的实际用例小结ColorPickerRoot是 OpenPencil SDK 中逻辑完整、样式全无的取色器根组件它用 reka-ui popover 承载弹出层生命周期用插槽把触发器与面板外观交给调用方用update/openChange/cancel三个事件精确刻画取色交互边界其中cancel的先取消后关闭时序是为BindableValue原子回滚变量解绑与涂色更新而专门设计的。配合ColorInputRoot的 Hex 输入与useColorModel的跨色域换算你可以在完全不依赖 OpenPencil 编辑器 UI 的情况下构建出自有品牌、任意交互形态的专业取色器。赞分享前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载相关推荐OpenPencil 无头色彩选择器原语 ColorPickerRoot 使用指南从插槽组合到交互生命周期OpenPencil 无头色彩选择器原语 ColorPickerRoot 使用指南从插槽组合到交互生命周期 ColorPickerRoot 是 OpenPen前端桌面应用AI 应用MCP 服务Flet SlidePicker 颜色选择器控件详解基于滑块的 RGB/HSV/HSL 取色实战Flet SlidePicker 颜色选择器控件详解基于滑块的 RGB/HSV/HSL 取色实战 SlidePicker 是 Flet 官方扩展包 flet前端跨平台桌面应用移动开发5分钟快速上手BepInEx游戏插件框架完整使用指南5分钟快速上手BepInEx游戏插件框架完整使用指南 BepInEx是一款强大的游戏插件框架专为Unity和.NET游戏设计让普通玩家和技术新手都能轻松为游戏开发插件系统上一篇英雄联盟玩家的终极效率工具League Akari 完整使用指南下一篇React Styleguidist 分节文档实战用 Markdown 内容页content嵌入 JSX 交互式示例创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表