From e631f88cc0afe711275f9103a9697ba91f9211f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 5 Oct 2026 12:59:33 -0400 Subject: [PATCH 01/11] Overlays: review r1 fixes --- alert_dialog.go | 26 +-- alert_dialog_test.go | 22 ++ context_menu.go | 6 +- context_menu_test.go | 15 +- dialog.go | 9 +- dialog_test.go | 48 +++++ docs/components/081-dialog.md | 5 +- docs/components/082-alert-dialog.md | 12 +- docs/components/083-drawer.md | 6 +- docs/components/084-popover.md | 5 +- docs/components/085-tooltip.md | 3 +- docs/components/086-hover-card.md | 5 +- docs/components/087-dropdown-menu.md | 3 +- docs/components/088-context-menu.md | 4 +- docs/components/089-popconfirm.md | 4 +- docs/components/090-overlay.md | 5 +- drawer.go | 12 +- dropdown_menu.go | 5 +- dropdown_menu_test.go | 36 +++- examples/gallery/pages_overlay.go | 48 +++-- hover_card.go | 63 ++---- hover_card_test.go | 142 +++++++++---- overlay.go | 10 +- overlay_layers.go | 103 +++++++++ overlay_snapshot_test.go | 65 ++++++ overlay_test.go | 196 +++++++++++++----- popconfirm.go | 44 ++-- popconfirm_test.go | 20 ++ popover.go | 19 +- popover_test.go | 22 ++ popup_menu.go | 30 +-- .../snapshots/darwin/context_menu-dark.png | Bin 12391 -> 12672 bytes .../snapshots/darwin/context_menu-light.png | Bin 13791 -> 14075 bytes .../snapshots/darwin/dropdown_menu-dark.png | Bin 11343 -> 15542 bytes .../snapshots/darwin/dropdown_menu-light.png | Bin 12878 -> 18539 bytes testdata/snapshots/darwin/hover_card-dark.png | Bin 11983 -> 12100 bytes .../snapshots/darwin/hover_card-light.png | Bin 13494 -> 13592 bytes testdata/snapshots/darwin/tooltip-dark.png | Bin 4404 -> 4912 bytes testdata/snapshots/darwin/tooltip-light.png | Bin 4513 -> 5054 bytes tooltip.go | 9 +- tooltip_test.go | 46 ++-- 41 files changed, 770 insertions(+), 278 deletions(-) create mode 100644 overlay_layers.go create mode 100644 overlay_snapshot_test.go diff --git a/alert_dialog.go b/alert_dialog.go index 1f619d1..e3268a2 100644 --- a/alert_dialog.go +++ b/alert_dialog.go @@ -31,17 +31,18 @@ type AlertDialogResult struct { // alertDialogState is the typed confirmation, kept while the alert shows. type alertDialogState struct{ typed string } -// AlertDialog asks to confirm a destructive action while *open is true. -// Cancel takes the focus, the backdrop ignores clicks, Escape cancels, -// and Enter never confirms before ConfirmText is typed. +// AlertDialog confirms a destructive action; Cancel has the focus. func AlertDialog(c *ui.Context, open *bool, opts AlertDialogOptions) AlertDialogResult { if opts.Title == "" { panic("mujica: AlertDialog needs a Title") } var res AlertDialogResult + site, focus := overlaySite(c) if !*open { + focus.closed(c, site) return res } + overlayLayer(c, open) k := Tokens(c) u := Density(c).Unit() confirmLabel, cancelLabel := opts.ConfirmLabel, opts.CancelLabel @@ -52,7 +53,7 @@ func AlertDialog(c *ui.Context, open *bool, opts AlertDialogOptions) AlertDialog cancelLabel = msg(c, "alert_dialog.cancel") } shown, backClicked := true, false - ui.DialogBase(c, &shown, func(back, panel *ui.Element) { + panel := ui.DialogBase(c, &shown, func(back, panel *ui.Element) { backClicked = back.Clicked() st := ui.Local(panel, "mujica.alert", func() alertDialogState { return alertDialogState{} }) p := overlayEnter(c, panel) @@ -62,15 +63,16 @@ func AlertDialog(c *ui.Context, open *bool, opts AlertDialogOptions) AlertDialog ui.Row(c).Gap(u * 3).AlignItems(ui.Start).Shrink(0).Children(func() { ui.Icon(c, icons.Must("triangle-alert")).Size(22, 22).TextColor(k.Danger).Shrink(0).Margin(1, 0, 0, 0) ui.Column(c).Gap(u * 2).Grow(1).Children(func() { - ui.Text(c, opts.Title).Font(theme.SerifFont).FontSize(theme.H3Size).FontWeight(600) + ui.Text(c, opts.Title).Font(theme.SerifFont).FontSize(FontSize(c, theme.H3Size)).FontWeight(600) if opts.Description != "" { ui.Text(c, opts.Description).TextColor(k.TextMuted) } }) }) - submitted := opts.ConfirmText != "" && alertDialogTyped(c, st, opts.ConfirmText) + if opts.ConfirmText != "" { + alertDialogTyped(c, st, opts.ConfirmText) + } unlocked := opts.ConfirmText == "" || st.typed == opts.ConfirmText - res.Confirmed = submitted && unlocked dialogActions(c, func() { if Button(c, cancelLabel, ButtonOptions{Variant: Secondary}).AutoFocus().Clicked() { res.Cancelled = true @@ -80,6 +82,7 @@ func AlertDialog(c *ui.Context, open *bool, opts AlertDialogOptions) AlertDialog } }) }) + focus.shown(panel) if !shown && !backClicked { res.Cancelled = true // Escape } @@ -93,18 +96,15 @@ func AlertDialog(c *ui.Context, open *bool, opts AlertDialogOptions) AlertDialog return res } -// alertDialogTyped builds the confirmation field and reports Enter in it. -func alertDialogTyped(c *ui.Context, st *alertDialogState, want string) bool { +// alertDialogTyped builds the confirmation field; Enter in it never confirms, even mid-composition. +func alertDialogTyped(c *ui.Context, st *alertDialogState, want string) { k := Tokens(c) d := Density(c) prompt := fmt.Sprintf(msg(c, "alert_dialog.type_to_unlock"), want) - submitted := false ui.Column(c).Gap(d.Unit()).Shrink(0).Children(func() { - ui.Text(c, prompt).FontSize(theme.CaptionSize).TextColor(k.TextMuted) + ui.Text(c, prompt).FontSize(FontSize(c, theme.CaptionSize)).TextColor(k.TextMuted) in := ui.TextInputBase(c, &st.typed).Label(prompt).MinHeight(d.ControlHeight()).Padding(0, d.Unit()*3). Radius(theme.ControlRadius).Background(k.Surface).Border(theme.BorderWidth, k.ControlBorder) internal.Ring(in, k.Focus, theme.ControlRadius) - submitted = in.Submitted() }) - return submitted } diff --git a/alert_dialog_test.go b/alert_dialog_test.go index 0d23111..1a7651b 100644 --- a/alert_dialog_test.go +++ b/alert_dialog_test.go @@ -86,11 +86,33 @@ func TestAlertDialogConfirmTextGatesEnter(t *testing.T) { } tt.Type("e") tt.Key(0, ui.KeyEnter) + if a.confirmed != 0 || !a.open { + t.Fatalf("Enter in the field confirmed: %d", a.confirmed) + } + tt.Key(0, ui.KeyTab) + tt.Key(0, ui.KeyTab) + if !tt.Focused("Delete") { + t.Fatal("Delete not reachable once unlocked") + } + tt.Key(0, ui.KeyEnter) if a.confirmed != 1 || a.open { t.Fatalf("typed target: confirmed %d open %v", a.confirmed, a.open) } } +// MyGo commits a composition on Enter and then handles the key (ui/editor.go:688). +func TestAlertDialogEnterDuringCompositionDoesNotConfirm(t *testing.T) { + a, tt := newAlertApp(AlertDialogOptions{ConfirmText: "archive"}) + if err := tt.Click("Type “archive” to confirm"); err != nil { + t.Fatal(err) + } + tt.Compose("archive", 7) + tt.Key(0, ui.KeyEnter) + if a.confirmed != 0 || !a.open { + t.Fatalf("Enter while composing confirmed: %d", a.confirmed) + } +} + func TestAlertDialogSnapshot(t *testing.T) { snapshot(t, "alert_dialog", 560, 320, func(c *ui.Context) { open := true diff --git a/context_menu.go b/context_menu.go index 468029c..5644a06 100644 --- a/context_menu.go +++ b/context_menu.go @@ -17,11 +17,7 @@ type contextMenuState struct { x, y float32 } -// ContextMenu gives target an in-window menu that build fills. A secondary -// click opens it at the pointer; the menu key or Shift+F10, while the focus -// is in target, opens it below target. It flips to stay in the window, and -// the focus returns on close. target must be a container: the menu adds an -// anchor child to it, and takes its HandleInput. It returns target. +// ContextMenu gives the container target an in-window menu at the pointer or below the focus. func ContextMenu(c *ui.Context, target *ui.Element, opts ContextMenuOptions, build func(m *PopupMenu)) *ui.Element { if target == nil { panic("mujica: ContextMenu needs a target") diff --git a/context_menu_test.go b/context_menu_test.go index c14c3c1..d767599 100644 --- a/context_menu_test.go +++ b/context_menu_test.go @@ -92,14 +92,19 @@ func TestContextMenuDisabled(t *testing.T) { } func TestContextMenuSnapshot(t *testing.T) { - snapshot(t, "context_menu", 460, 320, func(c *ui.Context) { - a := &menuApp{} + a := &menuApp{} + overlaySnapshot(t, "context_menu", 460, 320, func(c *ui.Context) { ui.Column(c).Padding(20).Children(func() { row := ui.Row(c).Height(36).FillWidth().Padding(0, 12).AlignItems(ui.Center).Background(Tokens(c).Selection) row.Children(func() { ui.Text(c, "Letter to the Countess") }) - anchor := ui.Box(c).Absolute().Left(140).Top(48).Size(1, 1) - open := true - popupMenuOpen(c, anchor, &open, a.build) + ContextMenu(c, row, ContextMenuOptions{}, a.build) }) + }, func(tt *ui.Tester) { + tt.RightClickAt(160, 40) + r, ok := tt.Find("Pinned") + if !ok { + t.Fatal("menu did not open") + } + tt.Move(r.X+4, r.Y+4) // hover highlight on Pinned }) } diff --git a/dialog.go b/dialog.go index 486e4f1..4aa7ed2 100644 --- a/dialog.go +++ b/dialog.go @@ -28,15 +28,17 @@ type DialogOptions struct { HideClose bool } -// Dialog shows a modal dialog while *open is true. It traps the focus, -// makes the window inert and gives the focus back to the opener on close. +// Dialog shows a modal dialog while *open is true, trapping and then restoring the focus. func Dialog(c *ui.Context, open *bool, opts DialogOptions, content func()) *ui.Element { if opts.Title == "" { panic("mujica: Dialog needs a Title") } + site, focus := overlaySite(c) if !*open { + focus.closed(c, site) return nil } + overlayLayer(c, open) k := Tokens(c) shown, backClicked, closed := true, false, false panel := ui.DialogBase(c, &shown, func(back, panel *ui.Element) { @@ -56,6 +58,7 @@ func Dialog(c *ui.Context, open *bool, opts DialogOptions, content func()) *ui.E dialogActions(c, opts.Actions) } }) + focus.shown(panel) switch { case closed: slog.Debug("mujica: dialog close", "by", "button") @@ -106,7 +109,7 @@ func dialogHeader(c *ui.Context, title, description string, decorated, closable clicked := false ui.Column(c).Gap(u).Shrink(0).Children(func() { ui.Row(c).Gap(u * 3).AlignItems(ui.Start).Children(func() { - ui.Text(c, title).Font(theme.SerifFont).FontSize(theme.H3Size).FontWeight(600).Grow(1) + ui.Text(c, title).Font(theme.SerifFont).FontSize(FontSize(c, theme.H3Size)).FontWeight(600).Grow(1) if closable { clicked = dialogCloseButton(c, msg(c, closeKey)).Clicked() } diff --git a/dialog_test.go b/dialog_test.go index 3706ea7..5546998 100644 --- a/dialog_test.go +++ b/dialog_test.go @@ -2,6 +2,7 @@ package mujica import ( "testing" + "time" "github.com/egoist/mygo/ui" @@ -173,6 +174,53 @@ func dialogSnapshotView(d theme.Density, decorated bool) func(c *ui.Context) { } } +func TestDialogEscapeHidesTooltipBeforeClosing(t *testing.T) { + open := true + tt := ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + Dialog(c, &open, DialogOptions{Title: "Outer", HideClose: true}, func() { + b := Button(c, "Seal", ButtonOptions{}) + Tooltip(c, b, "Seal with wax", TooltipOptions{Delay: time.Millisecond}) + }) + }, 600, 400) + tt.Key(0, ui.KeyTab) // keyboard focus on Seal + if !overlayUntil(tt, func() bool { return tt.HasText("Seal with wax") }) { + t.Fatal("tooltip did not show in the dialog") + } + tt.Key(0, ui.KeyEscape) + if tt.HasText("Seal with wax") || !open { + t.Fatalf("first Escape: tip shown %v, dialog open %v", tt.HasText("Seal with wax"), open) + } + tt.Key(0, ui.KeyEscape) + if open { + t.Fatal("second Escape did not close the dialog") + } +} + +func TestDialogFocusFallsBackWhenOpenerIsGone(t *testing.T) { + open, gone := false, false + tt := ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + ui.Column(c).Children(func() { + Button(c, "First", ButtonOptions{}) + if !gone && Button(c, "Open", ButtonOptions{}).Clicked() { + open, gone = true, true + } + Dialog(c, &open, DialogOptions{Title: "Gone"}, nil) + Button(c, "Next", ButtonOptions{}) + }) + }, 600, 400) + _ = tt.Click("Open") + tt.Key(0, ui.KeyEscape) + if open { + t.Fatal("Escape did not close") + } + tt.Key(0, ui.KeyTab) + if !tt.Focused("Next") { + t.Fatal("focus did not fall back to the dialog's place in the window") + } +} + func TestDialogSnapshot(t *testing.T) { snapshot(t, "dialog", 560, 360, dialogSnapshotView(theme.Default, true)) snapshot(t, "dialog-compact", 560, 360, dialogSnapshotView(theme.Compact, false)) diff --git a/docs/components/081-dialog.md b/docs/components/081-dialog.md index 679d06d..73afded 100644 --- a/docs/components/081-dialog.md +++ b/docs/components/081-dialog.md @@ -71,5 +71,6 @@ ui.Render(view, 400, 300, 1) ## 限制 -- 关闭后焦点回到打开时的控件;若该控件已不存在,MyGo 不回退到父级(`ui/scope.go:137` restoreFocus 只恢复原控件),焦点为空,再按 Tab 从窗口开头开始。 -- 没有关闭过渡:MyGo 在 `*open` 变为 false 的下一帧即移除浮层元素,`Transition` 的 Exit 需要父元素保留,而浮层根只在有浮层时存在。 +- 输入法组合期间按 Escape 仍会关闭浮层:MyGo 没有公开组合状态(`ui/editor.go:73` 的 `compose` 未导出,组合事件不交给带编辑器元素的 `HandleInput`,`ui/input.go:689`),编辑器也不接收 Escape(`ui/editor.go:163`),macOS 上按键先于输入法送达应用(`internal/darwin/surface.go:704`)。 +- 关闭后焦点优先由 MyGo 还给打开者;打开者已消失、焦点落空时,焦点停在组件调用处的不可见占位元素上,Tab 从这里继续。不能回到打开者的父级:MyGo 不公开当前焦点或打开者(`ui/scope.go:123`、`ui/scope.go:137`)。 +- 没有关闭过渡:`*open` 变为 false 的下一帧浮层元素即被移除。 diff --git a/docs/components/082-alert-dialog.md b/docs/components/082-alert-dialog.md index 40c2a18..b352f42 100644 --- a/docs/components/082-alert-dialog.md +++ b/docs/components/082-alert-dialog.md @@ -2,7 +2,7 @@ ## 用途 -确认危险操作。默认聚焦“取消”,点击遮罩无效,Escape 等同取消;可要求先输入目标名称,未确认目标前 Enter 不会执行。 +确认危险操作。默认聚焦“取消”,点击遮罩无效,Escape 等同取消;可要求先输入目标名称,未输入前确认按钮禁用;输入框中的 Enter 从不确认。 ## 最小示例 @@ -46,7 +46,7 @@ ui.Render(view, 400, 300, 1) ## 事件 -- `Confirmed`:点击确认,或在输入框内按 Enter 且目标已匹配。 +- `Confirmed`:点击确认,或焦点在已解锁的确认按钮上按 Enter / Space。 - `Cancelled`:点击取消、在取消上按 Enter / Space、或按 Escape。 - 点击遮罩不产生事件。 @@ -55,11 +55,13 @@ ui.Render(view, 400, 300, 1) | 按键 | 行为 | | --- | --- | | 打开时 | 焦点在“取消”。 | -| Enter | 触发聚焦的按钮;在输入框中只有目标匹配时确认。 | +| Enter | 触发聚焦的按钮;在输入框中不确认,Tab 到确认按钮后再按。 | | Escape | 取消并关闭。 | | Tab | 在对话框内循环。 | ## 限制 -- 取消按钮的焦点由 `AutoFocus` 给出,打开时不显示焦点环(MyGo 只在键盘移动焦点后设置可见焦点,`ui/input.go:868`);按 Tab 后显示。 -- 不替代系统原生警示框;需要系统样式时用 MyGo 的桌面对话框。 +- 输入框中的 Enter 从不确认,必须用 Tab 移到确认按钮:MyGo 在 Enter 时先提交输入法组合再处理按键(`ui/editor.go:688`),而组合状态不公开,无法区分“提交组合”的 Enter。 +- 输入法组合期间按 Escape 仍会关闭浮层:MyGo 没有公开组合状态(`ui/editor.go:73` 的 `compose` 未导出,组合事件不交给带编辑器元素的 `HandleInput`,`ui/input.go:689`),编辑器也不接收 Escape(`ui/editor.go:163`),macOS 上按键先于输入法送达应用(`internal/darwin/surface.go:704`)。 +- 关闭后焦点优先由 MyGo 还给打开者;打开者已消失、焦点落空时,焦点停在组件调用处的不可见占位元素上,Tab 从这里继续。不能回到打开者的父级:MyGo 不公开当前焦点或打开者(`ui/scope.go:123`、`ui/scope.go:137`)。 +- 取消按钮的焦点由 `AutoFocus` 给出,打开时不显示焦点环(`ui/input.go:868`);按 Tab 后显示。 diff --git a/docs/components/083-drawer.md b/docs/components/083-drawer.md index dce31ee..5f2a080 100644 --- a/docs/components/083-drawer.md +++ b/docs/components/083-drawer.md @@ -51,5 +51,7 @@ ui.Render(view, 400, 300, 1) ## 限制 -- 非模态抽屉不在打开时移动焦点,关闭时也不自动恢复焦点:MyGo 记录与恢复打开者的 `openOverlay` 不公开(`ui/scope.go:123`),也没有读取当前焦点的公开接口。 -- 非模态抽屉的 Escape 是窗口级快捷键,优先级最低;同时打开多个非模态浮层时由先构建的那个响应。 +- 输入法组合期间按 Escape 仍会关闭浮层:MyGo 没有公开组合状态(`ui/editor.go:73` 的 `compose` 未导出,组合事件不交给带编辑器元素的 `HandleInput`,`ui/input.go:689`),编辑器也不接收 Escape(`ui/editor.go:163`),macOS 上按键先于输入法送达应用(`internal/darwin/surface.go:704`)。 +- Escape 只关闭最上层的 MujicaUI 浮层(窗口内按打开顺序记录)。MyGo 自带的 `ui.Popover`、`ui.Select` 弹层不在这份记录中;它们打开在非模态 MujicaUI 浮层之上时,Escape 可能先关闭下面的 MujicaUI 浮层。 +- 关闭后焦点优先由 MyGo 还给打开者;打开者已消失、焦点落空时,焦点停在组件调用处的不可见占位元素上,Tab 从这里继续。不能回到打开者的父级:MyGo 不公开当前焦点或打开者(`ui/scope.go:123`、`ui/scope.go:137`)。 +- 非模态抽屉打开时不移动焦点,其内容排在窗口焦点顺序末尾。 diff --git a/docs/components/084-popover.md b/docs/components/084-popover.md index a1cf618..96b43a4 100644 --- a/docs/components/084-popover.md +++ b/docs/components/084-popover.md @@ -50,5 +50,6 @@ ui.Render(view, 400, 300, 1) ## 限制 -- 只支持下方与上方两个位置:位置由 MyGo `PopoverBase` 决定(`ui/widgets.go:689` keepInWindow)。 -- 打开时外部点击只用于关闭,不会传给下方控件:`PopoverBase` 用覆盖整窗的背板接收点击(`ui/base.go:373`)。 +- 打开期间外部点击只用于关闭,不传给下方控件:`PopoverBase` 用覆盖整窗的背板接收点击(`ui/base.go:373`)。 +- Escape 只关闭最上层的 MujicaUI 浮层(窗口内按打开顺序记录)。MyGo 自带的 `ui.Popover`、`ui.Select` 弹层不在这份记录中;它们打开在非模态 MujicaUI 浮层之上时,Escape 可能先关闭下面的 MujicaUI 浮层。 +- 只支持下方与上方两个位置(`ui/widgets.go:689` keepInWindow);宽度不超过窗口,过高时内容滚动。 diff --git a/docs/components/085-tooltip.md b/docs/components/085-tooltip.md index c3137b2..0700c27 100644 --- a/docs/components/085-tooltip.md +++ b/docs/components/085-tooltip.md @@ -41,5 +41,6 @@ ui.Render(view, 400, 300, 1) ## 限制 -- 只在键盘焦点(可见焦点)时显示,鼠标点击获得的焦点不触发,避免点击后弹出提示。 +- Escape 只关闭最上层的 MujicaUI 浮层(窗口内按打开顺序记录)。MyGo 自带的 `ui.Popover`、`ui.Select` 弹层不在这份记录中;它们打开在非模态 MujicaUI 浮层之上时,Escape 可能先关闭下面的 MujicaUI 浮层。 +- 只在键盘焦点(可见焦点)时显示,鼠标点击获得的焦点不触发。 - 不使用 MyGo 的 `Element.Tooltip`:它只跟随指针、不响应焦点(`ui/widgets.go:549`)。 diff --git a/docs/components/086-hover-card.md b/docs/components/086-hover-card.md index 18c1dc5..16701ac 100644 --- a/docs/components/086-hover-card.md +++ b/docs/components/086-hover-card.md @@ -48,5 +48,6 @@ ui.Render(view, 400, 300, 1) ## 限制 -- 键盘打开时卡片由 `PopoverBase` 承载,以便焦点顺序紧跟锚点;此时卡片外的点击只用于关闭(`ui/base.go:373`)。指针打开时卡片不拦截窗口其余部分。 -- 指针打开时卡片元素在窗口焦点顺序的末尾。 +- 卡片由 `PopoverBase` 承载,使焦点顺序紧跟锚点,在 Dialog 内也属于对话框的焦点范围;代价是打开期间外部点击只用于关闭,不传给下方控件:`PopoverBase` 用覆盖整窗的背板接收点击(`ui/base.go:373`)。 +- 指针在卡片外但焦点仍在卡片内时卡片保持打开,点击外部或按 Escape 关闭。 +- Escape 只关闭最上层的 MujicaUI 浮层(窗口内按打开顺序记录)。MyGo 自带的 `ui.Popover`、`ui.Select` 弹层不在这份记录中;它们打开在非模态 MujicaUI 浮层之上时,Escape 可能先关闭下面的 MujicaUI 浮层。 diff --git a/docs/components/087-dropdown-menu.md b/docs/components/087-dropdown-menu.md index 605c7a7..6eb6bad 100644 --- a/docs/components/087-dropdown-menu.md +++ b/docs/components/087-dropdown-menu.md @@ -72,4 +72,5 @@ ui.Render(view, 400, 300, 1) ## 限制 - MyGo 没有 menu / menuitem 无障碍角色(`ui/access.go:22` Role 列表),菜单面板报告为 popup,普通项为 button,勾选项为 checkbox,触发按钮为 menu button。 -- 菜单打开期间外部点击只用于关闭(`ui/base.go:373`)。 +- 打开期间外部点击只用于关闭,不传给下方控件:`PopoverBase` 用覆盖整窗的背板接收点击(`ui/base.go:373`)。 +- Escape 只关闭最上层的 MujicaUI 浮层(窗口内按打开顺序记录)。MyGo 自带的 `ui.Popover`、`ui.Select` 弹层不在这份记录中;它们打开在非模态 MujicaUI 浮层之上时,Escape 可能先关闭下面的 MujicaUI 浮层。 diff --git a/docs/components/088-context-menu.md b/docs/components/088-context-menu.md index b37874d..f4f0117 100644 --- a/docs/components/088-context-menu.md +++ b/docs/components/088-context-menu.md @@ -51,5 +51,7 @@ ui.Render(view, 400, 300, 1) ## 限制 - `target` 必须是容器:菜单会向它追加一个不可见的定位子元素,文字元素不能有非文字子元素(MyGo 会 panic)。 -- 菜单通过 `target.HandleInput` 接收右键按下,因此会替换调用方在同一元素上设置的 `HandleInput`(MyGo 每个元素只保存一个处理函数,`ui/handler.go:73`)。 +- 菜单通过 `target.HandleInput` 接收右键按下,因此会替换调用方在同一元素上设置的 `HandleInput`(`ui/handler.go:73`)。 - 不使用 MyGo 的 `Element.ContextMenu`:那是系统菜单,PRD 不允许把它当作哥特样式菜单。 +- 打开期间外部点击只用于关闭,不传给下方控件:`PopoverBase` 用覆盖整窗的背板接收点击(`ui/base.go:373`)。 +- Escape 只关闭最上层的 MujicaUI 浮层(窗口内按打开顺序记录)。MyGo 自带的 `ui.Popover`、`ui.Select` 弹层不在这份记录中;它们打开在非模态 MujicaUI 浮层之上时,Escape 可能先关闭下面的 MujicaUI 浮层。 diff --git a/docs/components/089-popconfirm.md b/docs/components/089-popconfirm.md index 7998d35..caea581 100644 --- a/docs/components/089-popconfirm.md +++ b/docs/components/089-popconfirm.md @@ -55,5 +55,5 @@ ui.Render(view, 400, 300, 1) ## 限制 -- 非模态:不屏蔽窗口,但外部点击只用于取消,不传给下方控件(`ui/base.go:373`)。 -- 位置只有下方与上方(`ui/widgets.go:689`)。 +- 打开期间外部点击只用于关闭,不传给下方控件:`PopoverBase` 用覆盖整窗的背板接收点击(`ui/base.go:373`)。 +- 位置只有下方与上方(`ui/widgets.go:689`);宽度不超过窗口,说明过长时滚动,按钮始终可见。 diff --git a/docs/components/090-overlay.md b/docs/components/090-overlay.md index 053a732..3aac2c8 100644 --- a/docs/components/090-overlay.md +++ b/docs/components/090-overlay.md @@ -46,6 +46,7 @@ Escape 与(模态时)背景点击把 `*open` 设为 false。 ## 限制 -- 非模态覆盖层的 Escape 是窗口级快捷键(MyGo 浮层专用快捷键 `overlayShortcut` 不公开,`ui/scope.go:109`),同时打开多个非模态浮层时由先构建的那个响应。 -- 非模态覆盖层关闭时不自动恢复焦点(`ui/scope.go:123` openOverlay 不公开)。 +- 输入法组合期间按 Escape 仍会关闭浮层:MyGo 没有公开组合状态(`ui/editor.go:73` 的 `compose` 未导出,组合事件不交给带编辑器元素的 `HandleInput`,`ui/input.go:689`),编辑器也不接收 Escape(`ui/editor.go:163`),macOS 上按键先于输入法送达应用(`internal/darwin/surface.go:704`)。 +- Escape 只关闭最上层的 MujicaUI 浮层(窗口内按打开顺序记录)。MyGo 自带的 `ui.Popover`、`ui.Select` 弹层不在这份记录中;它们打开在非模态 MujicaUI 浮层之上时,Escape 可能先关闭下面的 MujicaUI 浮层。 +- 关闭后焦点优先由 MyGo 还给打开者;打开者已消失、焦点落空时,焦点停在组件调用处的不可见占位元素上,Tab 从这里继续。不能回到打开者的父级:MyGo 不公开当前焦点或打开者(`ui/scope.go:123`、`ui/scope.go:137`)。 - 非模态面板首帧尚未测量尺寸,该帧透明,下一帧定位后淡入。 diff --git a/drawer.go b/drawer.go index 5897a86..dee05e8 100644 --- a/drawer.go +++ b/drawer.go @@ -22,8 +22,7 @@ const ( type DrawerOptions struct { Title string Side DrawerSide - // Size is the width (left, right) or height (top, bottom): 360 or 280 DIPs when zero. - // It is kept between 160 DIPs and 90% of the window. + // Size is the width or height (360 or 280 when zero), kept within 160 DIPs and 90% of the window. Size float32 // NonModal leaves the window usable and the focus free. NonModal bool @@ -31,8 +30,7 @@ type DrawerOptions struct { Actions func() } -// Drawer shows a panel along a window edge while *open is true. A modal -// drawer traps the focus and restores it on close; Escape closes either kind. +// Drawer shows a panel along a window edge while *open is true; Escape closes it. func Drawer(c *ui.Context, open *bool, opts DrawerOptions, content func()) *ui.Element { if opts.Title == "" { panic("mujica: Drawer needs a Title") @@ -43,7 +41,9 @@ func Drawer(c *ui.Context, open *bool, opts DrawerOptions, content func()) *ui.E if opts.Size < 0 { panic("mujica: Drawer Size is negative") } + site, focus := overlaySite(c) if !*open { + focus.closed(c, site) return nil } k := Tokens(c) @@ -69,8 +69,9 @@ func Drawer(c *ui.Context, open *bool, opts DrawerOptions, content func()) *ui.E drawerPlace(c, panel, opts.Side, size*p) panel.Children(func() { body(panel, p) }) }) - escaped = c.Shortcut(0, ui.KeyEscape) + escaped = overlayEscape(c, open) } else { + overlayLayer(c, open) shown := true panel = ui.DialogBase(c, &shown, func(back, panel *ui.Element) { p := overlayEnter(c, panel) @@ -80,6 +81,7 @@ func Drawer(c *ui.Context, open *bool, opts DrawerOptions, content func()) *ui.E }) escaped = !shown } + focus.shown(panel) if closed || escaped { slog.Debug("mujica: drawer close", "escape", escaped) *open = false diff --git a/dropdown_menu.go b/dropdown_menu.go index aafd4cd..87bc084 100644 --- a/dropdown_menu.go +++ b/dropdown_menu.go @@ -15,10 +15,7 @@ type DropdownMenuOptions struct { Label string } -// DropdownMenu is a button opening an in-window menu that build fills. -// Click, Enter, Space or Down opens it with the focus on the first item; -// the arrows, Home and End move, Escape or Tab closes, and the focus -// returns to the button. It returns the button. +// DropdownMenu is a button opening an in-window menu that build fills; it returns the button. func DropdownMenu(c *ui.Context, label string, opts DropdownMenuOptions, build func(m *PopupMenu)) *ui.Element { if build == nil { panic("mujica: DropdownMenu needs a build function") diff --git a/dropdown_menu_test.go b/dropdown_menu_test.go index f6b46b6..394ef59 100644 --- a/dropdown_menu_test.go +++ b/dropdown_menu_test.go @@ -145,14 +145,38 @@ func TestDropdownMenuDisabled(t *testing.T) { } } +func TestDropdownMenuTabInSubmenuClosesMenu(t *testing.T) { + a := &menuApp{} + tt := ui.NewTester(a.view, 500, 400) + tt.Key(0, ui.KeyTab) + tt.Key(0, ui.KeyDown) + tt.Key(0, ui.KeyEnd) + tt.Key(0, ui.KeyRight) + if !tt.Focused("Archive") { + t.Fatal("submenu not entered") + } + tt.Key(0, ui.KeyTab) + if tt.HasText("Archive") || tt.HasText("Rename") { + t.Fatal("Tab in a submenu left the menu open") + } + if !tt.Focused("Actions") { + t.Fatal("focus did not return to the trigger") + } +} + func TestDropdownMenuSnapshot(t *testing.T) { - snapshot(t, "dropdown_menu", 460, 320, func(c *ui.Context) { - a := &menuApp{pinned: true} + a := &menuApp{pinned: true} + overlaySnapshot(t, "dropdown_menu", 520, 320, func(c *ui.Context) { ui.Column(c).Padding(20).AlignItems(ui.Start).Children(func() { - b := ui.ButtonBase(c) - popupMenuTrigger(c, b, "Actions", nil, true) - open := true - popupMenuOpen(c, b, &open, a.build) + DropdownMenu(c, "Actions", DropdownMenuOptions{}, a.build) }) + }, func(tt *ui.Tester) { + tt.Key(0, ui.KeyTab) + tt.Key(0, ui.KeyDown) // opens with the first item focused + tt.Key(0, ui.KeyEnd) + tt.Key(0, ui.KeyRight) // opens Move to, focus ring on Archive + if !tt.Focused("Archive") { + t.Fatal("submenu did not open") + } }) } diff --git a/examples/gallery/pages_overlay.go b/examples/gallery/pages_overlay.go index 2458fd9..e4e650c 100644 --- a/examples/gallery/pages_overlay.go +++ b/examples/gallery/pages_overlay.go @@ -15,7 +15,7 @@ var overlayPages = []page{ {ID: "081", Name: "Dialog", ZhName: "对话框", Category: overlayCategory, Demo: dialogDemo, Code: dialogCode, Keys: "Tab / Shift+Tab 在对话框内循环;Escape 关闭(可关闭此规则);关闭后焦点回到触发按钮。"}, {ID: "082", Name: "AlertDialog", ZhName: "警示对话框", Category: overlayCategory, Demo: alertDialogDemo, Code: alertDialogCode, - Keys: "打开时焦点在取消;Enter 只触发聚焦的按钮;Escape 等同取消;点击遮罩无效。"}, + Keys: "打开时焦点在取消;Enter 只触发聚焦的按钮,输入框中的 Enter 不确认;Escape 等同取消;点击遮罩无效。"}, {ID: "083", Name: "Drawer", ZhName: "抽屉", Category: overlayCategory, Demo: drawerDemo, Code: drawerCode, Keys: "模态:焦点限制在抽屉内并在关闭后恢复;Escape 关闭。非模态:窗口仍可操作,Escape 关闭。"}, {ID: "084", Name: "Popover", ZhName: "弹出框", Category: overlayCategory, Demo: popoverDemo, Code: popoverCode, @@ -25,7 +25,7 @@ var overlayPages = []page{ {ID: "086", Name: "HoverCard", ZhName: "悬停卡片", Category: overlayCategory, Demo: hoverCardDemo, Code: hoverCardCode, Keys: "键盘聚焦锚点后显示,Tab 进入卡片;Escape 关闭。"}, {ID: "087", Name: "DropdownMenu", ZhName: "下拉菜单", Category: overlayCategory, Demo: dropdownMenuDemo, Code: dropdownMenuCode, - Keys: "Enter / Space / ↓ 打开;↑↓ Home End 移动;→ 打开子菜单,← 关闭;Enter 选择;Escape 或 Tab 关闭。"}, + Keys: "Enter / Space / ↓ 打开;↑↓ Home End 移动;→ 打开子菜单,← 关闭;Enter 选择;Escape 关闭最上层;Tab 在任一层关闭整个菜单。"}, {ID: "088", Name: "ContextMenu", ZhName: "右键菜单", Category: overlayCategory, Demo: contextMenuDemo, Code: contextMenuCode, Keys: "右键在指针处打开;焦点在区域内时按 Menu 键或 Shift+F10 在区域下方打开;其余按键同下拉菜单。"}, {ID: "089", Name: "Popconfirm", ZhName: "气泡确认", Category: overlayCategory, Demo: popconfirmDemo, Code: popconfirmCode, @@ -171,10 +171,7 @@ func drawerDemo(c *ui.Context, log func(string)) { log("side = " + s.side) } overlayCheck(c, log, &s.nonModal, "NonModal") - ui.Text(c, fmt.Sprintf("Size %.0f", s.size)) - if ui.StepSlider(c, &s.size, 120, 900, 20).Width(160).Changed() { - log(fmt.Sprintf("size = %.0f", s.size)) - } + overlaySlider(c, log, &s.size, "Size", "DIP", 120, 900, 20) }) if mujica.Button(c, "Open drawer", mujica.ButtonOptions{}).Clicked() { s.open = true @@ -247,10 +244,7 @@ ui.Render(view, 400, 300, 1)` func tooltipDemo(c *ui.Context, log func(string)) { delay := ui.Local(c.Root(), "085", func() float64 { return 500 }) overlayControls(c, func() { - ui.Text(c, fmt.Sprintf("Delay %.0f ms", *delay)) - if ui.StepSlider(c, delay, 100, 1500, 100).Width(160).Changed() { - log(fmt.Sprintf("delay = %.0f ms", *delay)) - } + overlaySlider(c, log, delay, "Delay", "ms", 100, 1500, 100) }) opts := mujica.TooltipOptions{Delay: time.Duration(*delay) * time.Millisecond} ui.Row(c).Gap(12).Children(func() { @@ -276,19 +270,43 @@ const hoverCardCode = `view := func(c *ui.Context) { } ui.Render(view, 400, 300, 1)` +type hoverCardDemoState struct { + shown bool + openDelay, closeDelay, width float64 +} + func hoverCardDemo(c *ui.Context, log func(string)) { - shown := ui.Local(c.Root(), "086", func() bool { return false }) + s := ui.Local(c.Root(), "086", func() hoverCardDemoState { + return hoverCardDemoState{openDelay: 500, closeDelay: 300, width: 280} + }) + overlayControls(c, func() { + overlaySlider(c, log, &s.openDelay, "OpenDelay", "ms", 100, 1500, 100) + overlaySlider(c, log, &s.closeDelay, "CloseDelay", "ms", 100, 1500, 100) + overlaySlider(c, log, &s.width, "Width", "DIP", 200, 420, 20) + }) b := mujica.Button(c, "Lady Sakiko", mujica.ButtonOptions{Variant: mujica.Ghost}) - card := mujica.HoverCard(c, b, mujica.HoverCardOptions{}, func() { + card := mujica.HoverCard(c, b, mujica.HoverCardOptions{ + OpenDelay: time.Duration(s.openDelay) * time.Millisecond, + CloseDelay: time.Duration(s.closeDelay) * time.Millisecond, + Width: float32(s.width), + }, func() { ui.Text(c, "Lady Sakiko").FontWeight(600) ui.Text(c, "Keyboardist of the court; writes the masquerade's score.").TextColor(mujica.Tokens(c).TextMuted) if mujica.Button(c, "Follow", mujica.ButtonOptions{Variant: mujica.Outline}).Clicked() { log("follow") } }) - if (card != nil) != *shown { - *shown = card != nil - log(fmt.Sprintf("card shown = %v", *shown)) + if (card != nil) != s.shown { + s.shown = card != nil + log(fmt.Sprintf("card shown = %v", s.shown)) + } +} + +// overlaySlider is a labeled step slider logging its value. +func overlaySlider(c *ui.Context, log func(string), v *float64, name, unit string, lo, hi, step float64) { + ui.Text(c, fmt.Sprintf("%s %.0f %s", name, *v, unit)) + if ui.StepSlider(c, v, lo, hi, step).Width(140).Changed() { + log(fmt.Sprintf("%s = %.0f %s", name, *v, unit)) } } diff --git a/hover_card.go b/hover_card.go index 6c9d658..030e5e1 100644 --- a/hover_card.go +++ b/hover_card.go @@ -20,17 +20,12 @@ type HoverCardOptions struct { // hoverCardState is what a card keeps between frames while its anchor lives. type hoverCardState struct { - open, dismissed bool - // keyMode keeps the card in the focus order while the keyboard is on it. - keyMode bool - enterAt, leaveAt time.Time - panel ui.Rect + open, dismissed, focusIn bool + enterAt, leaveAt time.Time + panel ui.Rect } -// HoverCard previews content beside anchor while the pointer rests on it or -// it has the keyboard focus. The pointer may move into the card; with the -// keyboard, Tab from the anchor enters it. It closes after CloseDelay once -// neither holds it, or at once on Escape. It returns the card, or nil. +// HoverCard previews content by a hovered or focused anchor; nil while hidden. func HoverCard(c *ui.Context, anchor *ui.Element, opts HoverCardOptions, content func()) *ui.Element { if anchor == nil { panic("mujica: HoverCard needs an anchor") @@ -50,11 +45,11 @@ func HoverCard(c *ui.Context, anchor *ui.Element, opts HoverCardOptions, content keyboard := anchor.FocusVisible() pointer := anchor.Hovered() if st.open { - // The card's layer covers the anchor, so test the pointer by geometry. + // The popover's backdrop covers the anchor, so test the pointer by geometry. x, y, in := c.Root().PointerPosition() pointer = pointer || in && (b.Contains(x, y) || st.panel.Contains(x, y)) } - hot := pointer || keyboard || st.keyMode + hot := pointer || keyboard || st.focusIn if !hot { st.dismissed = false } @@ -87,7 +82,7 @@ func HoverCard(c *ui.Context, anchor *ui.Element, opts HoverCardOptions, content c.After(wait) } else { slog.Debug("mujica: hover_card close") - st.open, st.keyMode, st.leaveAt = false, false, time.Time{} + st.open, st.focusIn, st.leaveAt = false, false, time.Time{} return nil } } @@ -95,43 +90,23 @@ func HoverCard(c *ui.Context, anchor *ui.Element, opts HoverCardOptions, content if width == 0 { width = 280 } - style := func(panel *ui.Element, p float32) { - overlayStyle(c, panel, p) - panel.Width(width).Padding(Density(c).Unit() * 4).Gap(Density(c).Unit() * 2).Label(opts.Label). - MaxHeight(popoverRoom(c, b)) + overlayLayer(c, st) + // A popover keeps the card in the anchor's focus order and modal scope, even inside a Dialog. + shown := true + panel := ui.PopoverBase(c, anchor, &shown, func(panel *ui.Element) { + overlayStyle(c, panel, overlayAnchored(c, panel, b)) + panel.Margin(6, 0, 0, 0).Width(popoverWide(c, width)).Padding(Density(c).Unit() * 4).Gap(Density(c).Unit() * 2). + Label(opts.Label).MaxHeight(popoverRoom(c, b)) ui.Scroll(c).Shrink(1).Children(content) - } - var panel *ui.Element - dismissed, keyMode := false, keyboard || st.keyMode - if keyMode { - shown := true - panel = ui.PopoverBase(c, anchor, &shown, func(panel *ui.Element) { - style(panel.Margin(6, 0, 0, 0), overlayAnchored(c, panel, b)) - }) - dismissed = !shown - } else { - ui.Overlay(c, func() { - panel = ui.Column(c).Absolute().Role(ui.RolePopup) - prev := panel.Bounds() - x, y := overlayPlace(c, b, width, prev.H, 6) - panel.Left(x).Top(y) - p := overlayEnter(c, panel) - if prev.H == 0 { - p = 0 // not measured yet - c.AnimationFrame() - } - panel.Children(func() { style(panel, p) }) - }) - dismissed = c.Shortcut(0, ui.KeyEscape) - } - if dismissed { + }) + if !shown { slog.Debug("mujica: hover_card dismiss") - st.open, st.dismissed, st.keyMode = false, true, false - if keyMode { + if keyboard || st.focusIn { anchor.Focus() // at once, so the anchor stays hot and the card stays dismissed } + st.open, st.dismissed, st.focusIn = false, true, false return panel } - st.panel, st.keyMode = panel.Bounds(), keyboard || keyMode && panel.FocusWithin() + st.panel, st.focusIn = panel.Bounds(), panel.FocusWithin() return panel } diff --git a/hover_card_test.go b/hover_card_test.go index 815ff06..8314668 100644 --- a/hover_card_test.go +++ b/hover_card_test.go @@ -7,30 +7,45 @@ import ( "github.com/egoist/mygo/ui" ) -const hoverCardTestDelay = 20 * time.Millisecond +const hoverCardTestDelay = 150 * time.Millisecond type hoverCardApp struct { follows, next int + inDialog bool +} + +func (a *hoverCardApp) card(c *ui.Context) { + b := Button(c, "Lady Sakiko", ButtonOptions{Variant: Ghost}) + HoverCard(c, b, HoverCardOptions{OpenDelay: hoverCardTestDelay, CloseDelay: hoverCardTestDelay}, func() { + ui.Text(c, "Keyboardist of the court") + if Button(c, "Follow", ButtonOptions{}).Clicked() { + a.follows++ + } + }) + if Button(c, "Next", ButtonOptions{}).Clicked() { + a.next++ + } } func (a *hoverCardApp) view(c *ui.Context) { Use(c, Settings{}) - ui.Column(c).Padding(40).Gap(80).AlignItems(ui.Start).Children(func() { - b := Button(c, "Lady Sakiko", ButtonOptions{Variant: Ghost}) - HoverCard(c, b, HoverCardOptions{OpenDelay: hoverCardTestDelay, CloseDelay: hoverCardTestDelay}, func() { - ui.Text(c, "Keyboardist of the court") - if Button(c, "Follow", ButtonOptions{}).Clicked() { - a.follows++ - } + if a.inDialog { + open := true + Dialog(c, &open, DialogOptions{Title: "Court", HideClose: true}, func() { + ui.Column(c).Gap(80).AlignItems(ui.Start).Children(func() { a.card(c) }) }) - if Button(c, "Next", ButtonOptions{}).Clicked() { - a.next++ - } - }) + return + } + ui.Column(c).Padding(40).Gap(80).AlignItems(ui.Start).Children(func() { a.card(c) }) } -func hoverCardWait(tt *ui.Tester) { - time.Sleep(hoverCardTestDelay + 15*time.Millisecond) +func hoverCardShown(tt *ui.Tester) func() bool { + return func() bool { return tt.HasText("Keyboardist of the court") } +} + +// hoverCardSettle waits past both delays so any pending open or close has happened. +func hoverCardSettle(tt *ui.Tester) { + time.Sleep(hoverCardTestDelay + 30*time.Millisecond) tt.Frame() } @@ -38,34 +53,54 @@ func TestHoverCardPointerCanEnterCard(t *testing.T) { a := &hoverCardApp{} tt := ui.NewTester(a.view, 500, 400) r, _ := tt.Find("Lady Sakiko") + start := time.Now() tt.Move(r.X+5, r.Y+5) - if tt.HasText("Keyboardist of the court") { + if time.Since(start) < hoverCardTestDelay && tt.HasText("Keyboardist of the court") { t.Fatal("opened before the delay") } - hoverCardWait(tt) - tt.Frame() - f, ok := tt.Find("Follow") - if !ok { + if !overlayUntil(tt, hoverCardShown(tt)) { t.Fatalf("card did not open: %q", tt.Texts()) } - // Moving into the card keeps it; its button works. - tt.Move(f.X+5, f.Y+5) - hoverCardWait(tt) + // The pointer inside the card keeps it open past the close delay. + k, _ := tt.Find("Keyboardist of the court") + tt.Move(k.X+5, k.Y+5) + hoverCardSettle(tt) + if !tt.HasText("Follow") { + t.Fatal("card closed with the pointer inside it") + } if err := tt.Click("Follow"); err != nil { t.Fatal(err) } - if a.follows != 1 { - t.Fatalf("follows %d", a.follows) + if a.follows != 1 || !tt.Focused("Follow") { + t.Fatalf("follows %d, Follow focused %v", a.follows, tt.Focused("Follow")) } - // Leaving both closes it after the delay, and the window stays usable. + // With the focus inside, leaving keeps it; a click outside closes it. tt.Move(490, 390) - tt.Frame() + hoverCardSettle(tt) if !tt.HasText("Follow") { + t.Fatal("card closed with the focus inside it") + } + tt.ClickAt(490, 390) + if tt.HasText("Follow") { + t.Fatal("outside click did not close the card") + } +} + +func TestHoverCardCloseDelay(t *testing.T) { + a := &hoverCardApp{} + tt := ui.NewTester(a.view, 500, 400) + r, _ := tt.Find("Lady Sakiko") + tt.Move(r.X+5, r.Y+5) + if !overlayUntil(tt, hoverCardShown(tt)) { + t.Fatal("card did not open") + } + start := time.Now() + tt.Move(490, 390) + if time.Since(start) < hoverCardTestDelay && !tt.HasText("Follow") { t.Fatal("closed without the close delay") } - hoverCardWait(tt) - if tt.HasText("Follow") { - t.Fatal("card stayed open") + if !overlayUntil(tt, func() bool { return !tt.HasText("Follow") }) { + t.Fatal("card stayed open after the close delay") } } @@ -73,8 +108,7 @@ func TestHoverCardKeyboardEntersAndEscapes(t *testing.T) { a := &hoverCardApp{} tt := ui.NewTester(a.view, 500, 400) tt.Key(0, ui.KeyTab) - hoverCardWait(tt) - if !tt.HasText("Keyboardist of the court") { + if !overlayUntil(tt, hoverCardShown(tt)) { t.Fatal("no card on keyboard focus") } tt.Key(0, ui.KeyTab) @@ -89,7 +123,7 @@ func TestHoverCardKeyboardEntersAndEscapes(t *testing.T) { if tt.HasText("Follow") || !tt.Focused("Lady Sakiko") { t.Fatalf("Escape: card shown %v, anchor focused %v", tt.HasText("Follow"), tt.Focused("Lady Sakiko")) } - hoverCardWait(tt) + hoverCardSettle(tt) if tt.HasText("Follow") { t.Fatal("dismissed card came back while focused") } @@ -99,19 +133,43 @@ func TestHoverCardKeyboardEntersAndEscapes(t *testing.T) { } } +func TestHoverCardInsideDialog(t *testing.T) { + a := &hoverCardApp{inDialog: true} + tt := ui.NewTester(a.view, 600, 500) + r, _ := tt.Find("Lady Sakiko") + tt.Move(r.X+5, r.Y+5) + if !overlayUntil(tt, hoverCardShown(tt)) { + t.Fatal("card did not open in the dialog") + } + if err := tt.Click("Follow"); err != nil { + t.Fatal(err) + } + if a.follows != 1 || !tt.Focused("Follow") { + t.Fatalf("follows %d, focus kept on Follow %v", a.follows, tt.Focused("Follow")) + } + tt.Key(ui.Shift, ui.KeyTab) + if !tt.Focused("Lady Sakiko") { + t.Fatal("Shift+Tab from the card did not reach its anchor in the dialog") + } +} + func TestHoverCardSnapshot(t *testing.T) { - snapshot(t, "hover_card", 420, 240, func(c *ui.Context) { + overlaySnapshot(t, "hover_card", 420, 240, func(c *ui.Context) { ui.Column(c).Padding(24).AlignItems(ui.Start).Children(func() { - Button(c, "Lady Uika", ButtonOptions{Variant: Ghost}) - }) - ui.Overlay(c, func() { - p := ui.Column(c).Absolute().Left(24).Top(66) - overlayStyle(c, p, 1) - p.Width(280).Padding(16).Gap(8).AlignItems(ui.Start).Children(func() { - ui.Text(c, "Lady Uika").FontWeight(600) - ui.Text(c, "Vocalist and guitarist; keeps the ledger of the masquerade.").TextColor(Tokens(c).TextMuted) - Button(c, "Follow", ButtonOptions{Variant: Outline}) + b := Button(c, "Lady Uika", ButtonOptions{Variant: Ghost}) + HoverCard(c, b, HoverCardOptions{OpenDelay: time.Millisecond}, func() { + ui.Column(c).Gap(8).AlignItems(ui.Start).Children(func() { + ui.Text(c, "Lady Uika").FontWeight(600) + ui.Text(c, "Vocalist and guitarist; keeps the ledger of the masquerade.").TextColor(Tokens(c).TextMuted) + Button(c, "Follow", ButtonOptions{Variant: Outline}) + }) }) }) + }, func(tt *ui.Tester) { + r, _ := tt.Find("Lady Uika") + tt.Move(r.X+5, r.Y+5) + if !overlayUntil(tt, func() bool { return tt.HasText("Follow") }) { + t.Fatal("card did not open") + } }) } diff --git a/overlay.go b/overlay.go index 7b4a4a0..e328e9b 100644 --- a/overlay.go +++ b/overlay.go @@ -37,8 +37,7 @@ type OverlayOptions struct { Label string } -// Overlay shows content in a layer above the window while *open is true. -// Escape closes it; a modal one also closes on a backdrop click. +// Overlay shows content in a layer above the window while *open is true; Escape closes it. func Overlay(c *ui.Context, open *bool, opts OverlayOptions, content func()) *ui.Element { if opts.Dim && !opts.Modal { panic("mujica: Overlay Dim requires Modal") @@ -46,7 +45,9 @@ func Overlay(c *ui.Context, open *bool, opts OverlayOptions, content func()) *ui if opts.Place < OverlayCenter || opts.Place > OverlayBottomRight { panic("mujica: Overlay Place out of range") } + site, focus := overlaySite(c) if !*open { + focus.closed(c, site) return nil } k := Tokens(c) @@ -56,6 +57,7 @@ func Overlay(c *ui.Context, open *bool, opts OverlayOptions, content func()) *ui } fx, fy := overlayFractions(opts.Place) if opts.Modal { + overlayLayer(c, open) var backClicked bool shown := true panel := ui.DialogBase(c, &shown, func(back, panel *ui.Element) { @@ -69,6 +71,7 @@ func Overlay(c *ui.Context, open *bool, opts OverlayOptions, content func()) *ui panel.Label(opts.Label).Padding(Density(c).Unit() * 4) content() }) + focus.shown(panel) if !shown { slog.Debug("mujica: overlay close", "backdrop", backClicked) *open = false @@ -89,7 +92,8 @@ func Overlay(c *ui.Context, open *bool, opts OverlayOptions, content func()) *ui overlayStyle(c, panel, p) panel.Children(content) }) - if c.Shortcut(0, ui.KeyEscape) { + focus.shown(panel) + if overlayEscape(c, open) { slog.Debug("mujica: overlay close", "escape", true) *open = false } diff --git a/overlay_layers.go b/overlay_layers.go new file mode 100644 index 0000000..6b9c419 --- /dev/null +++ b/overlay_layers.go @@ -0,0 +1,103 @@ +package mujica + +import ( + "log/slog" + "time" + + "github.com/egoist/mygo/ui" +) + +// overlayLayers is the window's open MujicaUI layers, oldest first. +type overlayLayers struct { + frame, prev time.Time + keys []any + seen []time.Time +} + +type overlayLayersKey struct{} + +// overlayLayer marks the layer key open in this frame and reports whether it is on top. +func overlayLayer(c *ui.Context, key any) bool { + s := ui.Local(c.Root(), overlayLayersKey{}, func() overlayLayers { return overlayLayers{} }) + if now := c.Now(); now != s.frame { + s.prev, s.frame = s.frame, now + n := 0 + for i, k := range s.keys { + if !s.seen[i].Before(s.prev) { // drop layers the last frame did not build + s.keys[n], s.seen[n] = k, s.seen[i] + n++ + } + } + clear(s.keys[n:]) + s.keys, s.seen = s.keys[:n], s.seen[:n] + } + at := -1 + for i, k := range s.keys { + if k == key { + at = i + } + } + if at < 0 { + s.keys, s.seen = append(s.keys, key), append(s.seen, s.frame) + at = len(s.keys) - 1 + } + s.seen[at] = s.frame + return at == len(s.keys)-1 +} + +// overlayEscape reports Escape for a window-level layer, delivered only while it is on top. +func overlayEscape(c *ui.Context, key any) bool { + if !overlayLayer(c, key) { + return false + } + // The root is around every focus, so it takes Escape before MyGo's overlays. + byFocus := c.Root().Shortcut(0, ui.KeyEscape) + byWindow := c.Shortcut(0, ui.KeyEscape) + return byFocus || byWindow +} + +// overlaySiteState follows the focus of a layer after it closes. +type overlaySiteState struct { + focusIn bool // the focus was inside the layer when it last showed + wait int // frames left to check the focus after a close + holding bool // the site holds the fallback focus +} + +// overlaySite builds the invisible focus fallback at a layer's call site. +func overlaySite(c *ui.Context) (*ui.Element, *overlaySiteState) { + site := ui.Box(c).Size(0, 0).FocusRing(false) + st := ui.Local(site, "mujica.overlay.site", func() overlaySiteState { return overlaySiteState{} }) + st.holding = st.holding && site.FocusWithin() + if st.holding { + site.Focusable() // in flow, so Tab goes on from the layer's place + } else { + site.Absolute() + } + return site, st +} + +// shown records whether the focus is in the open layer's panel. +func (st *overlaySiteState) shown(panel *ui.Element) { + st.focusIn, st.wait = panel != nil && panel.FocusWithin(), 0 +} + +// closed moves a lost focus to the site once MyGo has had its chance to restore it. +func (st *overlaySiteState) closed(c *ui.Context, site *ui.Element) { + if st.focusIn { + st.focusIn, st.wait = false, 2 // MyGo prunes the panel at the end of the next frame + } + if st.wait == 0 { + return + } + st.wait-- + if st.wait > 0 { + c.AnimationFrame() + return + } + // The site itself counts as lost: it may inherit a vanished opener's positional ID. + if !c.Root().FocusWithin() || site.FocusWithin() { + slog.Debug("mujica: overlay focus fallback") + site.Focus() + st.holding = true + } +} diff --git a/overlay_snapshot_test.go b/overlay_snapshot_test.go new file mode 100644 index 0000000..4388b69 --- /dev/null +++ b/overlay_snapshot_test.go @@ -0,0 +1,65 @@ +package mujica + +import ( + "bytes" + "os" + "path/filepath" + "runtime" + "strings" + "testing" + "time" + + "github.com/egoist/mygo/ui" +) + +// overlaySnapshot is snapshot, with drive opening the real component through input before the capture. +func overlaySnapshot(t *testing.T, name string, w, h int, view func(c *ui.Context), drive func(tt *ui.Tester)) { + t.Helper() + for _, m := range []Mode{Light, Dark} { + ready := false + tt := ui.NewTester(func(c *ui.Context) { + Use(c, Settings{Mode: m}) + if ready { + view(c) + } + }, w, h) + tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1}) + ready = true + tt.Frame() + drive(tt) + got := encode(t, tt.Image()) + path := filepath.Join("testdata", "snapshots", runtime.GOOS, name+"-"+strings.ToLower(m.String())+".png") + if *update { + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(path, got, 0o644); err != nil { + t.Fatal(err) + } + continue + } + want, err := os.ReadFile(path) + if err != nil { + t.Fatalf("%v (run go test -update)", err) + } + if !bytes.Equal(got, want) { + if err := os.WriteFile(path+".got.png", got, 0o644); err != nil { + t.Fatal(err) + } + t.Errorf("%s differs; see %s.got.png", path, path) + } + } +} + +// overlayUntil draws frames until cond holds, for at most 5 s of wall time. +func overlayUntil(tt *ui.Tester, cond func() bool) bool { + end := time.Now().Add(5 * time.Second) + for !cond() { + if time.Now().After(end) { + return false + } + time.Sleep(2 * time.Millisecond) + tt.Frame() + } + return true +} diff --git a/overlay_test.go b/overlay_test.go index c66bc7a..5fa3e8a 100644 --- a/overlay_test.go +++ b/overlay_test.go @@ -3,6 +3,7 @@ package mujica import ( "runtime" "testing" + "time" "github.com/egoist/mygo/ui" ) @@ -93,6 +94,57 @@ func TestOverlayNonModal(t *testing.T) { } } +func TestOverlayEscapeClosesTopNonModalLayerFirst(t *testing.T) { + bottom, top := false, false + tt := ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + if Button(c, "Show", ButtonOptions{}).Clicked() { + if bottom { + top = true + } + bottom = true + } + Overlay(c, &top, OverlayOptions{Place: OverlayTopRight}, func() { ui.Text(c, "Top layer") }) + Drawer(c, &bottom, DrawerOptions{Title: "Bottom layer", NonModal: true, Side: DrawerLeft}, nil) + }, 600, 400) + _ = tt.Click("Show") + _ = tt.Click("Show") // the overlay opens after the drawer, though built before it + if !bottom || !top { + t.Fatalf("bottom %v top %v", bottom, top) + } + tt.Key(0, ui.KeyEscape) + if top || !bottom { + t.Fatalf("first Escape: top %v bottom %v", top, bottom) + } + tt.Key(0, ui.KeyEscape) + if bottom { + t.Fatal("second Escape did not close the drawer") + } +} + +func TestOverlayNonModalRestoresFocusToItsPlace(t *testing.T) { + open := true + tt := ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + ui.Column(c).Children(func() { + Button(c, "First", ButtonOptions{}) + Overlay(c, &open, OverlayOptions{}, func() { Button(c, "Inside", ButtonOptions{}) }) + Button(c, "Next", ButtonOptions{}) + }) + }, 600, 400) + if err := tt.Click("Inside"); err != nil { + t.Fatal(err) + } + tt.Key(0, ui.KeyEscape) + if open { + t.Fatal("Escape did not close") + } + tt.Key(0, ui.KeyTab) + if !tt.Focused("Next") { + t.Fatal("focus lost on close instead of staying at the overlay's place") + } +} + func TestOverlayDimNeedsModal(t *testing.T) { defer func() { if recover() == nil { @@ -106,78 +158,114 @@ func TestOverlayDimNeedsModal(t *testing.T) { }, 200, 200) } -// TestOverlayLifecycle opens and closes every overlay 100 times and checks -// that nothing grows: goroutines, heap objects or the elements left behind. -func TestOverlayLifecycle(t *testing.T) { - var open bool - views := map[string]func(c *ui.Context, b *ui.Element){ - "Dialog": func(c *ui.Context, b *ui.Element) { Dialog(c, &open, DialogOptions{Title: "T"}, func() {}) }, - "Alert": func(c *ui.Context, b *ui.Element) { - AlertDialog(c, &open, AlertDialogOptions{Title: "T", ConfirmText: "x"}) - }, - "Drawer": func(c *ui.Context, b *ui.Element) { Drawer(c, &open, DrawerOptions{Title: "T"}, nil) }, - "Drawer2": func(c *ui.Context, b *ui.Element) { Drawer(c, &open, DrawerOptions{Title: "T", NonModal: true}, nil) }, - "Popover": func(c *ui.Context, b *ui.Element) { Popover(c, b, &open, PopoverOptions{}, func() {}) }, - "Confirm": func(c *ui.Context, b *ui.Element) { Popconfirm(c, b, &open, PopconfirmOptions{Title: "T"}) }, - "Overlay": func(c *ui.Context, b *ui.Element) { Overlay(c, &open, OverlayOptions{Modal: true}, func() {}) }, - "Menu": func(c *ui.Context, b *ui.Element) { - popupMenuOpen(c, b, &open, (&menuApp{}).build) - }, - "Context": nil, +// overlayCase drives one component open and closed through real input. +type overlayCase struct { + name string + view func(c *ui.Context, open *bool) + open, close func(tt *ui.Tester) + marker string +} + +func overlayCases() []overlayCase { + clickAnchor := func(tt *ui.Tester) { _ = tt.Click("Anchor") } + escape := func(tt *ui.Tester) { tt.Key(0, ui.KeyEscape) } + hover := func(tt *ui.Tester) { + r, _ := tt.Find("Anchor") + tt.Move(r.X+4, r.Y+4) } - for name, view := range views { + leave := func(tt *ui.Tester) { tt.Move(590, 390) } + anchor := func(c *ui.Context, open *bool) *ui.Element { + b := Button(c, "Anchor", ButtonOptions{}) + if b.Clicked() { + *open = true + } + return b + } + body := func(c *ui.Context) func() { return func() { ui.Text(c, "Layer body") } } + return []overlayCase{ + {"Dialog", func(c *ui.Context, open *bool) { + anchor(c, open) + Dialog(c, open, DialogOptions{Title: "T"}, body(c)) + }, clickAnchor, escape, "Layer body"}, + {"AlertDialog", func(c *ui.Context, open *bool) { + anchor(c, open) + AlertDialog(c, open, AlertDialogOptions{Title: "Layer body", ConfirmText: "x"}) + }, clickAnchor, escape, "Layer body"}, + {"Drawer", func(c *ui.Context, open *bool) { + anchor(c, open) + Drawer(c, open, DrawerOptions{Title: "T"}, body(c)) + }, clickAnchor, escape, "Layer body"}, + {"DrawerNonModal", func(c *ui.Context, open *bool) { + anchor(c, open) + Drawer(c, open, DrawerOptions{Title: "T", NonModal: true}, body(c)) + }, clickAnchor, escape, "Layer body"}, + {"Popover", func(c *ui.Context, open *bool) { + Popover(c, anchor(c, open), open, PopoverOptions{}, body(c)) + }, clickAnchor, escape, "Layer body"}, + {"Tooltip", func(c *ui.Context, open *bool) { + Tooltip(c, anchor(c, open), "Layer body", TooltipOptions{Delay: time.Millisecond}) + }, hover, leave, "Layer body"}, + {"HoverCard", func(c *ui.Context, open *bool) { + HoverCard(c, anchor(c, open), HoverCardOptions{OpenDelay: time.Millisecond, CloseDelay: time.Millisecond}, body(c)) + }, hover, leave, "Layer body"}, + {"DropdownMenu", func(c *ui.Context, open *bool) { + DropdownMenu(c, "Anchor", DropdownMenuOptions{}, (&menuApp{}).build) + }, clickAnchor, escape, "Rename"}, + {"ContextMenu", func(c *ui.Context, open *bool) { + row := ui.Row(c) + row.Children(func() { Button(c, "Anchor", ButtonOptions{}) }) + ContextMenu(c, row, ContextMenuOptions{}, (&menuApp{}).build) + }, func(tt *ui.Tester) { + clickAnchor(tt) + tt.Key(ui.Shift, ui.KeyF10) + }, escape, "Rename"}, + {"Popconfirm", func(c *ui.Context, open *bool) { + Popconfirm(c, anchor(c, open), open, PopconfirmOptions{Title: "Layer body"}) + }, clickAnchor, escape, "Layer body"}, + {"Overlay", func(c *ui.Context, open *bool) { + anchor(c, open) + Overlay(c, open, OverlayOptions{Modal: true}, body(c)) + }, clickAnchor, escape, "Layer body"}, + } +} + +// TestOverlayLifecycle opens and closes every overlay 100 times; goroutines, heap objects and elements must not grow. +func TestOverlayLifecycle(t *testing.T) { + for _, oc := range overlayCases() { + open := false tt := ui.NewTester(func(c *ui.Context) { Use(c, Settings{}) - row := ui.Row(c) - var b *ui.Element - row.Children(func() { b = Button(c, "Anchor", ButtonOptions{}) }) - if view == nil { - ContextMenu(c, row, ContextMenuOptions{}, (&menuApp{}).build) - } else { - view(c, b) - } + oc.view(c, &open) }, 600, 400) tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1}) - cycle := func() { - open = true - if view == nil { - _ = tt.Click("Anchor") - tt.Key(ui.Shift, ui.KeyF10) - if !tt.HasText("Rename") { - t.Fatalf("%s: did not open", name) - } + shown := func() bool { return tt.HasText(oc.marker) } + cycle := func(i int) { + oc.open(tt) + if !overlayUntil(tt, shown) { + t.Fatalf("%s: cycle %d did not open", oc.name, i) } - tt.Frame() - if name != "Drawer2" { - tt.Key(0, ui.KeyEscape) - if view == nil { - open = false - } - } else { - open = false - tt.Frame() - } - if open || tt.HasText("Rename") { - t.Fatalf("%s: Escape did not close", name) + oc.close(tt) + if !overlayUntil(tt, func() bool { return !shown() }) { + t.Fatalf("%s: cycle %d did not close", oc.name, i) } } - for range 20 { - cycle() + for i := range 20 { + cycle(i) } texts := len(tt.Texts()) before := heapObjects() goroutines := runtime.NumGoroutine() - for range 100 { - cycle() + for i := range 100 { + cycle(i) } if got := len(tt.Texts()); got != texts { - t.Errorf("%s: texts %d -> %d", name, texts, got) + t.Errorf("%s: texts %d -> %d", oc.name, texts, got) } if g := runtime.NumGoroutine(); g > goroutines { - t.Errorf("%s: goroutines %d -> %d", name, goroutines, g) + t.Errorf("%s: goroutines %d -> %d", oc.name, goroutines, g) } if after := heapObjects(); after > before+2000 { - t.Errorf("%s: heap objects %d -> %d", name, before, after) + t.Errorf("%s: heap objects %d -> %d", oc.name, before, after) } } } diff --git a/popconfirm.go b/popconfirm.go index 5f2c9b8..f4bc647 100644 --- a/popconfirm.go +++ b/popconfirm.go @@ -25,9 +25,7 @@ type PopconfirmResult struct { Cancelled bool } -// Popconfirm asks for a light confirmation beside anchor while *open is -// true. Confirm takes the focus; Cancel, Escape and an outside click cancel. -// Use AlertDialog for high-risk actions. +// Popconfirm asks for a light confirmation by anchor; use AlertDialog for high-risk actions. func Popconfirm(c *ui.Context, anchor *ui.Element, open *bool, opts PopconfirmOptions) PopconfirmResult { if anchor == nil { panic("mujica: Popconfirm needs an anchor") @@ -39,7 +37,7 @@ func Popconfirm(c *ui.Context, anchor *ui.Element, open *bool, opts PopconfirmOp if !*open { return res } - k := Tokens(c) + overlayLayer(c, open) u := Density(c).Unit() confirm, cancel := opts.ConfirmLabel, opts.CancelLabel if confirm == "" { @@ -56,22 +54,11 @@ func Popconfirm(c *ui.Context, anchor *ui.Element, open *bool, opts PopconfirmOp shown := true ui.PopoverBase(c, anchor, &shown, func(panel *ui.Element) { overlayStyle(c, panel, overlayAnchored(c, panel, b)) - panel.Margin(6, 0, 0, 0).Padding(u * 3).Gap(u * 3).MaxWidth(320).Role(ui.RoleAlertDialog). + panel.Margin(6, 0, 0, 0).Padding(u * 3).Gap(u * 3).MaxWidth(popoverWide(c, 320)).MaxHeight(popoverRoom(c, b)).Role(ui.RoleAlertDialog). Label(opts.Title).Description(opts.Description) - ui.Row(c).Gap(u * 2).AlignItems(ui.Start).Children(func() { - color := k.Warning - if opts.Danger { - color = k.Danger - } - ui.Icon(c, icons.Must("circle-alert")).Size(18, 18).TextColor(color).Shrink(0).Margin(1, 0, 0, 0) - ui.Column(c).Gap(u).Shrink(1).Children(func() { - ui.Text(c, opts.Title).FontWeight(600) - if opts.Description != "" { - ui.Text(c, opts.Description).TextColor(k.TextMuted) - } - }) - }) - ui.Row(c).Gap(u * 2).Justify(ui.End).Children(func() { + // The text scrolls so the actions stay in the window. + ui.Scroll(c).Shrink(1).Children(func() { popconfirmText(c, opts) }) + ui.Row(c).Gap(u * 2).Justify(ui.End).Shrink(0).Children(func() { if Button(c, cancel, ButtonOptions{Variant: Secondary}).Clicked() { res.Cancelled = true } @@ -89,3 +76,22 @@ func Popconfirm(c *ui.Context, anchor *ui.Element, open *bool, opts PopconfirmOp } return res } + +// popconfirmText is the icon, title and description of a Popconfirm. +func popconfirmText(c *ui.Context, opts PopconfirmOptions) { + k := Tokens(c) + u := Density(c).Unit() + ui.Row(c).Gap(u * 2).AlignItems(ui.Start).Children(func() { + color := k.Warning + if opts.Danger { + color = k.Danger + } + ui.Icon(c, icons.Must("circle-alert")).Size(18, 18).TextColor(color).Shrink(0).Margin(1, 0, 0, 0) + ui.Column(c).Gap(u).Shrink(1).Children(func() { + ui.Text(c, opts.Title).FontWeight(600) + if opts.Description != "" { + ui.Text(c, opts.Description).TextColor(k.TextMuted) + } + }) + }) +} diff --git a/popconfirm_test.go b/popconfirm_test.go index 32aef2a..b939a45 100644 --- a/popconfirm_test.go +++ b/popconfirm_test.go @@ -1,6 +1,7 @@ package mujica import ( + "strings" "testing" "github.com/egoist/mygo/ui" @@ -59,6 +60,25 @@ func TestPopconfirmCancelPaths(t *testing.T) { } } +func TestPopconfirmKeepsActionsInWindow(t *testing.T) { + long := strings.Repeat("The east gate stays unwatched tonight. ", 60) + open := true + tt := ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + ui.Column(c).Padding(30).Children(func() { + b := Button(c, "Archive", ButtonOptions{}) + Popconfirm(c, b, &open, PopconfirmOptions{Title: "Archive?", Description: long}) + }) + }, 400, 300) + tt.Frame() + for _, label := range []string{"Confirm", "Cancel"} { + r, ok := tt.Find(label) + if !ok || r.Y < 0 || r.Y+r.H > 300 || r.X+r.W > 400 { + t.Fatalf("%s at %+v outside the 400×300 window", label, r) + } + } +} + func TestPopconfirmSnapshot(t *testing.T) { snapshot(t, "popconfirm", 420, 220, func(c *ui.Context) { open := true diff --git a/popover.go b/popover.go index aef1a18..609a16d 100644 --- a/popover.go +++ b/popover.go @@ -18,9 +18,7 @@ type PopoverOptions struct { Label string } -// Popover shows content in a panel below anchor while *open is true. The -// panel flips above where there is no room, stays in the window and scrolls -// when taller than the room; an outside click or Escape closes it. +// Popover shows content below anchor, or above it, inside the window while *open is true. func Popover(c *ui.Context, anchor *ui.Element, open *bool, opts PopoverOptions, content func()) *ui.Element { if anchor == nil { panic("mujica: Popover needs an anchor") @@ -28,6 +26,7 @@ func Popover(c *ui.Context, anchor *ui.Element, open *bool, opts PopoverOptions, if !*open { return nil } + overlayLayer(c, open) u := Density(c).Unit() b := anchor.Bounds() label := opts.Label @@ -36,14 +35,14 @@ func Popover(c *ui.Context, anchor *ui.Element, open *bool, opts PopoverOptions, } panel := ui.PopoverBase(c, anchor, open, func(panel *ui.Element) { overlayStyle(c, panel, overlayAnchored(c, panel, b)) - panel.Margin(6, 0, 0, 0).Padding(u * 3).Gap(u * 2).MinWidth(b.W).MaxHeight(popoverRoom(c, b)).Label(label) + panel.Margin(6, 0, 0, 0).Padding(u * 3).Gap(u * 2).MinWidth(popoverWide(c, b.W)).MaxHeight(popoverRoom(c, b)).Label(label) if opts.Width > 0 { - panel.Width(opts.Width) + panel.Width(popoverWide(c, opts.Width)) } else { - panel.MaxWidth(360) + panel.MaxWidth(popoverWide(c, 360)) } if opts.Title != "" { - ui.Text(c, opts.Title).Font(theme.SerifFont).FontSize(theme.BodySize + 2).FontWeight(600).Shrink(0) + ui.Text(c, opts.Title).Font(theme.SerifFont).FontSize(FontSize(c, theme.BodySize+2)).FontWeight(600).Shrink(0) } ui.Scroll(c).Shrink(1).Children(content) }) @@ -58,3 +57,9 @@ func popoverRoom(c *ui.Context, b ui.Rect) float32 { _, h := c.Size() return max(b.Y, h-b.Y-b.H) - 16 } + +// popoverWide caps a panel width w to the window. +func popoverWide(c *ui.Context, w float32) float32 { + ww, _ := c.Size() + return min(w, ww-8) +} diff --git a/popover_test.go b/popover_test.go index a5226b5..db3887e 100644 --- a/popover_test.go +++ b/popover_test.go @@ -1,6 +1,7 @@ package mujica import ( + "strings" "testing" "github.com/egoist/mygo/ui" @@ -76,6 +77,27 @@ func TestPopoverOutsideClickAndEscape(t *testing.T) { } } +func TestPopoverFitsWindow(t *testing.T) { + open := true + var panel ui.Rect + tt := ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + ui.Column(c).Padding(30).Children(func() { + b := Button(c, "Filter", ButtonOptions{}) + if p := Popover(c, b, &open, PopoverOptions{Width: 1000}, func() { + ui.Text(c, strings.Repeat("Long row of guests. ", 200)) + Button(c, "Bottom", ButtonOptions{}) + }); p != nil { + panel = p.Bounds() + } + }) + }, 400, 300) + tt.Frame() + if panel.W > 400 || panel.X < 0 || panel.Y+panel.H > 300 { + t.Fatalf("panel %+v outside the 400×300 window", panel) + } +} + func TestPopoverNeedsAnchor(t *testing.T) { defer func() { if recover() == nil { diff --git a/popup_menu.go b/popup_menu.go index 0b3db9e..d0d272a 100644 --- a/popup_menu.go +++ b/popup_menu.go @@ -17,8 +17,7 @@ type PopupMenuItemOptions struct { KeepOpen bool } -// PopupMenu builds the items of a DropdownMenu or ContextMenu. Its methods -// add items in order and report choices in the frame they happen. +// PopupMenu builds the items of a DropdownMenu or ContextMenu, reporting choices as they happen. type PopupMenu struct { c *ui.Context root *popupMenuRoot @@ -43,8 +42,7 @@ type popupMenuSub struct { build func(m *PopupMenu) } -// Item adds an item showing label and reports whether it was chosen. -// Choosing it closes the menu unless KeepOpen is set. +// Item adds an item and reports its choice, which closes the menu unless KeepOpen. func (m *PopupMenu) Item(label string, opts PopupMenuItemOptions) bool { it := m.row(ui.ButtonBase(m.c), opts.Disabled, false) m.content(it, label, false, false) @@ -68,8 +66,7 @@ func (m *PopupMenu) Check(label string, checked *bool, opts PopupMenuItemOptions return true } -// Submenu adds an item opening a nested menu that build fills. Hover, -// click, Enter, Space or Right opens it; Left or Escape closes it. +// Submenu adds an item opening a nested menu that build fills. func (m *PopupMenu) Submenu(label string, opts PopupMenuItemOptions, build func(m *PopupMenu)) { if build == nil { panic("mujica: PopupMenu Submenu needs a build function") @@ -95,7 +92,7 @@ func (m *PopupMenu) Group(label string, fn func()) { m.Separator() } if label != "" { - ui.Text(m.c, label).FontSize(theme.CaptionSize).TextColor(k.TextMuted).Padding(u, u*3, u/2, u*3+16+u*2).Shrink(0) + ui.Text(m.c, label).FontSize(FontSize(m.c, theme.CaptionSize)).TextColor(k.TextMuted).Padding(u, u*3, u/2, u*3+16+u*2).Shrink(0) } fn() } @@ -115,7 +112,8 @@ func (m *PopupMenu) row(it *ui.Element, disabled, sub bool) *ui.Element { m.rows++ seq := m.seq it.Justify(ui.Start).MinHeight(max(theme.MinHitSize, d.ControlHeight()-4)).Padding(0, d.Unit()*3). - Gap(d.Unit() * 2).Radius(theme.ControlRadius).Disabled(disabled).FocusRing(false).TextColor(k.Text) + Gap(d.Unit() * 2).Radius(theme.ControlRadius).Disabled(disabled).TextColor(k.Text) + internal.Ring(it, k.Focus, theme.ControlRadius) if disabled { return it } @@ -135,7 +133,7 @@ func (m *PopupMenu) row(it *ui.Element, disabled, sub bool) *ui.Element { } *was = hovered if hovered || it.FocusVisible() || m.level.open == seq { - it.Background(k.Selection).DrawOver(func(p *ui.Painter, r ui.Rect) { + it.Background(k.Selection).Draw(func(p *ui.Painter, r ui.Rect) { p.Fill(ui.Rect{X: r.X, Y: r.Y + 4, W: 2, H: r.H - 8}, k.AccentText, 1) }) } @@ -163,13 +161,15 @@ func popupMenuOpen(c *ui.Context, anchor *ui.Element, open *bool, build func(m * if !*open { return nil } + overlayLayer(c, open) b := anchor.Bounds() root := &popupMenuRoot{} panel := ui.PopoverBase(c, anchor, open, func(panel *ui.Element) { overlayStyle(c, panel, overlayAnchored(c, panel, b)) - panel.Margin(4, 0, 0, 0).MinWidth(max(b.W, 200)).MaxWidth(360).MaxHeight(popoverRoom(c, b)) - items := popupMenuLevelBuild(c, panel, root, build, true) - if items.Shortcut(0, ui.KeyTab) || items.Shortcut(ui.Shift, ui.KeyTab) { + panel.Margin(4, 0, 0, 0).MinWidth(popoverWide(c, max(b.W, 200))).MaxWidth(popoverWide(c, 360)).MaxHeight(popoverRoom(c, b)) + popupMenuLevelBuild(c, panel, root, build, true) + // The panel holds every level, so Tab in a submenu closes the whole menu too. + if panel.Shortcut(0, ui.KeyTab) || panel.Shortcut(ui.Shift, ui.KeyTab) { root.close = true } }) @@ -183,9 +183,10 @@ func popupMenuOpen(c *ui.Context, anchor *ui.Element, open *bool, build func(m * } // popupMenuLevelBuild builds one level's items in outer, then its open submenu. -func popupMenuLevelBuild(c *ui.Context, outer *ui.Element, root *popupMenuRoot, build func(m *PopupMenu), autofocus bool) *ui.Element { +func popupMenuLevelBuild(c *ui.Context, outer *ui.Element, root *popupMenuRoot, build func(m *PopupMenu), autofocus bool) { u := Density(c).Unit() - items := ui.Scroll(c).Shrink(1).Padding(u).FocusGroup(ui.Vertical) + // The padding leaves room for the items' focus rings inside the clipping scroll. + items := ui.Scroll(c).Shrink(1).Padding(u + theme.FocusGap + theme.FocusWidth).FocusGroup(ui.Vertical) m := &PopupMenu{c: c, root: root, autofocus: autofocus} m.level = ui.Local(items, "mujica.menu.level", func() popupMenuLevel { return popupMenuLevel{} }) outer.Role(ui.RolePopup) @@ -195,7 +196,6 @@ func popupMenuLevelBuild(c *ui.Context, outer *ui.Element, root *popupMenuRoot, popupMenuSubmenu(c, outer, root, m.level, s) } } - return items } // popupMenuSubmenu builds a submenu beside its item, flipped to stay in the window. diff --git a/testdata/snapshots/darwin/context_menu-dark.png b/testdata/snapshots/darwin/context_menu-dark.png index 9cda9f7b6b6b56d24115b4eb8c2d25b9b302f973..199f092b67c9b35427665b4f8498ba20a980bac4 100644 GIT binary patch literal 12672 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 z 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 diff --git a/testdata/snapshots/darwin/context_menu-light.png b/testdata/snapshots/darwin/context_menu-light.png index 6699812fd33b3c572d741f6ed0d11ea2ae994ae8..9f58256a3f1a696880bf67fcbb81d78a197eeb4a 100644 GIT binary patch literal 14075 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 z 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 XDu3S6iWv5%HaKN@b-8L8%dr0k+D^t_ literal 13791 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 C6w2)Y literal 11343 zcmeHtcT`hBx38!O(wm_4BE5-JDI!SkAT5zj=q1#I-lX>$1OyZWq(hJ)p5RU3abf?zh(a<7H1KIdf*6IlIhn?>#e7S{jOkc+_~eZrvhOR+7`X zbqnh|=KBKoHm0RzVAk!{Egni`IT>BAcgQ(kE!{~voP!#qvpFC!omKKSoEdqW8wAyL z@vh~j!6g}a-1Sk;Ox*6()1OUBS#K3A2|$@b`4iR2Boc-F`F4d*woJ|Pc~gZ$EhrzF zk(9lc#A7A~z@SX@nG1itp+$WAPfXzfAiv6nu$B_O@wk8ml_>cx(e%U8m#P>)}0pBv2oNi)U$k7D^IiU z{9$4`jH#3;ji$w(Zj&L8ycdak_qHh1=2ZOIZzdt$%$KIM_#budhh{4p%HsC8-tm8_ zQyi*s>kse9kRAWLqsd)@;&fxm;YPwFfhR_stv34_x83l z*eNq(ktfFBT?$+m;s<*lI;3<5PUyK9n;1c&on_KqSLNB@_2H=VqZR+kO`YXP;b<-I zNUpcIxc|`C^s}TmuS12AQ!_#Po;(Fv%Q>M-)H!W{Cv(|4ZMf$ z8JlHy9)k`g0g{@OLn+3{jlSm|Msx38PL`Kf78^K>2^@}eg|SZ9k$obV%Y=`nKhTF6b6$@%jC&*+|w-eI?j*`!~Dyx$O&|RusMJf-& zKY+LCNuxuDS{fS5i%+kpHtvh^mWe3SJY?qgyGhLu{y~+OEYBLFLYanK(d|>%%5!vd zd@gb9?d$IQnJ*e#<#XY+zP7>DL2(h2eo=8|m(qGOGgPBSUbx*)E$BeMN%yIutkKim zYmMAl(@Wjct=X^H?bv;-{{A>h~pY6qVrDw&W=iql` zD%`tdzRC-}m&W>EQgh2Ux3-lv)JL77vJUI6S*$0FP|C$d#lviNMcaVVDz}0>WQq_$LrUjmiXn+mPbAJKDY;m@lIKw(z3n@D+M`{Aj$sr`y~7J`+2Bz@@@O z*71pnRWN)uzy5by;EigzCuzoMtdOvf``lQolfdUA!sv?limW@L+Ezt)uCrg6z){}xJE6+RWjj%(VGyVyPsSgx&^O-@GNw6tPMbzfdK<{az! zo0wJ>3ji#KG=PUp^F|@o?#pz)ng%gOm8M@Wx(h+&Tvx?K^_$D}&y9awE2gdKc?6$7 zosu^ERr)G4G3hmn2hsoHu2n^!gF>NO9^whvRhb>Uxw>8jNJJTXeGf;}X(+Py2u}>1 zh9-7W<@C)Zxo%umLC7S&bbE-;R){x>onKr6hm@u+v;vY%a_M>=5G|B`ZRNN;-T~mC ztk$0r^umA{W4ngo=xGVx6diIww^2_{ zR|8-L#(454ZF)?X0)M`lJjO#ge5Mh#XX&(XHLwwFj%37zbDW#9G(C5tWBT|79HEbeo?iU9fVs~zZr-KyUobFGV>S14OK56t=|g(z1(Zq&&x>xjb->5j8~{ z|Dj75mxOpt|sH?!WujE0idp#u&<>2y|;=R{lF~RRk>Vk#F81eXKyMw9A+CvZulBR6pmi z#h_RS4yZdA792BpUA@2T*P=(WK7%kQ74fyq+=n#H`-b2 z3@v1XiZa)$I*Q7n@_xZV9M~_DTu!=J28yqlLLSRn3S@a@b!GD7vLQT1{JU0;yJNeW zgcb@S{L@7s?A+YB=5T;xL45KHEe~IxR0&c!r&YrcHN5c0;L0IwGk(w1$oBUfQ6mzr zLZSH|mJ-5aeJCqJt3pW>KS*^jV6gfsq@`zxXCX6+7 z72mt%#f!!;M$0&Ul3uFoCPsmGVKw($AfL05L7DY{vOJ+*ZV|Z25IIiU8p8JKCKpH4N^f zukX*E^%22IIap;28%@-$Y zJqY}hi|(&b1F>ild9fw=w^AT;p4hPJCzRcVmSuP#*Z1LfgyU#GeW1{ersnJ-V9Bz7 zzo5MjD1oL@s&K0o6zGB0v=;@4s)0P<*2W)eWjbs+g-3yclzKxkH{7LGUFewO!FI(u>?cl(@weHO=y ztD_Jp^;`)TuCe*@b<%&40exO%8c?1CoqVIZUkl`^-1l6l@Q-S1^OS3rWM4L*vv1(-wr-lvzj$o;JkPEVJYf-xa!@qj#=^g zNMBycIG8;v6R<1OwDqBu&t`4mB77ZI7e_N8#?6iR{5eN*eD(M&0A7Dx*($L^LqsCm zg5FbF>3h}K*zqGv6uV$}Z-!ruZ7*Xm;eaiLarL{$v-z77zlI_Wys%Vug>KPe5o=Gq)@zi%?VoqV8p5a){_W8&PDfi?+wkbE|1@(N#D!0- zeq2)5=zhc@m^v+%nxT*+&mN;ena%S@9?1VP*V3==y&hO-R+I;Kx%MJ1)oY$s@j*bNn6OP&%Av`#=|qGqtDXx7moBr zBHxI&KOxG(b2ootwkmRr_?~0#cYmPlffV5>TI%|+Wylx3vyz^h@Kp)^-ywf>IQrLF zUw4=CxnIB;TgK}_&zojYk0RmRdH%iMndS6#7_u;~R9-d^lJI@qfxpZMikwPE-uqN*nDGedylxt_@85ULrN5f9sJ2$Sd}$#oNy_WHH3?%S3?DgSx$W{ zJ!{!)WME30(%|dlntpr}ldp8MB5K)3znW$jSeTpU1*D7G%xtd`PQDpifuCO;G+;V0 z>`Q;XX8=v{j2LZmrSmF16esmbpe8bRu3Z$jmS zJd_Cj22a;2iBfJSx=Yc*vL9|*7kwo-p0qi(tUn%|jWKuhX|BGc_|mfEQn9zay=}qI z8nbqh{%vvk$j2j9&bYL^ynMw)?9I!UQ?DW$4__`L*H7Je83i*kW8>5-aP$luws$;{ zu73l<-HqNE$GZ4<1g7lHE)Jy)_GM*|pTTExLI@mcdU2ozy`7A*CPT<_J2TA2;kP`WcOd!BE|?UjhGl5rqP>@Pnk zcaU#)JbeDqkKA_>?3QOa2}GF0z+pW#4t(XgQQ?1m9a6MzZB#s|nVaPP4cjq8O`YId ztTNp*UVk?^uc^-`eaNI-KF{*HianhQp4rLCA{m>v*%@p}kv8A^9qfc_ip)H*^r`+- zC$r<&BHh-Of$zZJ{i!33jJ8P|>u!dj>`R}n{!@`Ar!BG!9`@Je6O@vd@MD`BlMM;} z`f115^73X&|3m8!!-40=F{6cQ;*h!Xz()_mt7n~vBJwxlA)lTt$b11WcJf5soibbD`FkN*Vonfo7F zBl_2@!CluS#u42g%zARp-kMHD#ooN%vQ#0Rj4L3aPAr)SywG>m1>Kc!jo@axSg0+< z-(Ns$bBt9M&+Wa89(g0X<_;?1UYt95+1T9kPb8h@5L#pPzPwbB-ZVb z`5tKKEA<8`GI+b}x1gb0*S{SAfYG-;(er-kh$uyK>znK*Jx;C?6%nV?!$W#OHt(6S zK2{oiX>r%zwwg;PslWK%W=Qsf)+f`l24@cB(NTG}KDUH_=|90ghJVQGxcOu zcS?`Hn|@^kFTvN>Venm6c1_OZm5(DMXCj%IB2EjaEt_2YyDg&G?99^AGS|!4#l2t+151H04kBaPe&P;NpFj}LsaFOPjEKng${(yq5kGd zj$_w%B3=W5HdckzLvqRTf5@}-@s5kwQL2|ulk{T#-?90 zB0a=c1dpEn!)B%?ph5M^9^Hu>AJ4q-p-bqg zJ@FBZSqs1Xn}nCmGR>|a9o*d_H&LOic?0P*{g6HLvkRcGFm=(dv<=mI82N~lOz`11 zi*b7=C#QJ~%vO(bc$UK=_ZUQ@n{WROoaY|^(rfTlRi~OwTgGZr*pMnStoAYFw#pxLE+g0Nn60olq)b|#yNbUy zjXT`tRK40Uef8=`x7mk@a$iRuA8TzJAI_QVHCyMiEpFC@v+>piu)5I;3{{a(l}!=d zd)aQb31(SYz_C>R(~P+>vvNB+?^Bv7BR>3JQIvy_-^3WZv)7)$baf_6Bx?vkGLZA6 zwfrtc?)%cfPVE1kROzXLczQ$r6$KeBFXB0vS!1IyPG2H)&&NhGCjj-m_-Nyd=1w9u z;CJz71U--!$WS}?-c#hEv}9uqJ7;UwiN)IJbIalRT{)7yV{h_s63IGS-#`zqk|w35 zrsjpPTUNilW?-gNwO7{*`;jC?L*RoBKBj8*+?~@tcI)!p4}9Vd*4IuYS4e3^KyWB9&O&dvQDY;3Hhoe3SL zf3PiRvYP{j?tByuC&9$-AHeH=UZOjCnb#tH1WQa`+6-hiJ&Vf zS>J_tqk~U`O6^4qT2DH*QhGFVC0qJh+F?n~MpAuFl&EWm+2t`g_UAl}()1@2f>B*+3ISL=E(TU)y0L+r(-^b1@3}3;{Zm)6EA# z?`(zajoxBp41mCqpp*c1Zsy?JCfOwyfSqf;jX4cBb7mnS!MxXDBl@+d%@^Y)6%?h> z&MsAw(&J@f4_ZmBiCJkc8w;Jl+0&&rIQ_`F*zzpVW?y7^Q7)HA1=gRblhxUa2#jH* zjFD$fvfkHRs)BS)ibyAPVU~^+H?~9Chb6$Rhcl%SGvea>e#Q(p&kir{l$7|OvCv_? zJsaCXPJ5jrEIkW;{*G4@Yn0#+Q-vQw==bH0pQqzILx5KbW2O?6U{X%Rpy`rko}QjC zWgJ4Dxtr0oxTJ)GjL4xo2w3N4^DJ}L|3W9~%)fx+emDsJn^e>KuHEf2Q4B3{4MBg1 z5wQGw(%;Aj|F@E;p&Z9 zBSJMG=BuYjU(d$t#9sz5Tu-6r!OjWU)5J|f0!@E?*MEC+6g`xr#{p6)@DqUV?NwY~ zs|1^cEpkBt4^SwbJtvI+O~;+STD<Ba8ZFnz8ervuZRF(x7dr_sIA6$#4ju;=UAP-0y z_2nhqRg324^V@N>Jipvu?{bP+TA$I6Rj^b(FFtmn`{&@IaDz&FedSJp5mHK!)MObE zt`-rI{d%A%eM(l!DH1lgz1PxRIFw_!f0M;BjX)3++lA-nckl{HNMDVE{RLN5ZuICA zypIj+X6qE7kP<|;L&6M2fY{ls+@TE-dGYL)!n$B9Lh4;5b*FE&JC=(YekgWd(<-W2 z1O1#N6*|FD9gDnm>8SFwu4x!5zRbV`CjM;UY!~bI_HX*V=~llH@h4AGNp51Xr*~&9 zH`doRV7YaSJ4<_Y&!_f5=UZdB^uOd$OOqx;DJpavg z3e#Pbmy*&!6!E~>?hwN3)XaP&LZ!fnt!exqJ7?m-RfQJ>qF=r@C=D?xrJGKwvQiTK zx^wAEOy7UAus2p+eHa>gt{H-feqnHD(8hXfL7*6GO5^2uMT%0VW{;zz_~m&O3QP%F zbJJulDRp>SP9l7D_zGtA01sgK>Uec^th@J#JF%#4{v$iPT`dlf90l#Ffy+r;NIp0; zJQEjIdHU5U20uxu)49SF?EF0NczrR-*5jo69ER`EJaOPv_p8l5+#KQjPyvKiN@DahiH(HEu zF;^e2k>N!X(%VN$L9Lpe>dhmz6j5?=9=kK1oxK|G{sFn#B!`PKCc!-b^!I0Y6_HPaGbAD>GoD?8rZD~t}am0dB$SiL34 zZ12z{^zjjq_tQI8+l`5CssN_LoN?X}@PJ2ywKs^;VBXOZkH{R+d^ zy?f_uflx)j^j79fxN%>UcLe72gX~p$uE9ml%!0XXF#Nwb9AFcAewK|d9W#Z@5&ClyLxkcL%vR1K4zbO z(T04*E<*mrNI7Qugp8aC*E=_SC=~MtEwN|Mx(Mf(WIvceAUO}h&FTHxmg>k&#%_$B z)0^a)h}i%^-)lJtEMrW0^M3CD-qaYoOm3d~I3MnfY@LYD8?W=@I$We!3dv6Svhw_0 zQml%d!RDaAtG&Yi*B)!3c>&>cCRtfo>f&VDqj@ItT0ZFv-R8m#K zRFs;PXYpS&JKnUFh_1%#=at)X7ZljrajMUTCiZs*|9oLVQ`x*w4A}ul?9uxfe%rh7 z&cUCkSxHJoj@&p%Q!!ut~QL-x>&;5FZa9oF*9?IX|*?L zYao5$;wq-{427yRHlCT8L4Zb!4-Yk^Uz5J969}a$XAE|eHDF;{642Y^09HCEgCo5Z}rKJrxB<&V%gZ_w(&b4MrnTE``WKnmy29BhZ4F|d-37d!`3^!x8XrN zj1otQ^NakI6%||QtL@$EwWX>(3F!R=aA_zB*RZurs0e>-=w!nL>ah?-fHJlH8`C_t zm`omf_@};jFLnLOzB<)pvWv>VLJn$f!IZ5)Kt|5HpT?L&VyK+O|_%D=5zNKhNQVL8*o?KO;CPg$-wK_l9KbQ2_#ZGtr*A&6G$ueyX90~=Krd^ z1Rig3o8a3)P@!N%(Rppu%w!~iox0EEtj*$;6`FVf`K-%g#K+i9NXzc@Rl(`^>XgL= zv`kZ8YUU~2R^g8>%4Rdl@=NqGOl3*#HdEi1xg>6XLg3qn5f%m};6Y_LOfm3>{T45I zW0=}V%w7^cA(o-6jyF8hEn{IMP0YblqGEKQ*(mfSHuEB(k->gAADl;XIa@=k7cO9UkLKC(K=YuUhtUMUzp!`TB#>rw=cNNnTt0 zHAc%K!-=&jx||%u*mH!9IR zXI!j3ZFeve>gS6I6Nx5yZIYVelVE+^ZPjUAAVp{PJTo}xJ)=@85vzFS7Y+JPqn{=p zSUt_aJV2$k|ITqYX=Eb59Or|(Ok{ZM-OJNsazeCy(wxXv4!bOUuiQJM_PVg8$X5+6 zc2ofc%cy78%{keR1sdKT>9g6zPCh ztaqC;$m}}+God8{+=ivK27)`U4^%}wmj+;#Q)Ckt4j3`g-0B71G-s?6##}lbcburx z*NDt&o8`V0_q(qAWGT8KfWeW8%EWOJ`(SNug{0AKGZXOMT0_wb~ot^R#vK2CMm)HX|H%2U`K=V${$!xap8LE=lb%7z;zzhCZd@6mbt7p}@j_!jzTy6|9s z=b5vFJZButES|n4tN(f~FZId9!0P*TTd843u)>#pd_n_{P181nAu{-}yiILmEg zoay$~mgU*V3qz8Lo6uc5s7yj>`;)o)LlcpO0f-;J#8l$iK*vuWF^RhfdvolLkSZ)D zN9nZ?$kvbcy}OTaw`IJXR~n^KH|lbkW}|>*+TQkY{rt{O)#2}Najh<>*&)*Of%rdf zH|Vz&;C#Cm{$?j}V5L@*W(ME6Y4f)4%vhQz&L7b63@Mxbnm-Q>Gk-{w92VR{C_{30 z8t*rR{{yT4-A^;Yzq|Yo`~3gL|5$eahg_!3WKg+Sx3JL`^a{%Bm?OitZYj%a$W_Ri Gh5Q@6eV76O diff --git a/testdata/snapshots/darwin/dropdown_menu-light.png b/testdata/snapshots/darwin/dropdown_menu-light.png index 426e388a89a43843a3301f76eadc8c819263c4bb..f8b2b87b0d0b3930b55fd38f85d4498be4240ac9 100644 GIT binary patch literal 18539 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 diff --git a/testdata/snapshots/darwin/hover_card-dark.png b/testdata/snapshots/darwin/hover_card-dark.png index 8de2e5ef94f80359e844dcd3d0de5466072bd838..67759371050ffb5774ae74b10ed360875d5a9dfb 100644 GIT binary patch literal 12100 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�_SjbW9(QyU??;55wrAni+;b1(&tR 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 diff --git a/testdata/snapshots/darwin/hover_card-light.png b/testdata/snapshots/darwin/hover_card-light.png index 1efdfc92425ed279a5458d3d41b30e46f122c9ab..2a5f55f7ef7b611aa3b2fdfaf8aa47903e89c6b7 100644 GIT binary patch delta 4708 zcmc(g=QrGKx5q^bl4!X_Nwi4xPB2Cg(OZTPb#x(&(PFglLzIZ9lc+(6=w%Qsy3q+y zV{}Fv1~Ei8j^}>eb;BNy=z~kx+FXR7PM5K82Nq1&${U%O*nh@ zyg%J(@V`S2Z@asrPve{b^7#^NfJS#Vdw5EWr8$oM?5t$==8Z{D)%|HX_|mSUswhpu zo0qNAX*Tk{AWb3C07C!7IWr8x(PJ*G5-JK2g^;gk@$Hojh57owwutHn$j_*-O)k>hE%%c6&CJG;#gcN7ijbSCNSqU8V%C)4?);8t*gjP(i4Zu(6z^0(uayI3%-EPq-?uQ5G zP29HK1lh)guEQU}(q)UC5vj2yZ&W5OwxeW{{}lq_2Fo^vo@-3kHe02KG`J==`UU0( z*Q{5ZO{h@Kb$!-Z;5eW<$k^{2&8K|+#4BKZwL|CuYGcr`WI{09+0{)%F>u1E%De^h z1+bGIuT9NZG1HjS?)%XsBw)8{p_sEtJVamNWak6xBY5O7AUzN3&!~BKmxP48Hq4Te zsFiDdk@x=5kdl8pV6KVpHdaZJHeiV6blYjN4DTEq<!V z;;yWwoTqaW{#W>S)22Z$cM^}w983*2r$XnbDuwi$ zmvauSYkl{dhUaep;2&jWW%g!C3gblM2;Y^G@EiyqT?DWEsB@u^T-rQL@>#m&e5 z-`-21@`asK8|Zq8B@j5!{u49d8`kuTDI4;4Iot>@5#+q-7a z?k>M39`}&m@3?3Ad1W9mmv1Y8ep2$mLcCT^l8VI_bZqeC9xTSFpv2%JmNo8+(l;RV`x7vj< zJqt$H($b$qoY7?YgDWE+BfJCHcLd=doliGyBj_(PK#uMC6KM+%InEATxx@QMxM3sb zSAz@qUgOKN`rY{KAbK7pxf+w{uQ7C3$Engg_1>X$OZEo*+W}fm#pSK1XafKmDPz}_TVS`cg4LiVpT)@@uxKOAgal z+Q0fOC7;=D!}Sm{DA?QcspClE=_2oq7A_;~yX$RZBz^&UYgyvmo&iB&R-DPvc4g=N zu7ZYbzeD_64BP`G3XmjmbYdXXwLj7%S&G`DT3>iY-ao7~%>5!HJwtLcZu-OYn!*C< z3&Kezz4872uvn-B&@EX*0{&^stSR3&$Q}z~>irsPTuv6Mu9r%gIvKK$qN@9SaS`WXPfdsNki?d56&>0n!0TnnI+sn%}umsqQ*O3GTFsU`T2-Y z_U=*bM7YDFZf@-Z(i(OFh)yCaqH-B}bF!Cap(M4*gf-Zn$Z$i$-hZ6BFN>4Fzc_-& zu9k6AgkR`i1z{H8FBlF}M`n9jqD7XP5{F3zU6 zmrq_Tzzs0qUjIX==Y1W?tX!9Xd`ANQhC(W9liv&Fq5#1?JFy%aTM{gK0=M1YJrm!G z<%LH{Vs}Vi+WcXX?H2By!g|rt-J+cas*Yas>S@M|-KD~j4^e+a(pr6UJl@lvP?{I8 z(G`!EVRN4kB!+ffDEXu#pO1|eB#0<;K~y(ixdR;dUA>n1j*TWQ&a`H%r+T3}M|7TJ z{m0xNIs*NPv=lt->gBdk?arj5*Ki@PwY8$?wRN)X#M3R&w4x}KN6*5IcK%3irVk{I zg*H)%Z&F4d4_}nt=4Mx)0!cgTYhh6CiDEQ5Bw!yD@{s?L zG0?N%O_$2Y?i&vsS~@0AyJ7UUeNppXwhaOlB_S5RaWEvt>)8vTm=cJ{ggGTCGIP}5 zZP>4e27HZ{rU+H;&y!78fTz%#cF-+TF4Nj$_(-M%qM*tqG_Tmr)FR6@9oRckBQS;! ztG{t2WH&isDlOkpzhZxszUtXi*TqeC2e4t5z;Bf2C7*lrT#DWTuo~4K$<&`6NuAQj zvm6<7>i=-RHB~ITA&1dGW%b z3}nLAec2>FKQBH0yc{wp8e(ckqj#ZCrWEjS5KA{0*1pIu(tR7aq50<+vL7SY3XnP= z5?>++bG)Pavo{_TUhxm&UTj5M~swLji!x%LbYs&2LElTA^W%H1D20)h4zPNBA~Z`-TZ zo@(`S_2T7JO%E8>t~YXBM3dbiA3YHXX=v6H0h!@!R&^#t8>0}yKh-%mkBN8B_JJ95cP z0%ky%?!DjWs>0_+=(G|~ObjL8d{P!4^6+8B_{7Asn~AC;L^XTd`A z^?#x;>2Z_er!p1A#c)^GGt8WC;@_o-$w_$iqXtV+!*+jT9FX4Me_>{p)*4W}ae(Vi z(Xn!Co^q)fy2r{|RCw$#cAYaRlIs^gwNP=SZD~GwYUJqGFNo(}l2&r`3s)JH!Y_+` zyRBzAB_$<4P8U}P$o2s&#};dczIR#9euv0d!4{(KnG*j)YfHus9h&5J)5pm2zR0k;ajsJ@9DP)^c# zw$tcKaL@_5pst(Q9@t%5Sx;Pl{&i<3%lDFCWoS5h3LFhAFE7)p_|E(H{6X!vtw+IX zc^l{A=-Iq(Ca#H_T}S$Sl{CAKo~mT+UPk$NiAX~23SN9F2l?*2X)>{#j!PWF zsZz1Vs=Et0NJg8$$8oQ{3H$eGHJ+l2(!bV3M@P4mCM3I~TNJ@X$`^;hr_`_f6*#_* zh>MG(faW)RgyQ1j)3k!@g_a;E003NEHdEP6u32Yv+xF+UTtjHv`gXm>J41bahdb0- zG1b1mfBbcPDdoHE7Wt%Z!860Xtd5D`=n+Okv&I#ExKngqyN53|n>_Zzslj$z_+r4l zf4XeTLw>cjDMO);RWuPUVvl?}TKeZ+R{QS*Yh|}?70|1EIy~3{;Q-jo zWPB}5z}>A`T29VyMe~+F=}=nQ7`(+_+vo3-51zzXKFylKbCCaKaj~e7h3}~@7Py7O zJ$h6lBEl>sRWRo@@G~!(AKCXY(Q_-q{o)nIRVes!lW;K+D2!|{sX1}C0EmlZjfm~Y zL0ZX1gP(W@^&0WcSopiZ2r2M_PYoU5ztR@^w8g?6i_zc+a&8YhNfE6n6NJvW@3vkN zS?7~C%1a097W~n6l}5(KvNBl!)LdAvg0P?6#=^&EE$h98&eJzK6yuny_bls@#O-g2 z^$+-3*8hUlyxcA2FR+gG*tJMiYW;%pfCmQl+^uMZ8XCUo$*ki98CL&*LE%H#1k96{ z*VCXdM}#i$JHD!5j?gOowyVU9U=sCr-gKU&T6n9uaTY_kJTmK>WCNW2rf^;jNyrKw zrrdzQGhSUyTT+{980LL{(3!R0(r+QFOR^%Qfr*L9760)fR?4@b<7$G9%}R>%s?V6i zl+AIi3*(kf4O#_bIF`tzT~>DVV?&i$&dUZ}jzT&ZOSg-}2X>3Do($6Uxp3-7RlQqy z%q?QW}B^%6t-{eNcFG=CUwob!`hJuNkT)p8Y^ Gu>S$XDo$Vk delta 4609 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