news 2026/9/8 20:03:21

tldraw 专注模式实战:用 updateInstanceState({ isFocusMode: true }) 隐藏默认 UI,只留画布

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
tldraw 专注模式实战:用 updateInstanceState({ isFocusMode: true }) 隐藏默认 UI,只留画布

tldraw 专注模式实战:用 updateInstanceState({ isFocusMode: true }) 隐藏默认 UI,只留画布

【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw

本篇围绕 tldraw 示例库中的「Toggle focus mode」示例展开:如何在编辑器挂载时通过editor.updateInstanceState({ isFocusMode: true })强制开启专注模式,并深入源码说明isFocusMode这一实例状态(instance state)字段的定义、默认值、跨会话保留机制,以及默认 UI 如何通过toggle-focus-mode动作(快捷键Cmd/Ctrl+.和角落退出按钮)响应该标志位。读完你可以掌握在任意 tldraw 应用中以编程方式控制「无干扰画布」体验的完整链路。

示例代码:挂载时开启专注模式

示例文档 README.md 的核心结论只有一句话:专注模式是编辑器实例状态上的一个标志位,用editor.updateInstanceState({ isFocusMode: true })打开,默认 UI 会随之隐藏自身。完整示例组件仅有十几行:

// apps/examples/src/examples/editor-api/focus-mode/FocusModeExample.tsx import { Tldraw } from 'tldraw' import 'tldraw/tldraw.css' export default function FocusModeExample() { return ( <div className="tldraw__editor"> <Tldraw onMount={(editor) => { // [1] editor.updateInstanceState({ isFocusMode: true }) }} /> </div> ) }

示例中的注释 FocusModeExample.tsx 补充了两点关键行为:

  1. updateInstanceState负责设置该标志位;默认 UI 读取它后隐藏除一个小退出按钮之外的所有元素;
  2. 当应用使用了persistenceKey时,这个标志位会作为用户偏好被保留——因此在onMount里设置它,相当于“强制覆盖”历史偏好,确保每次挂载都进入专注模式。

专注模式下 UI 长什么样:源码级的验证

专注模式并非简单地给 DOM 加一个 class,而是条件渲染整棵 UI 树。在 TldrawUi.tsx 中,默认 UI 组件先订阅该标志位:

const isFocusMode = useValue('focus', () => editor.getInstanceState().isFocusMode, [editor])

然后在布局节点上做出分支:

{isFocusMode ? ( <div className="tlui-layout__top"> <TldrawUiButton type="icon" className="tlui-focus-button" title={msg('focus-mode.toggle-focus-mode')} onClick={() => toggleFocus.onSelect('menu')} > <TldrawUiButtonIcon icon="dot" /> </TldrawUiButton> </div> ) : ( // 正常布局:MenuPanel、TopPanel、SharePanel、StylePanel、Toolbar…… )}

可以看到:进入专注模式后,菜单栏、顶栏、分享按钮、样式面板、工具栏等全部不渲染,只剩一个带dot图标的圆形按钮。点击该按钮时调用toggleFocus.onSelect('menu'),即复用与主菜单完全相同的切换动作——这正是示例文档中“focus mode 会在角落留下退出按钮”的由来。

isFocusMode 字段定义:TLInstance 记录的一部分

isFocusMode不是 React 状态,而是存储在TLInstance记录上的字段。该记录代表“单个浏览器标签页的会话状态”,定义于 TLInstance.ts:

export interface TLInstance extends BaseRecord<'instance', TLInstanceId> { // ... isFocusMode: boolean isDebugMode: boolean isToolLocked: boolean // ... }

围绕该字段有三个值得注意的实现细节:

  • 默认值为false:在createInstanceRecordTypewithDefaultProperties中,isFocusMode: false(TLInstance.ts)。因此不调用updateInstanceState时,编辑器不会默认进入专注模式;
  • 校验器为T.boolean:实例状态的写入会经过该 validator 校验(TLInstance.ts),保证该字段只能是布尔值;
  • 跨会话保留策略shouldKeyBePreservedBetweenSessions显式声明isFocusMode: true, // preserves because it's a user preference(TLInstance.ts)。

最后一点解释了示例注释中的persistenceKey行为:当快照在浏览器会话之间加载(即配置了持久化)时,只有被标记为true的实例字段才会被恢复,其余如cursoropenMenusisHoveringCanvas等临时状态一律重置。也就是说,用户自己切换过的专注模式会在下次打开页面时“记忆”下来;而示例在onMount中主动置true,正是为了以代码覆盖这份被保留下来的偏好。

默认 UI 的切换路径:toggle-focus-mode 动作

用户在界面上的切换(菜单勾选、快捷键、角落退出按钮)最终都汇聚到同一个动作定义。该动作位于默认 UI 的动作集合中(actions.tsx):

{ id: 'toggle-focus-mode', label: { default: 'action.toggle-focus-mode', menu: 'action.toggle-focus-mode.menu', }, readonlyOk: true, kbd: 'cmd+.,ctrl+.', checkbox: true, onSelect(source) { // this needs to be deferred because it causes the menu // UI to unmount which puts us in a dodgy state editor.timers.requestAnimationFrame(() => { editor.run(() => { trackEvent('toggle-focus-mode', { source }) helpers.clearDialogs() helpers.clearToasts() editor.updateInstanceState({ isFocusMode: !editor.getInstanceState().isFocusMode }) }) }) }, },

这里有几个实现细节值得留意:

  1. 快捷键kbd: 'cmd+.,ctrl+.'对应示例文档中提到的Cmd/Ctrl+.,在 macOS 上按Cmd+.、Windows/Linux 上按Ctrl+.即可切换;
  2. 延迟一帧执行:注释解释了原因——切换会使菜单 UI 卸载,若不通过requestAnimationFrame推迟,会让 UI 处于不稳定状态。这属于从源码结构可直接确认的防御性写法;
  3. 清空对话框与 toastclearDialogs()/clearToasts()保证进入专注模式时不残留悬浮 UI,这与“只留画布”的语义一致;
  4. 只读模式可用readonlyOk: true意味着即使编辑器处于只读状态,专注模式也可以切换;
  5. 取反切换:动作内部读取当前值后取反(!editor.getInstanceState().isFocusMode),因此菜单项可以做成复选框样式。菜单里的复选框项由 ToggleFocusModeItem 提供,它同样用useValue('isFocusMode', ...)订阅状态来决定勾选态。

读写该状态:getInstanceState 与 updateInstanceState

从示例和源码可以看出读写该标志位的一对 API:

  • editor.getInstanceState().isFocusMode,返回当前布尔值;
  • editor.updateInstanceState({ isFocusMode: ... }),传入部分更新即可。

updateInstanceState定义在 Editor.ts,内部以history: 'ignore'为默认委托给_updateInstanceState——即实例状态的更新默认不产生历史(撤销点)。这与实例状态“会话级、非文档内容”的定位一致:撤销Cmd+Z不会还原 UI 的显示状态。

在你的应用中,任何需要随专注模式联动逻辑的地方,都可以直接读取该字段,例如:

editor.onMount((editor) => { const inFocus = editor.getInstanceState().isFocusMode // 根据 inFocus 调整外部布局、埋点或键盘拦截逻辑 })

小结

  • 专注模式 =TLInstance上的布尔字段isFocusMode,默认false,被标记为跨会话保留的用户偏好;
  • 编程开启:onMount中调用editor.updateInstanceState({ isFocusMode: true }),可覆盖持久化偏好;
  • 默认 UI 在该标志位为true时只渲染角落的 dot 退出按钮;切换动作toggle-focus-mode绑定Cmd/Ctrl+.,内部延迟一帧执行并清理对话框与 toast;
  • 实例状态更新默认不进历史,专注模式的切换不会影响撤销栈。

参考文件:FocusModeExample.tsx、TLInstance.ts、actions.tsx、TldrawUi.tsx、menu-items.tsx、Editor.ts。

【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 20:03:20

从Isaac Gym到RK3566:双足机器人强化学习策略的完整部署实践

先交代一下背景&#xff1a;Microduck是一台25厘米左右的小型双足机器人&#xff0c;最初是在英伟达GPU上用强化学习在仿真里练出来的&#xff0c;整套训练流程跑在Isaac Gym这类环境里。这篇文章记录的是我把它从“GPU上的数字模型”搬上RK3566实机&#xff08;泰山派&#xf…

作者头像 李华
网站建设 2026/9/8 20:02:11

WOA-CNN-LSTM-Attention风电功率预测模型详解与Matlab复现

简介&#xff1a;面向风电功率预测研究与应用&#xff0c;提供一套复现SCI一区论文方法的Matlab源码&#xff0c;基于鲸鱼算法&#xff08;WOA&#xff09;优化CNN-LSTM-Attention模型&#xff0c;适合需要开展算法对比、学术复现或毕业设计的科研人员与在校学生。代码采用模块…

作者头像 李华
网站建设 2026/9/8 20:00:44

YOLOv5动物检测落地:2000张图构建最小可行闭环

简介&#xff1a;本资源是一套开箱即用的YOLOv5动物目标检测实战套件&#xff0c;面向深度学习初学者与计算机视觉入门开发者&#xff0c;聚焦多类别动物识别场景&#xff0c;有效降低目标检测项目从数据准备到模型部署的学习门槛。压缩包共3923个文件&#xff0c;含1959张标注…

作者头像 李华
网站建设 2026/9/8 19:56:18

从 CI 失败到可合并:深入解析 Remotion 的 pr-ready Agent 技能

从 CI 失败到可合并&#xff1a;深入解析 Remotion 的 pr-ready Agent 技能 【免费下载链接】remotion &#x1f3a5; Make videos programmatically with React 项目地址: https://gitcode.com/GitHub_Trending/re/remotion 本篇以 Remotion 单仓库中的 pr-ready 技能定…

作者头像 李华