@gjsify/example-gtk-adwaita-storybook 0.53.0 → 0.55.0

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 (243) hide show
  1. package/dist/browser-main.js +8093 -3042
  2. package/dist/gjs.js +15 -10
  3. package/dist/gjs.node.mjs +10 -5
  4. package/package.json +5 -5
  5. package/src/browser/buttons/color-dialog-button.web.ts +42 -0
  6. package/src/browser/buttons/font-dialog-button.web.ts +42 -0
  7. package/src/browser/buttons/link-button.web.ts +37 -0
  8. package/src/browser/buttons/scale-button.web.ts +36 -0
  9. package/src/browser/buttons/toggle-button.web.ts +35 -0
  10. package/src/browser/controls/check-button.web.ts +38 -0
  11. package/src/browser/controls/gtk-spinner.web.ts +39 -0
  12. package/src/browser/controls/level-bar.web.ts +43 -0
  13. package/src/browser/controls/password-entry.web.ts +36 -0
  14. package/src/browser/controls/progress-bar.web.ts +39 -0
  15. package/src/browser/controls/scale.web.ts +44 -0
  16. package/src/browser/controls/search-entry.web.ts +49 -0
  17. package/src/browser/controls/spin-button.web.ts +40 -0
  18. package/src/browser/controls/switch.web.ts +38 -0
  19. package/src/browser/drawing/drag-icon.web.ts +112 -0
  20. package/src/browser/drawing/drawing-area.web.ts +66 -0
  21. package/src/browser/drawing/gl-area.web.ts +162 -0
  22. package/src/browser/drawing/graphics-offload.web.ts +74 -0
  23. package/src/browser/feedback/dialog.web.ts +76 -0
  24. package/src/browser/feedback/emoji-chooser.web.ts +93 -0
  25. package/src/browser/feedback/gtk-about-dialog.web.ts +105 -0
  26. package/src/browser/feedback/page-setup-unix-dialog.web.ts +93 -0
  27. package/src/browser/feedback/print-unix-dialog.web.ts +111 -0
  28. package/src/browser/feedback/shortcuts-dialog.web.ts +90 -0
  29. package/src/browser/layout/application-window.web.ts +94 -0
  30. package/src/browser/layout/aspect-frame.web.ts +49 -0
  31. package/src/browser/layout/bin.web.ts +41 -0
  32. package/src/browser/layout/breakpoint-bin.web.ts +61 -0
  33. package/src/browser/layout/center-box.web.ts +45 -0
  34. package/src/browser/layout/clamp-scrollable.web.ts +47 -0
  35. package/src/browser/layout/expander.web.ts +52 -0
  36. package/src/browser/layout/fixed.web.ts +51 -0
  37. package/src/browser/layout/frame.web.ts +40 -0
  38. package/src/browser/layout/grid.web.ts +46 -0
  39. package/src/browser/layout/layout-slot.web.ts +60 -0
  40. package/src/browser/layout/multi-layout-view.web.ts +94 -0
  41. package/src/browser/layout/overlay.web.ts +57 -0
  42. package/src/browser/layout/paned.web.ts +69 -0
  43. package/src/browser/layout/popover-bin.web.ts +54 -0
  44. package/src/browser/layout/popover-menu.web.ts +48 -0
  45. package/src/browser/layout/popover.web.ts +61 -0
  46. package/src/browser/layout/revealer.web.ts +53 -0
  47. package/src/browser/layout/scrollbar.web.ts +54 -0
  48. package/src/browser/layout/scrolled-window.web.ts +52 -0
  49. package/src/browser/layout/separator.web.ts +47 -0
  50. package/src/browser/layout/viewport.web.ts +51 -0
  51. package/src/browser/layout/window.web.ts +60 -0
  52. package/src/browser/media/image.web.ts +39 -0
  53. package/src/browser/media/inscription.web.ts +52 -0
  54. package/src/browser/media/media-controls.web.ts +65 -0
  55. package/src/browser/media/picture.web.ts +56 -0
  56. package/src/browser/media/video.web.ts +56 -0
  57. package/src/browser/navigation/popover-menu-bar.web.ts +40 -0
  58. package/src/browser/presentation/calendar.web.ts +49 -0
  59. package/src/browser/presentation/column-view.web.ts +45 -0
  60. package/src/browser/presentation/flow-box.web.ts +52 -0
  61. package/src/browser/presentation/grid-view.web.ts +37 -0
  62. package/src/browser/presentation/list-box.web.ts +48 -0
  63. package/src/browser/presentation/list-view.web.ts +36 -0
  64. package/src/browser/presentation/tree-expander.web.ts +68 -0
  65. package/src/browser/presentation/window-handle.web.ts +42 -0
  66. package/src/browser/rows/preferences-row.web.ts +43 -0
  67. package/src/browser/stories.ts +158 -0
  68. package/src/browser/text/editable-label.web.ts +45 -0
  69. package/src/browser/text/search-bar.web.ts +45 -0
  70. package/src/browser/text/text-view.web.ts +54 -0
  71. package/src/browser/text/text.web.ts +48 -0
  72. package/src/browser/view-switching/notebook.web.ts +67 -0
  73. package/src/browser/view-switching/stack-sidebar.web.ts +68 -0
  74. package/src/browser/view-switching/stack-switcher.web.ts +70 -0
  75. package/src/browser/view-switching/stack.web.ts +72 -0
  76. package/src/browser/view-switching/tab-bar.web.ts +105 -0
  77. package/src/browser/view-switching/tab-button.web.ts +52 -0
  78. package/src/browser/view-switching/tab-overview.web.ts +87 -0
  79. package/src/browser/view-switching/view-switcher-sidebar.web.ts +77 -0
  80. package/src/browser/windows/action-bar.web.ts +66 -0
  81. package/src/browser/windows/gtk-application-window.web.ts +67 -0
  82. package/src/browser/windows/gtk-header-bar.web.ts +61 -0
  83. package/src/browser/windows/gtk-window.web.ts +58 -0
  84. package/src/browser/windows/window-controls.web.ts +54 -0
  85. package/src/buttons/color-dialog-button.meta.ts +16 -0
  86. package/src/buttons/color-dialog-button.story.ts +49 -0
  87. package/src/buttons/font-dialog-button.meta.ts +29 -0
  88. package/src/buttons/font-dialog-button.story.ts +52 -0
  89. package/src/buttons/link-button.meta.ts +18 -0
  90. package/src/buttons/link-button.story.ts +48 -0
  91. package/src/buttons/scale-button.meta.ts +34 -0
  92. package/src/buttons/scale-button.story.ts +50 -0
  93. package/src/buttons/toggle-button.meta.ts +17 -0
  94. package/src/buttons/toggle-button.story.ts +46 -0
  95. package/src/controls/check-button.meta.ts +19 -0
  96. package/src/controls/check-button.story.ts +56 -0
  97. package/src/controls/gtk-spinner.meta.ts +24 -0
  98. package/src/controls/gtk-spinner.story.ts +53 -0
  99. package/src/controls/level-bar.meta.ts +39 -0
  100. package/src/controls/level-bar.story.ts +58 -0
  101. package/src/controls/password-entry.meta.ts +18 -0
  102. package/src/controls/password-entry.story.ts +54 -0
  103. package/src/controls/progress-bar.meta.ts +20 -0
  104. package/src/controls/progress-bar.story.ts +53 -0
  105. package/src/controls/scale.meta.ts +47 -0
  106. package/src/controls/scale.story.ts +66 -0
  107. package/src/controls/search-entry.meta.ts +18 -0
  108. package/src/controls/search-entry.story.ts +57 -0
  109. package/src/controls/spin-button.meta.ts +40 -0
  110. package/src/controls/spin-button.story.ts +55 -0
  111. package/src/controls/switch.meta.ts +18 -0
  112. package/src/controls/switch.story.ts +50 -0
  113. package/src/drawing/drag-icon.meta.ts +39 -0
  114. package/src/drawing/drag-icon.story.ts +117 -0
  115. package/src/drawing/drawing-area.meta.ts +45 -0
  116. package/src/drawing/drawing-area.story.ts +78 -0
  117. package/src/drawing/gl-area.meta.ts +30 -0
  118. package/src/drawing/gl-area.story.ts +113 -0
  119. package/src/drawing/graphics-offload.meta.ts +39 -0
  120. package/src/drawing/graphics-offload.story.ts +73 -0
  121. package/src/feedback/dialog.meta.ts +25 -0
  122. package/src/feedback/dialog.story.ts +78 -0
  123. package/src/feedback/emoji-chooser.meta.ts +10 -0
  124. package/src/feedback/emoji-chooser.story.ts +98 -0
  125. package/src/feedback/gtk-about-dialog.meta.ts +29 -0
  126. package/src/feedback/gtk-about-dialog.story.ts +90 -0
  127. package/src/feedback/page-setup-unix-dialog.meta.ts +37 -0
  128. package/src/feedback/page-setup-unix-dialog.story.ts +70 -0
  129. package/src/feedback/print-unix-dialog.meta.ts +30 -0
  130. package/src/feedback/print-unix-dialog.story.ts +93 -0
  131. package/src/feedback/shortcuts-dialog.meta.ts +12 -0
  132. package/src/feedback/shortcuts-dialog.story.ts +79 -0
  133. package/src/layout/application-window.meta.ts +16 -0
  134. package/src/layout/application-window.story.ts +97 -0
  135. package/src/layout/aspect-frame.meta.ts +19 -0
  136. package/src/layout/aspect-frame.story.ts +62 -0
  137. package/src/layout/bin.meta.ts +15 -0
  138. package/src/layout/bin.story.ts +56 -0
  139. package/src/layout/breakpoint-bin.meta.ts +38 -0
  140. package/src/layout/breakpoint-bin.story.ts +62 -0
  141. package/src/layout/center-box.meta.ts +26 -0
  142. package/src/layout/center-box.story.ts +54 -0
  143. package/src/layout/clamp-scrollable.meta.ts +30 -0
  144. package/src/layout/clamp-scrollable.story.ts +51 -0
  145. package/src/layout/expander.meta.ts +30 -0
  146. package/src/layout/expander.story.ts +62 -0
  147. package/src/layout/fixed.meta.ts +16 -0
  148. package/src/layout/fixed.story.ts +54 -0
  149. package/src/layout/frame.meta.ts +24 -0
  150. package/src/layout/frame.story.ts +51 -0
  151. package/src/layout/grid.meta.ts +45 -0
  152. package/src/layout/grid.story.ts +80 -0
  153. package/src/layout/layout-slot.meta.ts +22 -0
  154. package/src/layout/layout-slot.story.ts +68 -0
  155. package/src/layout/multi-layout-view.meta.ts +31 -0
  156. package/src/layout/multi-layout-view.story.ts +101 -0
  157. package/src/layout/overlay.meta.ts +42 -0
  158. package/src/layout/overlay.story.ts +72 -0
  159. package/src/layout/paned.meta.ts +45 -0
  160. package/src/layout/paned.story.ts +70 -0
  161. package/src/layout/popover-bin.meta.ts +29 -0
  162. package/src/layout/popover-bin.story.ts +66 -0
  163. package/src/layout/popover-menu.meta.ts +54 -0
  164. package/src/layout/popover-menu.story.ts +119 -0
  165. package/src/layout/popover.meta.ts +38 -0
  166. package/src/layout/popover.story.ts +66 -0
  167. package/src/layout/revealer.meta.ts +44 -0
  168. package/src/layout/revealer.story.ts +79 -0
  169. package/src/layout/scrollbar.meta.ts +33 -0
  170. package/src/layout/scrollbar.story.ts +61 -0
  171. package/src/layout/scrolled-window.meta.ts +57 -0
  172. package/src/layout/scrolled-window.story.ts +74 -0
  173. package/src/layout/separator.meta.ts +25 -0
  174. package/src/layout/separator.story.ts +53 -0
  175. package/src/layout/viewport.meta.ts +19 -0
  176. package/src/layout/viewport.story.ts +53 -0
  177. package/src/layout/window.meta.ts +13 -0
  178. package/src/layout/window.story.ts +66 -0
  179. package/src/media/image.meta.ts +24 -0
  180. package/src/media/image.story.ts +48 -0
  181. package/src/media/inscription.meta.ts +45 -0
  182. package/src/media/inscription.story.ts +64 -0
  183. package/src/media/media-controls.meta.ts +30 -0
  184. package/src/media/media-controls.story.ts +58 -0
  185. package/src/media/picture.meta.ts +42 -0
  186. package/src/media/picture.story.ts +81 -0
  187. package/src/media/video.meta.ts +32 -0
  188. package/src/media/video.story.ts +57 -0
  189. package/src/metas.ts +79 -0
  190. package/src/navigation/popover-menu-bar.meta.ts +51 -0
  191. package/src/navigation/popover-menu-bar.story.ts +72 -0
  192. package/src/presentation/calendar.meta.ts +28 -0
  193. package/src/presentation/calendar.story.ts +64 -0
  194. package/src/presentation/column-view.meta.ts +30 -0
  195. package/src/presentation/column-view.story.ts +73 -0
  196. package/src/presentation/flow-box.meta.ts +51 -0
  197. package/src/presentation/flow-box.story.ts +72 -0
  198. package/src/presentation/grid-view.meta.ts +28 -0
  199. package/src/presentation/grid-view.story.ts +64 -0
  200. package/src/presentation/list-box.meta.ts +55 -0
  201. package/src/presentation/list-box.story.ts +68 -0
  202. package/src/presentation/list-view.meta.ts +38 -0
  203. package/src/presentation/list-view.story.ts +73 -0
  204. package/src/presentation/tree-expander.meta.ts +24 -0
  205. package/src/presentation/tree-expander.story.ts +105 -0
  206. package/src/presentation/window-handle.meta.ts +27 -0
  207. package/src/presentation/window-handle.story.ts +53 -0
  208. package/src/rows/preferences-row.meta.ts +15 -0
  209. package/src/rows/preferences-row.story.ts +50 -0
  210. package/src/text/editable-label.meta.ts +17 -0
  211. package/src/text/editable-label.story.ts +47 -0
  212. package/src/text/search-bar.meta.ts +17 -0
  213. package/src/text/search-bar.story.ts +48 -0
  214. package/src/text/text-view.meta.ts +49 -0
  215. package/src/text/text-view.story.ts +69 -0
  216. package/src/text/text.meta.ts +21 -0
  217. package/src/text/text.story.ts +50 -0
  218. package/src/view-switching/notebook.meta.ts +44 -0
  219. package/src/view-switching/notebook.story.ts +77 -0
  220. package/src/view-switching/stack-sidebar.meta.ts +50 -0
  221. package/src/view-switching/stack-sidebar.story.ts +85 -0
  222. package/src/view-switching/stack-switcher.meta.ts +53 -0
  223. package/src/view-switching/stack-switcher.story.ts +95 -0
  224. package/src/view-switching/stack.meta.ts +53 -0
  225. package/src/view-switching/stack.story.ts +95 -0
  226. package/src/view-switching/tab-bar.meta.ts +22 -0
  227. package/src/view-switching/tab-bar.story.ts +85 -0
  228. package/src/view-switching/tab-button.meta.ts +14 -0
  229. package/src/view-switching/tab-button.story.ts +52 -0
  230. package/src/view-switching/tab-overview.meta.ts +21 -0
  231. package/src/view-switching/tab-overview.story.ts +86 -0
  232. package/src/view-switching/view-switcher-sidebar.meta.ts +42 -0
  233. package/src/view-switching/view-switcher-sidebar.story.ts +73 -0
  234. package/src/windows/action-bar.meta.ts +27 -0
  235. package/src/windows/action-bar.story.ts +65 -0
  236. package/src/windows/gtk-application-window.meta.ts +27 -0
  237. package/src/windows/gtk-application-window.story.ts +89 -0
  238. package/src/windows/gtk-header-bar.meta.ts +39 -0
  239. package/src/windows/gtk-header-bar.story.ts +76 -0
  240. package/src/windows/gtk-window.meta.ts +30 -0
  241. package/src/windows/gtk-window.story.ts +64 -0
  242. package/src/windows/window-controls.meta.ts +42 -0
  243. package/src/windows/window-controls.story.ts +61 -0
@@ -0,0 +1,53 @@
1
+ // Gtk.Separator — the rule between two groups, and the .spacer gap.
2
+ // original implementation.
3
+
4
+ import Gtk from 'gi://Gtk?version=4.0';
5
+ import GObject from 'gi://GObject?version=2.0';
6
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
7
+ import { separatorMeta } from './separator.meta.js';
8
+
9
+ /** Story: a Gtk.Separator between two labels, in the box direction that makes it visible. */
10
+ export class SeparatorStory extends StoryWidget {
11
+ private _box: Gtk.Box | null = null;
12
+ private _separator: Gtk.Separator | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookSeparator' }, SeparatorStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(SeparatorStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...separatorMeta, component: Gtk.Separator.$gtype };
24
+ }
25
+
26
+ initialize(): void {
27
+ this._separator = new Gtk.Separator();
28
+ this._box = new Gtk.Box({ spacing: 12, halign: Gtk.Align.CENTER });
29
+ this._box.append(new Gtk.Label({ label: 'Above' }));
30
+ this._box.append(this._separator);
31
+ this._box.append(new Gtk.Label({ label: 'Below' }));
32
+ this._apply();
33
+ this.addContent(this._box);
34
+ }
35
+
36
+ updateArgs(_args: StoryArgs): void {
37
+ this._apply();
38
+ }
39
+
40
+ private _apply(): void {
41
+ if (!this._box || !this._separator) return;
42
+ const vertical = this.args.orientation === 'vertical';
43
+ this._separator.orientation = vertical ? Gtk.Orientation.VERTICAL : Gtk.Orientation.HORIZONTAL;
44
+ // A rule runs ACROSS its box, so the box runs the other way.
45
+ this._box.orientation = vertical ? Gtk.Orientation.HORIZONTAL : Gtk.Orientation.VERTICAL;
46
+ if (this.args.spacer as boolean) this._separator.add_css_class('spacer');
47
+ else this._separator.remove_css_class('spacer');
48
+ }
49
+ }
50
+
51
+ GObject.type_ensure(SeparatorStory.$gtype);
52
+
53
+ export const SeparatorStories: StoryModule = { stories: [SeparatorStory] };
@@ -0,0 +1,19 @@
1
+ // Shared, renderer-agnostic metadata for the Viewport story. Imported by the GTK renderer
2
+ // (layout/viewport.story.ts) and the browser renderer (browser/layout/viewport.web.ts), so
3
+ // both expose identical controls.
4
+
5
+ // THE CONTROL NAME IS A CAMEL-CASE ARG NAME, not the GIR spelling: the control panel's
6
+ // reader takes `name` as an identifier (`scripts/check-storybook-control-parity.mjs` reads
7
+ // `\bname:\s*'([A-Za-z0-9_]+)'`), and each renderer writes it onto the property whose own
8
+ // name it is — `scroll-to-focus` here.
9
+
10
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
11
+
12
+ export const viewportMeta: StoryMeta = {
13
+ title: 'Layout/Viewport',
14
+ description:
15
+ 'Gtk.Viewport — scrollability for a widget that has none of its own. It has one ' +
16
+ 'property, scroll-to-focus: whether a widget that takes the focus is scrolled into ' +
17
+ 'view. It is also what a Gtk.ScrolledWindow puts its child in.',
18
+ controls: [{ name: 'scrollToFocus', label: 'Scroll to focus', type: ControlType.BOOLEAN, defaultValue: true }],
19
+ };
@@ -0,0 +1,53 @@
1
+ // Gtk.Viewport — a column in a window that clips it, with the focus behaviour bound to args.
2
+ // original implementation.
3
+
4
+ import Gtk from 'gi://Gtk?version=4.0';
5
+ import GObject from 'gi://GObject?version=2.0';
6
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
7
+ import { viewportMeta } from './viewport.meta.js';
8
+
9
+ /** Story: a Gtk.Viewport over a column of labels and a focusable button at its end. */
10
+ export class ViewportStory extends StoryWidget {
11
+ private _viewport: Gtk.Viewport | null = null;
12
+
13
+ static {
14
+ GObject.registerClass({ GTypeName: 'AdwStorybookViewport' }, ViewportStory);
15
+ }
16
+
17
+ constructor() {
18
+ super(StoryWidget.fromMeta(ViewportStory.getMetadata(), 'Default'));
19
+ }
20
+
21
+ static getMetadata(): StoryMeta {
22
+ return { ...viewportMeta, component: Gtk.Viewport.$gtype };
23
+ }
24
+
25
+ initialize(): void {
26
+ const box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, spacing: 8 });
27
+ for (let i = 1; i <= 16; i++) {
28
+ box.append(new Gtk.Label({ label: `Row ${i}` }));
29
+ }
30
+ // The one widget whose focus a viewport acts on, so the property has something to
31
+ // reveal: with it off, tabbing to the button leaves it below the edge.
32
+ box.append(new Gtk.Button({ label: 'Focus me', halign: Gtk.Align.START }));
33
+ this._viewport = new Gtk.Viewport({
34
+ child: box,
35
+ halign: Gtk.Align.CENTER,
36
+ });
37
+ this._apply();
38
+ this.addContent(this._viewport);
39
+ }
40
+
41
+ updateArgs(_args: StoryArgs): void {
42
+ this._apply();
43
+ }
44
+
45
+ private _apply(): void {
46
+ if (!this._viewport) return;
47
+ this._viewport.set_scroll_to_focus(this.args.scrollToFocus as boolean);
48
+ }
49
+ }
50
+
51
+ GObject.type_ensure(ViewportStory.$gtype);
52
+
53
+ export const ViewportStories: StoryModule = { stories: [ViewportStory] };
@@ -0,0 +1,13 @@
1
+ // Shared, renderer-agnostic metadata for the Window story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const windowMeta: StoryMeta = {
6
+ title: 'Layout/Window',
7
+ description:
8
+ 'Adw.Window — a freeform window with no titlebar area. Use Adw.ToolbarView with Adw.HeaderBar for the top chrome.',
9
+ controls: [
10
+ { name: 'title', label: 'Title', type: ControlType.TEXT, defaultValue: 'Text Editor' },
11
+ { name: 'subtitle', label: 'Subtitle', type: ControlType.TEXT, defaultValue: 'notes.md' },
12
+ ],
13
+ };
@@ -0,0 +1,66 @@
1
+ // Adw.Window — a freeform window with a header bar and content.
2
+ // original implementation.
3
+
4
+ import Adw from 'gi://Adw?version=1';
5
+ import Gtk from 'gi://Gtk?version=4.0';
6
+ import GObject from 'gi://GObject?version=2.0';
7
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
8
+ import { windowMeta } from './window.meta.js';
9
+
10
+ /** Story: Adw.Window with a header bar and status page content. */
11
+ export class WindowStory extends StoryWidget {
12
+ private _window: Adw.Window | null = null;
13
+ private _title: Adw.WindowTitle | null = null;
14
+
15
+ static {
16
+ GObject.registerClass({ GTypeName: 'AdwStorybookWindow' }, WindowStory);
17
+ }
18
+
19
+ constructor() {
20
+ super(StoryWidget.fromMeta(WindowStory.getMetadata(), 'Default'));
21
+ }
22
+
23
+ static getMetadata(): StoryMeta {
24
+ return { ...windowMeta, component: Adw.Window.$gtype };
25
+ }
26
+
27
+ initialize(): void {
28
+ this._title = new Adw.WindowTitle({
29
+ title: this.args.title as string,
30
+ subtitle: this.args.subtitle as string,
31
+ });
32
+
33
+ const headerBar = new Adw.HeaderBar({ titleWidget: this._title, widthRequest: 460 });
34
+
35
+ const backButton = new Gtk.Button({ iconName: 'go-previous-symbolic' });
36
+ backButton.add_css_class('flat');
37
+ headerBar.pack_start(backButton);
38
+
39
+ const menuButton = new Gtk.MenuButton({ iconName: 'open-menu-symbolic' });
40
+ menuButton.add_css_class('flat');
41
+ headerBar.pack_end(menuButton);
42
+
43
+ const toolbarView = new Adw.ToolbarView();
44
+ toolbarView.add_top_bar(headerBar);
45
+
46
+ const statusPage = new Adw.StatusPage({
47
+ title: 'Your Library',
48
+ description: 'Content sits between the toolbars and scrolls independently of them.',
49
+ });
50
+ toolbarView.content = statusPage;
51
+
52
+ this._window = new Adw.Window({ content: toolbarView });
53
+
54
+ this.addContent(this._window);
55
+ }
56
+
57
+ updateArgs(_args: StoryArgs): void {
58
+ if (!this._title) return;
59
+ this._title.title = this.args.title as string;
60
+ this._title.subtitle = this.args.subtitle as string;
61
+ }
62
+ }
63
+
64
+ GObject.type_ensure(WindowStory.$gtype);
65
+
66
+ export const WindowStories: StoryModule = { stories: [WindowStory] };
@@ -0,0 +1,24 @@
1
+ // Shared, renderer-agnostic metadata for the Image story. Imported by the GTK
2
+ // renderer (image.story.ts) and the browser renderer (browser/media/image.web.ts),
3
+ // so both expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const imageMeta: StoryMeta = {
8
+ title: 'Media/Image',
9
+ description:
10
+ 'Gtk.Image — a symbolic icon, drawn as a CSS-masked box in the surrounding text colour. It takes a ' +
11
+ 'NAME, not a file: a name the icon theme cannot resolve draws the missing-image glyph, which is exactly ' +
12
+ 'what GTK draws for it. That is why <gtk-picture> is a separate widget — an icon sized by the theme and ' +
13
+ 'an image fitted to a box are two different jobs.',
14
+ controls: [
15
+ {
16
+ name: 'iconName',
17
+ label: 'Icon name',
18
+ type: ControlType.TEXT,
19
+ defaultValue: 'avatar-default-symbolic',
20
+ },
21
+ { name: 'size', label: 'Size (px)', type: ControlType.RANGE, min: 16, max: 96, step: 8, defaultValue: 48 },
22
+ { name: 'disabled', label: 'Disabled', type: ControlType.BOOLEAN, defaultValue: false },
23
+ ],
24
+ };
@@ -0,0 +1,48 @@
1
+ // Gtk.Image — the symbolic icon node, sized by the reader.
2
+ // original implementation.
3
+
4
+ import Gtk from 'gi://Gtk?version=4.0';
5
+ import GObject from 'gi://GObject?version=2.0';
6
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
7
+ import { imageMeta } from './image.meta.js';
8
+
9
+ /** Story: one Gtk.Image at the reader's size, with the name as the control. */
10
+ export class ImageStory extends StoryWidget {
11
+ private _image: Gtk.Image | null = null;
12
+
13
+ static {
14
+ GObject.registerClass({ GTypeName: 'AdwStorybookImage' }, ImageStory);
15
+ }
16
+
17
+ constructor() {
18
+ super(StoryWidget.fromMeta(ImageStory.getMetadata(), 'Default'));
19
+ }
20
+
21
+ static getMetadata(): StoryMeta {
22
+ return { ...imageMeta, component: Gtk.Image.$gtype };
23
+ }
24
+
25
+ initialize(): void {
26
+ this._image = new Gtk.Image({ halign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER });
27
+ this._apply();
28
+ this.addContent(this._image);
29
+ }
30
+
31
+ updateArgs(_args: StoryArgs): void {
32
+ this._apply();
33
+ }
34
+
35
+ private _apply(): void {
36
+ if (!this._image) return;
37
+ // `icon_size` is GTK's own ICON_SIZE enum, and a widget's measurement is made from the
38
+ // minimum AND the natural size of that enum (gtkspinner.c:110-123 is the same shape),
39
+ // so the size request is what actually grows the box.
40
+ this._image.icon_size = this.args.size as number as Gtk.IconSize;
41
+ this._image.icon_name = this.args.iconName as string;
42
+ this._image.sensitive = !(this.args.disabled as boolean);
43
+ }
44
+ }
45
+
46
+ GObject.type_ensure(ImageStory.$gtype);
47
+
48
+ export const ImageStories: StoryModule = { stories: [ImageStory] };
@@ -0,0 +1,45 @@
1
+ // Shared, renderer-agnostic metadata for the Inscription story. Imported by the GTK
2
+ // renderer (inscription.story.ts) and the browser renderer
3
+ // (browser/media/inscription.web.ts), so both expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const inscriptionMeta: StoryMeta = {
8
+ title: 'Media/Inscription',
9
+ description:
10
+ 'Gtk.Inscription — text laid out to a size in CHARACTERS and LINES rather than to a size in pixels. ' +
11
+ 'It is the widget for text whose extent should be the same everywhere, so it never measures its own ' +
12
+ 'content: min-chars/nat-chars and min-lines/nat-lines ARE its size request.',
13
+ controls: [
14
+ { name: 'text', label: 'Text', type: ControlType.TEXT, defaultValue: 'Inscription' },
15
+ { name: 'minChars', label: 'Min chars', type: ControlType.RANGE, min: 0, max: 40, step: 1, defaultValue: 3 },
16
+ { name: 'natChars', label: 'Nat chars', type: ControlType.RANGE, min: 0, max: 40, step: 1, defaultValue: 0 },
17
+ { name: 'minLines', label: 'Min lines', type: ControlType.RANGE, min: 0, max: 6, step: 1, defaultValue: 1 },
18
+ { name: 'natLines', label: 'Nat lines', type: ControlType.RANGE, min: 0, max: 6, step: 1, defaultValue: 0 },
19
+ {
20
+ name: 'wrapMode',
21
+ label: 'Wrap mode',
22
+ type: ControlType.SELECT,
23
+ options: [
24
+ { label: 'Word', value: 'word' },
25
+ { label: 'Char', value: 'char' },
26
+ { label: 'Word-char (default)', value: 'word-char' },
27
+ ],
28
+ defaultValue: 'word-char',
29
+ },
30
+ {
31
+ name: 'textOverflow',
32
+ label: 'Text overflow',
33
+ type: ControlType.SELECT,
34
+ options: [
35
+ { label: 'Clip (default)', value: 'clip' },
36
+ { label: 'Ellipsize start', value: 'ellipsize-start' },
37
+ { label: 'Ellipsize middle', value: 'ellipsize-middle' },
38
+ { label: 'Ellipsize end', value: 'ellipsize-end' },
39
+ ],
40
+ defaultValue: 'clip',
41
+ },
42
+ { name: 'xalign', label: 'X align', type: ControlType.RANGE, min: 0, max: 1, step: 0.05, defaultValue: 0 },
43
+ { name: 'yalign', label: 'Y align', type: ControlType.RANGE, min: 0, max: 1, step: 0.05, defaultValue: 0.5 },
44
+ ],
45
+ };
@@ -0,0 +1,64 @@
1
+ // Gtk.Inscription — text held to a size in characters and lines.
2
+ // original implementation.
3
+
4
+ import Gtk from 'gi://Gtk?version=4.0';
5
+ import GObject from 'gi://GObject?version=2.0';
6
+ import Pango from 'gi://Pango?version=1.0';
7
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
8
+ import { inscriptionMeta } from './inscription.meta.js';
9
+
10
+ /** Story: a Gtk.Inscription inside a fixed frame, so its counts are the only thing that moves. */
11
+ export class InscriptionStory extends StoryWidget {
12
+ private _inscription: Gtk.Inscription | null = null;
13
+ private _frame: Gtk.Frame | null = null;
14
+
15
+ static {
16
+ GObject.registerClass({ GTypeName: 'AdwStorybookInscription' }, InscriptionStory);
17
+ }
18
+
19
+ constructor() {
20
+ super(StoryWidget.fromMeta(InscriptionStory.getMetadata(), 'Default'));
21
+ }
22
+
23
+ static getMetadata(): StoryMeta {
24
+ return { ...inscriptionMeta, component: Gtk.Inscription.$gtype };
25
+ }
26
+
27
+ initialize(): void {
28
+ // The widget's CSS name is `label` (gtkinscription.c:780), so a Gtk.Frame around it
29
+ // gives the fixed box the counts are supposed to show off — without a frame the
30
+ // inscription shrinks to its minimum every time and the nat counts do nothing.
31
+ this._inscription = new Gtk.Inscription();
32
+ this._frame = new Gtk.Frame({ child: this._inscription, halign: Gtk.Align.CENTER });
33
+ this._apply();
34
+ this.addContent(this._frame);
35
+ }
36
+
37
+ updateArgs(_args: StoryArgs): void {
38
+ this._apply();
39
+ }
40
+
41
+ private _apply(): void {
42
+ if (!this._inscription || !this._frame) return;
43
+ // The ORDER is the measure: `nat_chars` only ever WIDENS a widget, and the natural is
44
+ // `MAX (min_chars, nat_chars)` (gtkinscription.c:348) — so a `min_chars` written
45
+ // after a large `nat_chars` still leaves the natural at the larger of the two. Both
46
+ // counts go before the text for the same reason the level bar's endpoints go before
47
+ // its value.
48
+ this._inscription.min_chars = this.args.minChars as number;
49
+ this._inscription.nat_chars = this.args.natChars as number;
50
+ this._inscription.min_lines = this.args.minLines as number;
51
+ this._inscription.nat_lines = this.args.natLines as number;
52
+ this._inscription.text = this.args.text as string;
53
+ this._inscription.wrap_mode = this.args.wrapMode as Pango.WrapMode;
54
+ this._inscription.text_overflow = this.args.textOverflow as Gtk.InscriptionOverflow;
55
+ this._inscription.xalign = this.args.xalign as number;
56
+ this._inscription.yalign = this.args.yalign as number;
57
+ this._frame.width_request = 320;
58
+ this._frame.height_request = 160;
59
+ }
60
+ }
61
+
62
+ GObject.type_ensure(InscriptionStory.$gtype);
63
+
64
+ export const InscriptionStories: StoryModule = { stories: [InscriptionStory] };
@@ -0,0 +1,30 @@
1
+ // Shared, renderer-agnostic metadata for the Media Controls story. Imported by the GTK
2
+ // renderer (media-controls.story.ts) and the browser renderer
3
+ // (browser/media/media-controls.web.ts), so both expose identical controls.
4
+ //
5
+ // The NAME is `media-controls` and not `controls`: the storybook keys every meta on its
6
+ // file name, and `bareName('Gtk.MediaControls')` in
7
+ // `scripts/check-website-adwaita-gallery.mjs` derives the same spelling — so the block on
8
+ // /gjsify/gtk/media/ is found from this file without a TITLED_AFTER entry.
9
+
10
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
11
+
12
+ // ONE control, and the omission is the decision. `sensitive` is the whole of the widget's
13
+ // API beyond its one object property — `gtk_media_controls_set_sensitive` — and it is what
14
+ // both renderings bind.
15
+ //
16
+ // `volume` used to sit here beside it and does not, because it would have moved on the
17
+ // browser and done NOTHING on GTK: `volume_adjustment` is private to the template
18
+ // (`ui/gtkmediacontrols.ui`) and `Gtk.MediaControls` exposes no volume setter at all. One
19
+ // meta drives three panels, so a control one of them cannot honour is precisely the shape
20
+ // `check-storybook-control-parity.mjs` exists to refuse. The browser element's `volume`
21
+ // property is real and its own, and the doc says so.
22
+ export const mediaControlsMeta: StoryMeta = {
23
+ title: 'Media/Media Controls',
24
+ description:
25
+ 'Gtk.MediaControls — the transport bar: play, position, duration, volume. It owns no playback at all ' +
26
+ '(its one property is an object, `media-stream`), and the bar is INSENSITIVE until a stream is ' +
27
+ 'attached. Note which label shows what: the position label shows the elapsed time and the one beside ' +
28
+ 'it shows what REMAINS, negatively.',
29
+ controls: [{ name: 'sensitive', label: 'Sensitive', type: ControlType.BOOLEAN, defaultValue: true }],
30
+ };
@@ -0,0 +1,58 @@
1
+ // Gtk.MediaControls — the transport bar, shown with and without a stream.
2
+ // original implementation.
3
+
4
+ import Gtk from 'gi://Gtk?version=4.0';
5
+ import GObject from 'gi://GObject?version=2.0';
6
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
7
+ import { mediaControlsMeta } from './media-controls.meta.js';
8
+
9
+ /** Story: a Gtk.MediaControls inside a `.osd .bottom` frame, as ui/gtkvideo.ui dresses it. */
10
+ export class MediaControlsStory extends StoryWidget {
11
+ private _controls: Gtk.MediaControls | null = null;
12
+
13
+ static {
14
+ GObject.registerClass({ GTypeName: 'AdwStorybookMediaControls' }, MediaControlsStory);
15
+ }
16
+
17
+ constructor() {
18
+ super(StoryWidget.fromMeta(MediaControlsStory.getMetadata(), 'Default'));
19
+ }
20
+
21
+ static getMetadata(): StoryMeta {
22
+ return { ...mediaControlsMeta, component: Gtk.MediaControls.$gtype };
23
+ }
24
+
25
+ initialize(): void {
26
+ this._controls = new Gtk.MediaControls();
27
+ // The `.osd` and `.bottom` classes are what `ui/gtkvideo.ui` puts on the controls
28
+ // revealer's child, and libadwaita has rules for exactly these (the `%osd` surface
29
+ // and the 12px standalone-OSD-toolbar padding). The story wears them so the bar is
30
+ // drawn as the video draws it rather than as a bare row of controls.
31
+ this._controls.add_css_class('osd');
32
+ this._controls.add_css_class('bottom');
33
+ this._apply();
34
+ this.addContent(this._controls);
35
+ }
36
+
37
+ updateArgs(_args: StoryArgs): void {
38
+ this._apply();
39
+ }
40
+
41
+ private _apply(): void {
42
+ if (!this._controls) return;
43
+ // `sensitive` is the bar's WHOLE state, and the template ships it at 0
44
+ // (ui/gtkmediacontrols.ui) — `gtk_media_controls_new()` gives a bar you cannot press.
45
+ // The control flips it so a reader can see both halves of the widget's life.
46
+ this._controls.sensitive = this.args.sensitive as boolean;
47
+ // There is no `volume` line here and there cannot be: `Gtk.MediaControls` exposes no
48
+ // volume setter, because `volume_adjustment` is private to the template
49
+ // (`ui/gtkmediacontrols.ui`) and the button reads it directly. That is why the shared
50
+ // meta declares no `volume` control either — one meta drives three panels, and a
51
+ // control the browser alone could honour is what
52
+ // `check-storybook-control-parity.mjs` refuses.
53
+ }
54
+ }
55
+
56
+ GObject.type_ensure(MediaControlsStory.$gtype);
57
+
58
+ export const MediaControlsStories: StoryModule = { stories: [MediaControlsStory] };
@@ -0,0 +1,42 @@
1
+ // Shared, renderer-agnostic metadata for the Picture story. Imported by the GTK
2
+ // renderer (picture.story.ts) and the browser renderer (browser/media/picture.web.ts),
3
+ // so both expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const pictureMeta: StoryMeta = {
8
+ title: 'Media/Picture',
9
+ description:
10
+ 'Gtk.Picture — an image fitted to the box it is given, not sized by itself. `content-fit` picks one ' +
11
+ 'of the four fit modes (contain, cover, fill, scale-down), `can-shrink` decides whether it may be ' +
12
+ 'smaller than its content, and `alternative-text` is what a screen reader hears.',
13
+ controls: [
14
+ {
15
+ name: 'contentFit',
16
+ label: 'Content fit',
17
+ type: ControlType.SELECT,
18
+ options: [
19
+ { label: 'Contain', value: 'contain' },
20
+ { label: 'Cover', value: 'cover' },
21
+ { label: 'Fill', value: 'fill' },
22
+ { label: 'Scale down', value: 'scale-down' },
23
+ ],
24
+ defaultValue: 'contain',
25
+ },
26
+ { name: 'canShrink', label: 'Can shrink', type: ControlType.BOOLEAN, defaultValue: true },
27
+ {
28
+ name: 'alternativeText',
29
+ label: 'Alternative text',
30
+ type: ControlType.TEXT,
31
+ defaultValue: 'A tangerine',
32
+ },
33
+ { name: 'isolateContents', label: 'Isolate contents', type: ControlType.BOOLEAN, defaultValue: true },
34
+ {
35
+ name: 'keepAspectRatio',
36
+ label: 'Keep aspect ratio (deprecated)',
37
+ type: ControlType.BOOLEAN,
38
+ defaultValue: true,
39
+ },
40
+ { name: 'width', label: 'Width (px)', type: ControlType.RANGE, min: 64, max: 320, step: 16, defaultValue: 240 },
41
+ ],
42
+ };
@@ -0,0 +1,81 @@
1
+ // Gtk.Picture — an image fitted to the box, with the fit mode as the control.
2
+ // original implementation.
3
+
4
+ import Gtk from 'gi://Gtk?version=4.0';
5
+ import Gdk from 'gi://Gdk?version=4.0';
6
+ import GLib from 'gi://GLib?version=2.0';
7
+ import GObject from 'gi://GObject?version=2.0';
8
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
9
+ import { pictureMeta } from './picture.meta.js';
10
+
11
+ /** The story's paintable: a `Gdk.MemoryTexture` of two bands, so `contain` and `cover` differ. */
12
+ function makePaintable(): Gdk.Paintable {
13
+ const width = 320;
14
+ const height = 180;
15
+ const stride = width * 4;
16
+ const bytes = new Uint8Array(stride * height);
17
+ for (let y = 0; y < height; y++) {
18
+ // A horizontal split, so an axis-preserving fit and an axis-breaking one are
19
+ // distinguishable at a glance — which is the whole point of a `content-fit` demo.
20
+ const band = y < height / 2 ? 0x30 : 0x90;
21
+ for (let x = 0; x < width; x++) {
22
+ const offset = y * stride + x * 4;
23
+ bytes[offset] = band;
24
+ bytes[offset + 1] = x < width / 2 ? 0x40 : 0xc0;
25
+ bytes[offset + 2] = 0xa0;
26
+ bytes[offset + 3] = 0xff;
27
+ }
28
+ }
29
+ return Gdk.MemoryTexture.new(width, height, Gdk.MemoryFormat.R8G8B8A8, GLib.Bytes.new(bytes), stride);
30
+ }
31
+
32
+ /** Story: a Gtk.Picture in a deliberately non-square box, so every fit mode is visible. */
33
+ export class PictureStory extends StoryWidget {
34
+ private _picture: Gtk.Picture | null = null;
35
+
36
+ static {
37
+ GObject.registerClass({ GTypeName: 'AdwStorybookPicture' }, PictureStory);
38
+ }
39
+
40
+ constructor() {
41
+ super(StoryWidget.fromMeta(PictureStory.getMetadata(), 'Default'));
42
+ }
43
+
44
+ static getMetadata(): StoryMeta {
45
+ return { ...pictureMeta, component: Gtk.Picture.$gtype };
46
+ }
47
+
48
+ initialize(): void {
49
+ this._picture = new Gtk.Picture({
50
+ paintable: makePaintable(),
51
+ halign: Gtk.Align.CENTER,
52
+ valign: Gtk.Align.CENTER,
53
+ });
54
+ this._apply();
55
+ this.addContent(this._picture);
56
+ }
57
+
58
+ updateArgs(_args: StoryArgs): void {
59
+ this._apply();
60
+ }
61
+
62
+ private _apply(): void {
63
+ if (!this._picture) return;
64
+ const width = this.args.width as number;
65
+ // A 16:9 box round a 16:9 paintable, so `contain` fills it and `cover` does too —
66
+ // which would hide the difference. The box is 3:2 so `cover` crops top and bottom.
67
+ this._picture.set_size_request(width, Math.round((width * 2) / 3));
68
+ // The ORDER is the C's: `keep_aspect_ratio` is a MAPPING onto `content_fit`
69
+ // (gtkpicture.c:1017-1021), so writing it after `content_fit` would overwrite the
70
+ // control the reader just moved. It goes FIRST, and only when it is on.
71
+ if (this.args.keepAspectRatio as boolean) this._picture.keep_aspect_ratio = true;
72
+ this._picture.content_fit = this.args.contentFit as Gtk.ContentFit;
73
+ this._picture.can_shrink = this.args.canShrink as boolean;
74
+ this._picture.alternative_text = this.args.alternativeText as string;
75
+ this._picture.isolate_contents = this.args.isolateContents as boolean;
76
+ }
77
+ }
78
+
79
+ GObject.type_ensure(PictureStory.$gtype);
80
+
81
+ export const PictureStories: StoryModule = { stories: [PictureStory] };
@@ -0,0 +1,32 @@
1
+ // Shared, renderer-agnostic metadata for the Video story. Imported by the GTK
2
+ // renderer (video.story.ts) and the browser renderer (browser/media/video.web.ts),
3
+ // so both expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const videoMeta: StoryMeta = {
8
+ title: 'Media/Video',
9
+ description:
10
+ 'Gtk.Video — a play surface with an overlay icon and a controls bar that hides itself three seconds ' +
11
+ 'after you stop moving the pointer. The overlay icon is a four-way choice — no stream, error, ended, ' +
12
+ 'or ready — and it is only VISIBLE while the video is stopped; there is no pause glyph over the frames.',
13
+ controls: [
14
+ { name: 'autoplay', label: 'Autoplay', type: ControlType.BOOLEAN, defaultValue: false },
15
+ { name: 'loop', label: 'Loop', type: ControlType.BOOLEAN, defaultValue: true },
16
+ {
17
+ name: 'graphicsOffload',
18
+ label: 'Graphics offload',
19
+ type: ControlType.BOOLEAN,
20
+ defaultValue: false,
21
+ },
22
+ {
23
+ name: 'width',
24
+ label: 'Width (px)',
25
+ type: ControlType.RANGE,
26
+ min: 160,
27
+ max: 480,
28
+ step: 40,
29
+ defaultValue: 320,
30
+ },
31
+ ],
32
+ };