zaniah 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/README.md +9 -28
  4. data/assets/fonts/NotoSans-LICENSE.txt +94 -0
  5. data/assets/fonts/NotoSans-Regular.ttf +0 -0
  6. data/docs/_templates/page.erb +123 -0
  7. data/docs/components.md +13 -5
  8. data/docs/gallery/command-palette-dark.png +0 -0
  9. data/docs/gallery/command-palette-light.png +0 -0
  10. data/docs/gallery/components-dark.png +0 -0
  11. data/docs/gallery/components-high_contrast.png +0 -0
  12. data/docs/gallery/components-light.png +0 -0
  13. data/docs/gallery/dialog-dark.png +0 -0
  14. data/docs/gallery/dialog-light.png +0 -0
  15. data/docs/gallery/hover-card-dark.png +0 -0
  16. data/docs/gallery/hover-card-high_contrast.png +0 -0
  17. data/docs/gallery/hover-card-light.png +0 -0
  18. data/docs/gallery/modal-dark.png +0 -0
  19. data/docs/gallery/modal-light.png +0 -0
  20. data/docs/gallery/popover-bottom-dark.png +0 -0
  21. data/docs/gallery/popover-bottom-light.png +0 -0
  22. data/docs/gallery/popover-left-dark.png +0 -0
  23. data/docs/gallery/popover-left-high_contrast.png +0 -0
  24. data/docs/gallery/popover-left-light.png +0 -0
  25. data/docs/gallery/popover-right-dark.png +0 -0
  26. data/docs/gallery/popover-right-light.png +0 -0
  27. data/docs/gallery/popover-top-dark.png +0 -0
  28. data/docs/gallery/popover-top-light.png +0 -0
  29. data/docs/gallery/toast-danger-dark.png +0 -0
  30. data/docs/gallery/toast-danger-light.png +0 -0
  31. data/docs/gallery/toast-info-dark.png +0 -0
  32. data/docs/gallery/toast-info-light.png +0 -0
  33. data/docs/gallery/toast-success-dark.png +0 -0
  34. data/docs/gallery/toast-success-light.png +0 -0
  35. data/docs/gallery/toast-warning-dark.png +0 -0
  36. data/docs/gallery/toast-warning-light.png +0 -0
  37. data/docs/gallery/tooltip-bottom-dark.png +0 -0
  38. data/docs/gallery/tooltip-bottom-light.png +0 -0
  39. data/docs/gallery/tooltip-left-dark.png +0 -0
  40. data/docs/gallery/tooltip-left-light.png +0 -0
  41. data/docs/gallery/tooltip-right-dark.png +0 -0
  42. data/docs/gallery/tooltip-right-light.png +0 -0
  43. data/docs/gallery/tooltip-top-dark.png +0 -0
  44. data/docs/gallery/tooltip-top-light.png +0 -0
  45. data/docs/inspection.md +3 -1
  46. data/docs/layout.md +0 -8
  47. data/docs/native.md +12 -17
  48. data/docs/pages.yml +949 -0
  49. data/docs/previews/actions.png +0 -0
  50. data/docs/previews/choices.png +0 -0
  51. data/docs/previews/command-palette-dark.png +0 -0
  52. data/docs/previews/data.png +0 -0
  53. data/docs/previews/dialog-dark.png +0 -0
  54. data/docs/previews/drawer-right-dark.png +0 -0
  55. data/docs/previews/editors.png +0 -0
  56. data/docs/previews/feedback.png +0 -0
  57. data/docs/previews/forms.png +0 -0
  58. data/docs/previews/foundation.png +0 -0
  59. data/docs/previews/grid.png +0 -0
  60. data/docs/previews/hex-view.png +0 -0
  61. data/docs/previews/menu-dark.png +0 -0
  62. data/docs/previews/navigation.png +0 -0
  63. data/docs/previews/pane-grid.png +0 -0
  64. data/docs/previews/popover-right-dark.png +0 -0
  65. data/docs/previews/structure.png +0 -0
  66. data/docs/previews/text-input.png +0 -0
  67. data/docs/previews/toast-success-dark.png +0 -0
  68. data/docs/previews/tooltip-bottom-dark.png +0 -0
  69. data/docs/previews/values.png +0 -0
  70. data/docs/previews/variants.png +0 -0
  71. data/docs/previews/workspace.png +0 -0
  72. data/docs/process_pool.md +1 -6
  73. data/docs/site.css +89 -29
  74. data/docs/text.md +0 -10
  75. data/docs/tui.md +3 -2
  76. data/docs/vector_and_list.md +15 -7
  77. data/examples/gallery.rb +4 -4
  78. data/lib/zaniah/accessibility/linux/service.rb +1 -1
  79. data/lib/zaniah/accessibility/mac.rb +1 -0
  80. data/lib/zaniah/accessibility/node.rb +2 -0
  81. data/lib/zaniah/accessibility/tree.rb +3 -2
  82. data/lib/zaniah/accessibility/windows/provider.rb +1 -0
  83. data/lib/zaniah/gpu/software.rb +26 -8
  84. data/lib/zaniah/input/dispatcher.rb +6 -0
  85. data/lib/zaniah/input/keymap.rb +16 -0
  86. data/lib/zaniah/inspection.rb +9 -2
  87. data/lib/zaniah/layout/engine.rb +1 -1
  88. data/lib/zaniah/list/height_index.rb +14 -0
  89. data/lib/zaniah/list.rb +24 -3
  90. data/lib/zaniah/platform/file_dialog_options.rb +26 -0
  91. data/lib/zaniah/platform/headless/window.rb +2 -2
  92. data/lib/zaniah/platform/linux/window.rb +9 -1
  93. data/lib/zaniah/platform/mac/window.rb +11 -1
  94. data/lib/zaniah/platform/windows/window.rb +23 -5
  95. data/lib/zaniah/scene.rb +2 -2
  96. data/lib/zaniah/ui/component.rb +3 -1
  97. data/lib/zaniah/ui/hex_view.rb +185 -0
  98. data/lib/zaniah/ui/layout_components.rb +9 -1
  99. data/lib/zaniah/ui/text_inputs.rb +130 -9
  100. data/lib/zaniah/ui/tree_view.rb +37 -7
  101. data/lib/zaniah/ui/virtual_table.rb +227 -0
  102. data/lib/zaniah/ui.rb +2 -0
  103. data/lib/zaniah/uniform_list.rb +33 -3
  104. data/lib/zaniah/version.rb +1 -1
  105. data/sig/elements.rbs +10 -3
  106. data/sig/gpu.rbs +1 -1
  107. data/sig/native.rbs +4 -4
  108. data/sig/ui.rbs +57 -0
  109. data/tools/build_docs.rb +101 -0
  110. data/tools/generate_component_gallery.rb +18 -10
  111. data/tools/generate_doc_previews.rb +69 -0
  112. metadata +37 -3
  113. data/docs/index.html +0 -74
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a6d77e1edea911ee42064986e375f163213f45bedaeda9c6f3e409b42914cbd
4
- data.tar.gz: 21970a583f79a01502abf982811820361a7628dc0ffffca0a2f308fa4852a6b7
3
+ metadata.gz: 2880a0bf76786c774939df0c5d8c02cc287789607221c6a1739d71b50fcc2248
4
+ data.tar.gz: f2ccf99f464295d8e7af77e61a0b38911f133728b979f868b4ede8ce2f4a5fdd
5
5
  SHA512:
6
- metadata.gz: 83d536f11608784994079181c05524fb3935cddf6076728967b78fc54b48ae91889c387efc047159f767dac8743ae5cb89f7c3497f75afa7b733133f6bc7e982
7
- data.tar.gz: caa3b692cbe5435abc9571b0ccc3a09dc46db71c022a0ab2f80903dab7336c3818c3ae05ecc3ee6a0aa8ba657fb45bfa61a5218ec236546f229ba9d80614ace2
6
+ metadata.gz: e1a950ab9299a1a0121469d98310c945b7dbefb611b87f286c28d769fbbcdb3d14fb3cc20d12c135b5620071cbcc1ac75dc3ac083bc4c6c4978558d1fd75fb36
7
+ data.tar.gz: d31dd8cd5722a4bccccdc73f54e0cff07770d1094fe67a5d3ef000f097b950228f8b6a9f9ac05b0adc380d61a393c82ef24b66ff3810ffda3b8fdd8e3a904c8c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.1 — 2026-10-02
4
+
5
+ - Prevent obsolete focus controls from accumulating across redraws, reducing memory use and keeping keyboard navigation on current controls.
6
+
7
+ ## 0.12.0 — 2026-10-02
8
+
9
+ - Add streaming virtual tables with lazy cells, stable selection, row styling, configurable columns, and tail following.
10
+ - Add virtual hexadecimal and ASCII byte views with linked selection, highlights, keyboard navigation, and copying.
11
+ - Preserve scrolling and height measurements when virtual list counts change, with optional bottom following.
12
+ - Avoid stale rows and duplicated drawing when scrolling keyed virtual lists.
13
+ - Reduce layout work for fixed-size containers and reuse unchanged visible byte rows for faster redraws.
14
+ - Speed up vector recording by reusing resolved paint colors.
15
+ - Add text-field validation states and token completion with keyboard selection and Unicode-safe replacement.
16
+ - Add programmatic tree selection and item context menus.
17
+ - Add suggested filenames, starting directories, and extension filters for native file dialogs.
18
+ - Fix inspection snapshots for nested UI components, including select controls in dialogs.
19
+ - Preserve accessible content and actions inside wrapped split panes.
20
+
3
21
  ## 0.11.0 — 2026-09-25
4
22
 
5
23
  - Add segmented controls, alerts, hover cards, calendar and date-range inputs.
data/README.md CHANGED
@@ -114,7 +114,7 @@ For an interactive window, choose `backend: :mac`, `:linux`, `:windows`, or
114
114
  | `:tui` | ANSI terminal | Text-grid rendering and terminal input |
115
115
 
116
116
  Native backends use the operating system libraries through Ruby's Fiddle. See
117
- [Native backends](docs/native.md) for platform requirements and checks.
117
+ [Native backends](https://noxdea.github.io/zaniah/docs/guides/native.html) for platform requirements.
118
118
 
119
119
  Native macOS, Windows, and X11 windows can be moved to a display returned by
120
120
  `Zaniah::Platform.displays` with `window.move_to_display(display)`. Headless and
@@ -124,37 +124,18 @@ compositor to fullscreen on that output, but the compositor may choose otherwise
124
124
 
125
125
  ## Documentation
126
126
 
127
- - [Native backends](docs/native.md) — windows, displays, file watching, and terminals
128
- - [Text system](docs/text.md) — font discovery, shaping, rasterization, and caching
129
- - [Images](docs/images.md) — PNG, GIF, baseline JPEG, and orientation support
130
- - [SVG and lists](docs/vector_and_list.md) — static vector icons and virtual lists
131
- - [Drag-and-drop reordering](docs/drag_drop.md) — stable IDs, virtual targets, and keyboard access
132
- - [Layout and scrolling](docs/layout.md) — Grid, resizable pane grids, scrolling, sticky positioning, and RTL foundations
133
- - [Themes](docs/theme.md) — semantic tokens and state styles
134
- - [Components](docs/components.md) — controls, overlays, data views, charts, and forms
135
- - [Animation](docs/animation.md) — easing, springs, transitions, and reduced motion
136
- - [Accessibility](docs/accessibility.md) — semantic trees, diffs, and native bridges
137
- - [Terminal UI](docs/tui.md) — deterministic component degradation
138
- - [CPU process workers](docs/process_pool.md) — portable background CPU work
139
- - [Declarative elements](docs/describe.md) — validated vocabularies, event routing, diffs, and surfaces
140
- - [Architecture decisions](docs/adr) — design records and rationale
127
+ - [Getting started](https://noxdea.github.io/zaniah/docs/) — installation and your first render
128
+ - [Guides](https://noxdea.github.io/zaniah/docs/guides/) — platforms, layout, text, themes, accessibility, and advanced APIs
129
+ - [Components](https://noxdea.github.io/zaniah/docs/components/) — rendered examples, code, and API summaries
130
+ - [Component API reference](https://noxdea.github.io/zaniah/docs/guides/component-reference.html) — all constructors and variants in one table
131
+ - [Contributing guidelines](.github/CONTRIBUTING.md) — development and platform checks
132
+ - [Architecture decisions](docs/adr) — implementation rationale
141
133
  - [RBS declarations](sig) — public API signatures
142
134
 
143
- ## Development
144
-
145
- ```sh
146
- bundle install
147
- bundle exec rake test
148
- bundle exec rake bench
149
- gem build --strict zaniah.gemspec
150
- ```
151
-
152
- Set `BUDGET=1` to enable benchmark assertions.
153
-
154
135
  ## Contributing
155
136
 
156
- Bug reports and pull requests are welcome at
157
- [github.com/noxdea/zaniah](https://github.com/noxdea/zaniah).
137
+ Bug reports and pull requests are welcome. See the
138
+ [contributing guidelines](.github/CONTRIBUTING.md) for checks and documentation updates.
158
139
 
159
140
  ## License
160
141
 
@@ -0,0 +1,94 @@
1
+ Copyright 2018 The Noto Project Authors (github.com/googlei18n/noto-fonts)
2
+
3
+ This Font Software is licensed under the SIL Open Font License,
4
+ Version 1.1.
5
+
6
+ This license is copied below, and is also available with a FAQ at:
7
+ http://scripts.sil.org/OFL
8
+
9
+ -----------------------------------------------------------
10
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11
+ -----------------------------------------------------------
12
+
13
+ PREAMBLE
14
+ The goals of the Open Font License (OFL) are to stimulate worldwide
15
+ development of collaborative font projects, to support the font
16
+ creation efforts of academic and linguistic communities, and to
17
+ provide a free and open framework in which fonts may be shared and
18
+ improved in partnership with others.
19
+
20
+ The OFL allows the licensed fonts to be used, studied, modified and
21
+ redistributed freely as long as they are not sold by themselves. The
22
+ fonts, including any derivative works, can be bundled, embedded,
23
+ redistributed and/or sold with any software provided that any reserved
24
+ names are not used by derivative works. The fonts and derivatives,
25
+ however, cannot be released under any other type of license. The
26
+ requirement for fonts to remain under this license does not apply to
27
+ any document created using the fonts or their derivatives.
28
+
29
+ DEFINITIONS
30
+ "Font Software" refers to the set of files released by the Copyright
31
+ Holder(s) under this license and clearly marked as such. This may
32
+ include source files, build scripts and documentation.
33
+
34
+ "Reserved Font Name" refers to any names specified as such after the
35
+ copyright statement(s).
36
+
37
+ "Original Version" refers to the collection of Font Software
38
+ components as distributed by the Copyright Holder(s).
39
+
40
+ "Modified Version" refers to any derivative made by adding to,
41
+ deleting, or substituting -- in part or in whole -- any of the
42
+ components of the Original Version, by changing formats or by porting
43
+ the Font Software to a new environment.
44
+
45
+ "Author" refers to any designer, engineer, programmer, technical
46
+ writer or other person who contributed to the Font Software.
47
+
48
+ PERMISSION & CONDITIONS
49
+ Permission is hereby granted, free of charge, to any person obtaining
50
+ a copy of the Font Software, to use, study, copy, merge, embed,
51
+ modify, redistribute, and sell modified and unmodified copies of the
52
+ Font Software, subject to the following conditions:
53
+
54
+ 1) Neither the Font Software nor any of its individual components, in
55
+ Original or Modified Versions, may be sold by itself.
56
+
57
+ 2) Original or Modified Versions of the Font Software may be bundled,
58
+ redistributed and/or sold with any software, provided that each copy
59
+ contains the above copyright notice and this license. These can be
60
+ included either as stand-alone text files, human-readable headers or
61
+ in the appropriate machine-readable metadata fields within text or
62
+ binary files as long as those fields can be easily viewed by the user.
63
+
64
+ 3) No Modified Version of the Font Software may use the Reserved Font
65
+ Name(s) unless explicit written permission is granted by the
66
+ corresponding Copyright Holder. This restriction only applies to the
67
+ primary font name as presented to the users.
68
+
69
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70
+ Software shall not be used to promote, endorse or advertise any
71
+ Modified Version, except to acknowledge the contribution(s) of the
72
+ Copyright Holder(s) and the Author(s) or with their explicit written
73
+ permission.
74
+
75
+ 5) The Font Software, modified or unmodified, in part or in whole,
76
+ must be distributed entirely under this license, and must not be
77
+ distributed under any other license. The requirement for fonts to
78
+ remain under this license does not apply to any document created using
79
+ the Font Software.
80
+
81
+ TERMINATION
82
+ This license becomes null and void if any of the above conditions are
83
+ not met.
84
+
85
+ DISCLAIMER
86
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94
+ OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file
@@ -0,0 +1,123 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta name="description" content="<%= h(page.fetch("lead")) %>">
7
+ <meta name="theme-color" content="#0b1220">
8
+ <link rel="canonical" href="https://noxdea.github.io/zaniah/docs/<%= path == "index.html" ? "" : path %>">
9
+ <link rel="stylesheet" href="<%= link_from(path, "site.css") %>">
10
+ <title><%= h(page.fetch("title")) %> · Zaniah Docs</title>
11
+ </head>
12
+ <body>
13
+ <a class="skip-link" href="#content">Skip to content</a>
14
+ <header class="site-header">
15
+ <div class="header-inner">
16
+ <a class="brand" href="<%= link_from(path, "index.html") %>" aria-label="Zaniah documentation home"><span class="brand-symbol" aria-hidden="true">Z</span><span>Zaniah <small>Docs</small></span></a>
17
+ <nav class="header-links" aria-label="Global navigation">
18
+ <a href="<%= link_from(path, "index.html") %>">Docs</a>
19
+ <a href="<%= link_from(path, "guides/index.html") %>">Guides</a>
20
+ <a href="<%= link_from(path, "components/index.html") %>">Components</a>
21
+ <a href="https://github.com/noxdea/zaniah">GitHub</a>
22
+ </nav>
23
+ </div>
24
+ </header>
25
+
26
+ <div class="docs-shell">
27
+ <aside class="sidebar" aria-label="Documentation navigation">
28
+ <% groups.each do |group, items| %>
29
+ <div class="nav-group"><h2><%= h(group) %></h2>
30
+ <% items.each do |item| %>
31
+ <a href="<%= link_from(path, item.fetch("path")) %>"<%= ' aria-current="page"' if item["path"] == path %>><%= h(item.fetch("title")) %></a>
32
+ <% end %>
33
+ </div>
34
+ <% end %>
35
+ </aside>
36
+
37
+ <main id="content" class="content">
38
+ <details class="mobile-nav"><summary>Browse documentation</summary><nav aria-label="Mobile documentation navigation">
39
+ <% groups.each do |group, items| %>
40
+ <strong><%= h(group) %></strong>
41
+ <% items.each do |item| %>
42
+ <a href="<%= link_from(path, item.fetch("path")) %>"<%= ' aria-current="page"' if item["path"] == path %>><%= h(item.fetch("title")) %></a>
43
+ <% end %>
44
+ <% end %>
45
+ </nav></details>
46
+ <div class="page-heading">
47
+ <p class="breadcrumb"><a href="<%= link_from(path, "index.html") %>">Docs</a><span aria-hidden="true">/</span><%= h(page.fetch("group")) %></p>
48
+ <h1><%= h(page.fetch("title")) %></h1>
49
+ <p class="lead"><%= inline(page.fetch("lead")) %></p>
50
+ </div>
51
+ <% if page["kind"] == "component" %>
52
+ <section class="doc-section" id="import"><h2>Import</h2>
53
+ <p>Load the optional component layer before using the examples below.</p>
54
+ <div class="code-example"><div class="code-label">Ruby</div><pre><code>require "zaniah/ui"</code></pre></div>
55
+ </section>
56
+ <% end %>
57
+
58
+ <% if page["kind"] == "index" %>
59
+ <% index_groups.each do |group| %>
60
+ <% items = groups.fetch(group) %>
61
+ <% items = items.reject { |item| item["kind"] == "index" } %>
62
+ <section class="doc-section" id="<%= h(group.downcase.gsub(/[^a-z0-9]+/, "-")) %>">
63
+ <h2><%= h(group) %></h2>
64
+ <div class="directory">
65
+ <% items.each do |item| %>
66
+ <a href="<%= link_from(path, item.fetch("path")) %>"><strong><%= h(item.fetch("title")) %></strong><span><%= h(item.fetch("lead")) %></span></a>
67
+ <% end %>
68
+ </div>
69
+ </section>
70
+ <% end %>
71
+ <% elsif page["kind"] == "markdown" %>
72
+ <article class="markdown"><%= guide_html %></article>
73
+ <% else %>
74
+ <% page.fetch("sections", []).each do |section| %>
75
+ <section class="doc-section" id="<%= section_id(section) %>">
76
+ <h2><%= h(section.fetch("heading")) %></h2>
77
+ <% Array(section["text"]).each do |paragraph| %><p><%= inline(paragraph) %></p><% end %>
78
+ <% if section["image"] %>
79
+ <% image_width, image_height = image_dimensions(section.fetch("image")) %>
80
+ <figure class="example"><div class="example-label">Rendered example</div><img src="<%= link_from(path, section.fetch("image")) %>" alt="<%= h(section.fetch("alt")) %>" width="<%= image_width %>" height="<%= image_height %>" loading="lazy"><figcaption>Rendered by Zaniah's headless backend.</figcaption></figure>
81
+ <% end %>
82
+ <% if section["code"] %>
83
+ <div class="code-example"><div class="code-label"><%= h(section.fetch("code_label", "Ruby")) %></div><pre><code><%= h(section.fetch("code")) %></code></pre></div>
84
+ <% end %>
85
+ <% if section["note"] %><p class="note"><%= inline(section.fetch("note")) %></p><% end %>
86
+ </section>
87
+ <% end %>
88
+ <% if page["kind"] == "component" %>
89
+ <section class="doc-section" id="api"><h2>API summary</h2><p>Constructor options and behaviors are drawn from the <a href="<%= link_from(path, "guides/component-reference.html") %>">component reference</a>.</p>
90
+ <div class="table-scroll"><table><thead><tr><th>Component</th><th>Constructor and methods</th><th>Variants or behavior</th></tr></thead><tbody>
91
+ <% rows.each do |row| %><tr><td><code><%= h(row[:names].join(", ")) %></code></td><td><%= inline(row[:constructor]) %></td><td><%= inline(row[:variants]) %></td></tr><% end %>
92
+ </tbody></table></div>
93
+ </section>
94
+ <section class="doc-section" id="accessibility"><h2>Accessibility</h2>
95
+ <% if page["a11y"] %><p><%= inline(page["a11y"]) %></p><% end %>
96
+ <div class="table-scroll"><table><thead><tr><th>Component</th><th>Semantic role</th></tr></thead><tbody>
97
+ <% rows.each do |row| %><tr><td><code><%= h(row[:names].join(", ")) %></code></td><td><%= h(row[:role]) %></td></tr><% end %>
98
+ </tbody></table></div>
99
+ </section>
100
+ <% end %>
101
+ <% end %>
102
+
103
+ <nav class="pagination" aria-label="Adjacent pages">
104
+ <% if previous_page %><a href="<%= link_from(path, previous_page.fetch("path")) %>"><small>Previous</small><strong><%= h(previous_page.fetch("title")) %></strong></a><% end %>
105
+ <% if next_page %><a href="<%= link_from(path, next_page.fetch("path")) %>"><small>Next</small><strong><%= h(next_page.fetch("title")) %></strong></a><% end %>
106
+ </nav>
107
+ </main>
108
+
109
+ <aside class="toc" aria-label="On this page"><p>On this page</p>
110
+ <% if page["kind"] == "index" %>
111
+ <% index_groups.each do |group| %><a href="#<%= h(group.downcase.gsub(/[^a-z0-9]+/, "-")) %>"><%= h(group) %></a><% end %>
112
+ <% elsif page["kind"] == "markdown" %>
113
+ <% guide_toc.each do |anchor, heading| %><a href="#<%= h(anchor) %>"><%= heading %></a><% end %>
114
+ <% else %>
115
+ <% if page["kind"] == "component" %><a href="#import">Import</a><% end %>
116
+ <% page.fetch("sections", []).each do |section| %><a href="#<%= section_id(section) %>"><%= h(section.fetch("heading")) %></a><% end %>
117
+ <% if page["kind"] == "component" %><a href="#api">API summary</a><a href="#accessibility">Accessibility</a><% end %>
118
+ <% end %>
119
+ </aside>
120
+ </div>
121
+ <footer class="site-footer"><span>Zaniah is open source under the MIT License.</span><a href="https://github.com/noxdea/zaniah">Source on GitHub</a></footer>
122
+ </body>
123
+ </html>
data/docs/components.md CHANGED
@@ -21,10 +21,21 @@ Zaniah::UI::Button.variants[:variant][:brand] = ->(theme) {
21
21
  }
22
22
  ```
23
23
 
24
+ `VirtualTable`, `HexView`, and `TreeView` accept `viewport_height=` when a window
25
+ or split pane resizes. This updates their internal list viewport while retaining
26
+ scroll state and selection. `VirtualTable#follow_tail=` toggles bottom following;
27
+ call `scroll_to(source.count - 1, align: :end)` to resume immediately from elsewhere.
28
+
29
+ `TreeView#on_context_menu { |item, cx| menu }` selects the item under a right
30
+ click before opening the returned menu at the pointer. The callback receives the
31
+ same item value as `on_select`.
32
+
24
33
  ## Component reference
25
34
 
26
35
  | Layer | Component | Main constructor/options | Variants | Accessibility role |
27
36
  | --- | --- | --- | --- | --- |
37
+ | L4 | `VirtualTable` | `(source, columns:, height:, row_height:, selection:, follow_tail:)`; lazy `count`/`cell` source | stable row IDs, sortable/resizable headers, column visibility/order, row colors | table |
38
+ | L4 | `HexView` | `(bytes, bytes_per_row:, group:, offset_digits:, height:)`; `highlights=`, `select`, `scroll_to_offset` | viewport rows; synchronized hex/ASCII selection and copying | group |
28
39
  | L0 | `Label` | `(text, tone:, size:, wrap:)` | tone: default/muted/inverse; size: xs–xl | text |
29
40
  | L0 | `Icon` | `(source, size:, color:, label:)` | bundled: check/close/search/menu/info/warning | image when labeled |
30
41
  | L0 | `Divider` | `(axis:)` | horizontal/vertical | separator |
@@ -56,7 +67,7 @@ Zaniah::UI::Button.variants[:variant][:brand] = ->(theme) {
56
67
  | L2 | `ContextMenu`, `Menu` | `(items, anchor:, open:)` | pointer + arrows/Home/End/Enter/Esc | menu/menuitem |
57
68
  | L2 | `MenuBar` | `(menus)` or `.from(app.menu_bar)` | declarative menu model or legacy pairs | menubar |
58
69
  | L2 | `Dropdown` | `(label, items:, value:)`; `on_change` | menu-backed | button |
59
- | L2 | `TextField` | `(value, placeholder:, label:, prefix:, suffix:, error:, max_length:, clearable:)` | IME, selection, counter | textbox |
70
+ | L2 | `TextField` | `(value, placeholder:, label:, prefix:, suffix:, error:, max_length:, clearable:)`; `status(kind, message:)`, `completion(provider)` | IME, selection, counter, validation, token completion | textbox |
60
71
  | L2 | `TextArea` | TextField plus `rows:` | multiline/wrapped | textbox/multiline |
61
72
  | L2 | `SearchInput` | TextField options | search + clear icons | searchbox |
62
73
  | L2 | `PasswordInput` | TextField options | masked display | textbox |
@@ -93,7 +104,7 @@ Zaniah::UI::Button.variants[:variant][:brand] = ->(theme) {
93
104
  | L3 | `ListView` | `(items, height:, row_height:, selected:)`; `on_select` | virtual rows and keyboard selection | list/listitem |
94
105
  | L4 | `Table`, `DataGrid` | `(rows, columns:, height:, selection:, row_key:)`; `on_sort`, `on_select`, `on_edit`, `on_copy`, `on_paste` | virtual rows, sorting, resizing, editing, typed clipboard hooks | table/row/cell |
95
106
  | L4 | `Grid` | `(rows:, columns:, row_height:, column_width:, frozen_rows:, frozen_columns:)`; `scroll_to`, range `selection`, `on_select`, `on_edit`, `on_fill`, `on_resize`, `on_copy`, `on_paste` | two-axis virtualization, frozen panes, visible-cell resize/fill and typed clipboard hooks | table |
96
- | L4 | `TreeView` | `(items, height:, selected:)`; `expand`, `collapse`, `replace`, `replace_children`, `invalidate`, lazy `children` proc | arrows/Home/End | tree/treeitem |
107
+ | L4 | `TreeView` | `(items, height:, selected:)`; `select_id`, `on_context_menu`, `expand`, `collapse`, `replace`, `replace_children`, `invalidate`, lazy `children` proc | arrows/Home/End | tree/treeitem |
97
108
  | L4 | `PropertyGrid` | `(schema, values, height:, row_height:)`; `on_change`, `set` | typed existing controls, `Validation`, virtual rows | table/row/cell |
98
109
  | L5 | `Sparkline` | `(values, width:, height:, color:, label:)` | line + tooltip | image |
99
110
  | L5 | `LineChart`, `BarChart`, `StackedBarChart`, `AreaChart` | `(series, width:, height:, colors:, label:)`; `AreaChart(stacked:)` | shared axes, ticks, grid lines, color-keyed legend, tooltip | image |
@@ -199,6 +210,3 @@ resize. Grid and Table clipboard hooks receive half-open `Grid::Area` ranges;
199
210
  Table areas follow the current display order without changing its stable-ID
200
211
  selection. See [Layout](layout.md#two-axis-virtual-grid). Tree views use Up/Down to select, Right to expand or enter the first child,
201
212
  and Left to collapse or return to the parent.
202
-
203
- Run `bundle exec ruby tools/generate_component_gallery.rb` to rebuild the dark,
204
- light, and high-contrast component sheets plus overlay variants in all three themes.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/docs/inspection.md CHANGED
@@ -16,4 +16,6 @@ Zaniah::Inspection.perform(window, node, :press)
16
16
 
17
17
  The snapshot containers and copied collections are frozen. `entry.element` is deliberately a live element reference: use it only in the same frame, because the next render may replace it. Accessibility nodes are copied for inspection; pass one to `Inspection.perform` to invoke an action on its current source node. Actions require a node from the current frame. To wait for a settled UI, call `Zaniah::Inspection.idle?(app)` after draining queued work and rendering dirty windows.
18
18
 
19
- The public API is declared in [`sig/inspection.rbs`](../sig/inspection.rbs), and its independently runnable contract test is [`test/inspection_contract_test.rb`](../test/inspection_contract_test.rb). Breaking changes receive at least one minor version of deprecation during 0.x, as recorded in [ADR 013](adr/013-public-inspection-api.md).
19
+ The public API is declared in [`sig/inspection.rbs`](../sig/inspection.rbs).
20
+ Breaking changes receive at least one minor version of deprecation during 0.x,
21
+ as recorded in [ADR 013](adr/013-public-inspection-api.md).
data/docs/layout.md CHANGED
@@ -96,14 +96,6 @@ remains a set of stable row IDs; hook arguments are `Grid::Area` ranges in the
96
96
  current sorted display order, covering all columns. Disjoint selected rows
97
97
  produce separate areas. The application retains ownership of table data.
98
98
 
99
- `bench/grid.rb` measures a headless 800×600 viewport over a 1,000,000×16,000
100
- grid at 23 sequential scroll positions, including cell construction, layout,
101
- prepaint, and paint. `BUDGET=1 ruby bench/grid.rb` asserts a 16.67 ms median
102
- frame limit. A local run on 2026-09-23 measured 12.964 ms and constructed an
103
- average of 250 cells per frame. This microbenchmark does not include an
104
- application's backing store, expensive cell renderers, or a native compositor;
105
- rerun it on target hardware for deployment decisions.
106
-
107
99
  `ScrollView` accepts one child and clips it to the viewport. Its `axis` is
108
100
  `:vertical`, `:horizontal`, or `:both`; use `scroll_to` for programmatic
109
101
  scrolling and `scroll_state` for offsets and edge checks.
data/docs/native.md CHANGED
@@ -42,6 +42,18 @@ file drops, fullscreen, cursors, URL opening, file dialogs, appearance changes,
42
42
  and PNG capture. Platform availability differs; see [the RBS declarations](../sig/native.rbs)
43
43
  and [platform declarations](../sig/platform.rbs) for the exact API.
44
44
 
45
+ ## File dialogs
46
+
47
+ Native file dialogs accept a starting directory, suggested filename, and extension filters:
48
+
49
+ ```ruby
50
+ window.prompt_for_paths(save: true, default_name: "capture.pcapng", directory: Dir.home,
51
+ filters: [{label: "Capture files", patterns: ["*.pcapng", "*.pcap"]}])
52
+ ```
53
+
54
+ Patterns support `*` and `*.extension`. macOS combines the allowed extensions;
55
+ Linux and Windows also show each named filter. Cancel returns an empty array.
56
+
45
57
  ## Clipboard representations
46
58
 
47
59
  `Clipboard::Item` holds eager MIME-keyed data. `text/*` values are UTF-8 text;
@@ -145,20 +157,3 @@ On Windows, require `zaniah/platform/windows/terminal` to use
145
157
  `Zaniah::Platform::Windows::Terminal`, which wraps ConPTY. It supports starting
146
158
  a child process, nonblocking reads, writes, resizing, liveness checks, and
147
159
  explicit cleanup. ConPTY requires Windows 10 version 1809 or later.
148
-
149
- ## Development checks
150
-
151
- Run checks on the matching host and display server:
152
-
153
- ```sh
154
- ruby examples/native_smoke.rb --check /tmp/zaniah.png
155
- ruby examples/native_smoke.rb --gl --check /tmp/zaniah-gl.png
156
- ruby examples/linux_smoke.rb
157
- ruby examples/linux_smoke.rb --wayland
158
- ruby examples/native_watch.rb
159
- ruby examples/native_menu.rb # macOS only
160
- ```
161
-
162
- Linux XIM composition is exercised in CI with Xvfb and IBus/KKC. Native input,
163
- IME on macOS and Windows, dialogs, and terminal integration also require manual
164
- checks on the target operating system.