Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
c2fd6ad
fix(components): stop menu rows tinting under caller content
t8y2 Nov 13, 2026
0edcd90
fix(ui): let a tooltip open on a chosen side
xiaoyumuxi Nov 13, 2026
9305ef2
fix(tooltip): regenerate the installer recipe
t8y2 Nov 13, 2026
74ddd65
feat(web): allow a page to bypass system proxies
imjakey Nov 13, 2026
3c025a1
feat(app): scale macOS traffic lights in a custom titlebar
imjakey Nov 13, 2026
50a25e3
feat(app): request a native window content size
Ezreal-byte Nov 13, 2026
fb7300d
fix(gfx): draw cell glyphs with the font's underline weight
t8y2 Nov 13, 2026
30a91db
ci: run the underline metric test on Windows
t8y2 Nov 13, 2026
d1252da
feat(table): expose last-painted row identities
t8y2 Nov 13, 2026
5bee0d3
feat: add editor gutter actions and directory paths
t8y2 Nov 13, 2026
e419237
Merge remote-tracking branch 'origin/main' into lane/rowidentity
t8y2 Nov 13, 2026
8239839
feat(table): scroll wide tables left and right under a fixed header
t8y2 Nov 13, 2026
a6f6e5d
feat(gfx): stroke dashed borders through the path pipeline
t8y2 Nov 13, 2026
20d160a
feat(app): add the grabbing cursor to every backend
t8y2 Nov 13, 2026
a7345fa
feat(components): optional text alignment for InputSnapshot
t8y2 Nov 13, 2026
e1a04ae
feat(ui): dashed element borders and injected dashed frames
t8y2 Nov 13, 2026
6bfd5e2
fix(ui): keep a table's horizontal scrollbar inside its reserved gutter
t8y2 Nov 13, 2026
9a72c12
feat(app): write HTML and plain text to the clipboard in one copy
t8y2 Nov 13, 2026
9d0abef
feat(ui): frozen table columns pinned to a scrolling body's left edge
t8y2 Nov 13, 2026
449079b
fix(components): refresh the scroll-area recipe for the frozen band
t8y2 Nov 13, 2026
d621712
fix(components): keep long tooltip text whole when wrapping
t8y2 Nov 14, 2026
be5d296
fix(ui): hide duplicate anonymous table hover bars
t8y2 Nov 14, 2026
39c770a
fix(components): tint the caret's row in an empty CodeEditor
t8y2 Nov 14, 2026
0a4e756
feat(ui): TextEnd places an Input's text at the end of its direction
t8y2 Nov 14, 2026
5cce5aa
fix(instance): claim with a named pipe on Windows
t8y2 Nov 14, 2026
b8ae437
fix(instance): keep the claim off the browser target
t8y2 Nov 14, 2026
11a62ef
fix(components): wrap tooltip labels through a stack scratch
t8y2 Nov 14, 2026
2382a5a
fix(components): regenerate the stale code-editor recipe
t8y2 Nov 14, 2026
b5cd71e
docs(release): v0.6.3 notes
t8y2 Nov 14, 2026
4510c70
docs: point at v0.6.3
t8y2 Nov 14, 2026
ef9f0bd
feat(app): report a content window's frame and minimize state
t8y2 Nov 14, 2026
ba876bc
fix(gfx): draw cell glyphs with the font's own box stroke
t8y2 Nov 14, 2026
4e01052
feat(package): write a PKGBUILD for Arch Linux
t8y2 Nov 14, 2026
27429b5
feat(update): apply signed delta updates to the installed payload
t8y2 Nov 14, 2026
7daaafe
feat(ui): give Select an icon per option
t8y2 Nov 14, 2026
b63e4a0
feat(headless): add a test clock, accessibility queries and notificat…
t8y2 Nov 14, 2026
67313e5
Merge vivaui/viva main into main
xiaoyumuxi Nov 14, 2026
bf0a714
fix(update): install a patched macOS payload under the running bundle…
xiaoyumuxi Nov 14, 2026
0312f3d
Merge fix/update-darwin-payload-name into sync/upstream-b63e4a0
xiaoyumuxi Nov 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ jobs:
# native structure ABI tests are here for the same reason: they build only
# on Windows.
- name: Material contracts and controls (WARP)
run: go test ./internal/platform/windows ./ui ./components ./headless ./app -run 'Test(Backdrop|WindowBackdrop|Notification|TaskbarCreated|CompositionClear|CompositionFallback|CompositionCreation|CustomBackdrop|AcrylicAccent|LegacyAcrylic|RoundedOutline|Translucent|MonospaceFamilies|AlwaysOnTop|SaveDialogCheckbox|FileIcon|NativeStructureABI)' -count=1 -v
run: go test ./internal/platform/windows ./ui ./components ./headless ./app -run 'Test(Backdrop|WindowBackdrop|Notification|TaskbarCreated|CompositionClear|CompositionFallback|CompositionCreation|CustomBackdrop|AcrylicAccent|LegacyAcrylic|RoundedOutline|Translucent|MonospaceFamilies|EngineReportsTheFontsUnderline|AlwaysOnTop|SaveDialogCheckbox|FileIcon|NativeStructureABI)' -count=1 -v
- name: Terminal keyboard routing
run: go test ./internal/platform/windows -run '^TestATerminalGetsEditingKeysAndChordsAsRawKeys$' -count=1 -v
- name: Native Windows global shortcut
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Viva reaches Cocoa and Metal through cgo; on Linux, X11 with the system XCB and
Vulkan loaders; on Windows, Win32 with Direct3D 11 and DirectWrite. Viva loads
the system libraries at runtime and bundles none of them.

The current release is `v0.6.1`; name it explicitly (`@v0.6.1`) to pin it. Guides,
The current release is `v0.6.3`; name it explicitly (`@v0.6.3`) to pin it. Guides,
the API reference, and a component catalog with live previews live in
[`website/`](website/); run it with `npm run dev` there, or read them on
[vivaui.dev](https://vivaui.dev/en/), which is also available in
Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ viva dev . # hot reload: save a file, the window updates and keeps its st

环境要求:Go 1.26 或更新版本(缺失时 viva 会自己下载)。macOS 上需要 Xcode 命令行工具,因为 Viva 通过 cgo 访问 Cocoa 和 Metal;Linux 上需要带系统 XCB 和 Vulkan 加载库的 X11;Windows 上需要 Win32、Direct3D 11 和 DirectWrite。Viva 在运行时加载系统库,自身不捆绑任何一个。

当前版本是 `v0.6.1`;要固定版本就写明(`@v0.6.1`)。指南、API 参考和带实时预览的组件目录在 [`website/`](website/) 里,本地用 `npm run dev` 运行;也已经发布在 [vivaui.dev](https://vivaui.dev/zh/)。
当前版本是 `v0.6.3`;要固定版本就写明(`@v0.6.3`)。指南、API 参考和带实时预览的组件目录在 [`website/`](website/) 里,本地用 `npm run dev` 运行;也已经发布在 [vivaui.dev](https://vivaui.dev/zh/)。

下面的一切描述的都是这个仓库:它的测量、它自己的程序,以及如何开发框架本身,而不是如何用框架。

Expand Down
51 changes: 51 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,54 @@ The documentation site's JavaScript and CSS dependencies are pinned in
`website/package-lock.json`. Their license texts are part of the packages
installed from that lockfile; a deployed build should carry those notices in
its own license page.

### github.com/gabstv/go-bsdiff

The MIT License (MIT)

Copyright (c) 2019 Gabriel Ochsenhofer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

### github.com/dsnet/compress

Copyright © 2015, Joe Tsai and The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the copyright holder nor the names of its contributors may be used
to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
136 changes: 136 additions & 0 deletions app/accessnodes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package app

import (
"github.com/vivaui/viva/gfx"
"github.com/vivaui/viva/internal/semantic"
)

// AccessNode is what assistive technology sees of one control in a frame: the
// same information the platform adapters send to the system, without the
// platform. Driver.Accessibility returns the last frame's tree.
type AccessNode struct {
// ID names the control, as the hit it was made from does.
ID gfx.ID
// Role is the control's role; zero when it is a text without one.
Role gfx.Role
// Bounds is where the control was drawn, in logical pixels.
Bounds gfx.Rect

// Label is the accessible name, Value the control's value and Hint the
// short instruction usually read after the name.
Label string
Value string
Hint string
// Description is a longer explanation than Hint.
Description string

Focused bool
Disabled bool
Checked bool
Mixed bool
Selected bool
Expanded bool
Multiline bool
ReadOnly bool
Secure bool
Focusable bool
// Expandable marks a control that opens and closes something, whatever its
// state now.
Expandable bool

// Level is a heading's level or a tree item's depth; zero when not stated.
Level uint8
// PosInSet and SetSize place the node among its siblings, counting from 1.
PosInSet, SetSize int32
// Live marks a region that announces changes to its content.
Live gfx.LiveRegion
// Range is a slider's or progress bar's number.
Range gfx.ValueRange
// Selection is the selected span of a focused text field's Value.
Selection AccessSelection
}

// AccessSelection is a span of a text node's Value in Unicode code points:
// Start and End are the anchor and the caret, so End < Start for a selection
// made backwards. Valid is false when the node has no caret.
type AccessSelection struct {
Start, End int32
Valid bool
}

// Accessibility returns the accessibility tree of the last painted frame, in
// reading order. It is safe to call from the goroutine that drives the Driver
// (the main thread in a test), as Snapshot is.
func (driver *Driver) Accessibility() []AccessNode {
if driver == nil || driver.painter == nil {
return nil
}
nodes := driver.painter.accessibility
if len(nodes) == 0 {
return nil
}
out := make([]AccessNode, len(nodes))
for index, node := range nodes {
out[index] = AccessNode{
ID: node.ID, Role: accessRole(semantic.Role(node.Role)),
Bounds: gfx.Rect{X: node.X, Y: node.Y, Width: node.Width, Height: node.Height},
Label: node.Label, Value: node.Value, Hint: node.Hint, Description: node.Description,
Focused: node.Focused, Disabled: node.Disabled, Checked: node.Checked, Mixed: node.Mixed,
Selected: node.Selected, Expanded: node.Expanded, Multiline: node.Multiline,
ReadOnly: node.ReadOnly, Secure: node.Secure, Focusable: node.Focusable,
Expandable: node.Expandable, Level: node.Level, PosInSet: node.PosInSet, SetSize: node.SetSize,
Live: node.Live, Range: node.Range,
Selection: AccessSelection{Start: node.Selection.Start, End: node.Selection.End, Valid: node.Selection.Valid},
}
}
return out
}

// accessRole maps the semantic role the platform adapters receive back to the
// gfx.Role the application declared. Roles that have no gfx counterpart (a
// text, an image, the application itself) are zero.
func accessRole(role semantic.Role) gfx.Role {
switch role {
case semantic.RoleButton:
return gfx.RoleButton
case semantic.RoleLink:
return gfx.RoleLink
case semantic.RoleCheckbox:
return gfx.RoleCheckbox
case semantic.RoleRadio:
return gfx.RoleRadio
case semantic.RoleTab:
return gfx.RoleTab
case semantic.RoleMenuItem:
return gfx.RoleMenuItem
case semantic.RoleCombobox:
return gfx.RoleCombobox
case semantic.RoleSwitch:
return gfx.RoleSwitch
case semantic.RoleTextField:
return gfx.RoleTextField
case semantic.RoleSlider:
return gfx.RoleSlider
case semantic.RoleGroup:
return gfx.RoleGroup
case semantic.RoleMenu:
return gfx.RoleMenu
case semantic.RoleMenubar:
return gfx.RoleMenubar
case semantic.RoleListBox:
return gfx.RoleListBox
case semantic.RoleOption:
return gfx.RoleOption
case semantic.RoleGrid:
return gfx.RoleGrid
case semantic.RoleGridCell:
return gfx.RoleGridCell
case semantic.RoleHeading:
return gfx.RoleHeading
case semantic.RoleStatus:
return gfx.RoleStatus
case semantic.RoleSeparator:
return gfx.RoleSeparator
}
return 0
}
4 changes: 4 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ type Config struct {
// that. Zero means 28,
// the system titlebar's own height. It only applies to WindowCustomTitlebar.
TitlebarHeight float32
// TrafficLightScale scales native macOS traffic lights in a custom titlebar.
// Values in (0, 1] shrink the controls around their original centers; zero
// preserves the system size. Other platforms ignore this setting.
TrafficLightScale float32
// WindowControls styles the minimize, maximize and close buttons Viva draws at
// the trailing end of a WindowCustomTitlebar's strip on Windows and Linux,
// where the system draws none for a window without a titlebar; macOS has its
Expand Down
1 change: 1 addition & 0 deletions app/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var ErrNoWindows = errors.New("app: application opened no windows")
// and Fullscreen() bool. It reports transitions through Config.OnFullscreen
// before resize/frame callbacks and repaints afterward.
// An always-on-top host additionally implements SetAlwaysOnTop(bool) error.
// A size-capable host additionally implements SetSize(int, int) error.
type WindowControl interface {
Close()
Hide()
Expand Down
1 change: 1 addition & 0 deletions app/capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
CapabilityClipboardImage
CapabilityClipboardImageAsync
CapabilityClipboardFiles
CapabilityClipboardHTML
CapabilityFileDialogs
CapabilityFileDialogsAsync
CapabilityDirectoryDialogs
Expand Down
1 change: 1 addition & 0 deletions app/capabilities_native.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func nativeCapabilities() Capabilities {
CapabilityClipboardImage |
CapabilityClipboardImageAsync |
CapabilityClipboardFiles |
CapabilityClipboardHTML |
CapabilityFileDialogs |
CapabilityFileDialogsAsync |
CapabilityDirectoryDialogs |
Expand Down
1 change: 1 addition & 0 deletions app/capabilities_web.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ func nativeCapabilities() Capabilities {
return Capabilities(
CapabilityFileDrop |
CapabilityClipboardTextAsync |
CapabilityClipboardHTML |
CapabilityClipboardImageAsync |
CapabilityFileDialogsAsync |
CapabilitySecretStoreAsync |
Expand Down
37 changes: 37 additions & 0 deletions app/clipboard_html.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package app

import (
"fmt"
"strings"
)

// SetClipboardHTML makes the system clipboard hold html as its rich flavour and
// alt as its plain one, in a single write, for a copy a reader may take either
// way: a query result that pastes with its colours into a document and as text
// into an editor. alt is what plain-text readers get — deriving it from html is
// the caller's job, not the clipboard's.
//
// The flavours are what each platform calls rich text: NSPasteboard's
// public.html beside public.utf8-plain-text, Windows' registered "HTML Format"
// (CF_HTML) with the plain text as CF_UNICODETEXT, and the CLIPBOARD
// selection's text/html target beside UTF8_STRING. Nothing is written when
// either string contains NUL; an empty html writes alt as plain text only, with
// exactly SetClipboardText's shape, so the degradation is the copy the caller
// already spelled out. The Web target cannot answer a synchronous write
// (Clipboard.write resolves a Promise) and returns ErrAsyncRequired;
// SetClipboardHTMLAsync writes both flavours there.
func SetClipboardHTML(html, alt string) error {
if strings.IndexByte(html, 0) >= 0 {
return fmt.Errorf("app: clipboard html contains NUL")
}
if strings.IndexByte(alt, 0) >= 0 {
return fmt.Errorf("app: clipboard text contains NUL")
}
if html == "" {
return SetClipboardText(alt)
}
if err, handled := driverSetClipboardHTML(html, alt); handled {
return err
}
return nativeSetClipboardHTML(html, alt)
}
9 changes: 9 additions & 0 deletions app/clipboard_html_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build darwin

package app

import darwinplatform "github.com/vivaui/viva/internal/platform/darwin"

func nativeSetClipboardHTML(html, alt string) error {
return darwinplatform.SetClipboardHTML(html, alt)
}
9 changes: 9 additions & 0 deletions app/clipboard_html_js.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build js && wasm

package app

import webplatform "github.com/vivaui/viva/internal/platform/web"

func nativeSetClipboardHTML(html, alt string) error {
return webSystemError("write clipboard html", webplatform.SetClipboardHTML(html, alt))
}
9 changes: 9 additions & 0 deletions app/clipboard_html_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build linux

package app

import linuxplatform "github.com/vivaui/viva/internal/platform/linux"

func nativeSetClipboardHTML(html, alt string) error {
return linuxSystemError(linuxplatform.SetClipboardHTML(html, alt))
}
Loading
Loading