@gjsify/storybook 0.10.0 → 0.12.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.
- package/README.md +11 -0
- package/lib/esm/application.js +1 -1
- package/lib/esm/devtools-extension.js +1 -0
- package/lib/esm/discover.js +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/registry.js +1 -1
- package/lib/esm/story-widget.js +1 -1
- package/lib/esm/styles.js +18 -0
- package/lib/esm/window.js +1 -1
- package/lib/types/application.d.ts +2 -1
- package/lib/types/devtools-extension.d.ts +11 -0
- package/lib/types/discover.d.ts +4 -4
- package/lib/types/index.d.ts +1 -0
- package/lib/types/registry.d.ts +8 -19
- package/lib/types/story-widget.d.ts +8 -11
- package/lib/types/story-widget.gjs.spec.d.ts +2 -0
- package/lib/types/styles.d.ts +1 -1
- package/lib/types/window.d.ts +38 -21
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -82,6 +82,17 @@ await runStorybook({
|
|
|
82
82
|
});
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
## Debug it over MCP
|
|
86
|
+
|
|
87
|
+
Run the storybook with `GJSIFY_DEVTOOLS=1` and it exposes the [`@gjsify/devtools`](../devtools) control plane, so an AI agent can drive it:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
GJSIFY_DEVTOOLS=1 gjsify storybook # exposes org.gjsify.Devtools
|
|
91
|
+
gjsify debug --profile storybook # MCP bridge: list_stories / get_current_story / open_story / set_story_arg (+ generic screenshot)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
See the [Debugging & remote control guide](https://gjsify.github.io/gjsify/guides/devtools/).
|
|
95
|
+
|
|
85
96
|
## Exports
|
|
86
97
|
|
|
87
98
|
- `StoryWidget` — Adw.Bin base class; `fromMeta()`, `addContent()`, `initialize()`/`updateArgs()`/`teardown()` hooks
|
package/lib/esm/application.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{storybookDevtoolsExtension as e}from"./devtools-extension.js";import{STORYBOOK_CSS as t}from"./styles.js";import{StorybookWindow as n}from"./window.js";import r from"@girs/adw-1";import i from"@girs/gdk-4.0";import a from"@girs/gio-2.0";import o from"@girs/gobject-2.0";import s from"@girs/gtk-4.0";import{installDevtools as c}from"@gjsify/devtools";var l=class StorybookApplication extends r.Application{static{o.registerClass({GTypeName:`StorybookApplication`},StorybookApplication)}constructor(e){super({application_id:e.applicationId,flags:a.ApplicationFlags.DEFAULT_FLAGS}),this._window=null,this._options=e,this.connect(`startup`,()=>this._initStyles()),this.connect(`activate`,()=>this._onActivate())}_initStyles(){let e=new s.CssProvider;e.load_from_string(`${t}\n${this._options.css??``}`);let n=i.Display.get_default();if(!n){console.error(`No display found`);return}s.StyleContext.add_provider_for_display(n,e,s.STYLE_PROVIDER_PRIORITY_APPLICATION)}_onActivate(){if(!this._window){this._window=new n({application:this}),this._options.title&&this._window.set_title(this._options.title);try{this._window.populateSidebar(this._options.stories)}catch(e){console.error(`Failed to create story instances:`,e)}c(this,{enabled:this._options.devtools||void 0,extend:[e(this._window)]})}this._window.present()}};o.type_ensure(l.$gtype);export{l as StorybookApplication};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{buildStorybookDevtoolsExtension as e}from"@gjsify/storybook-core";const t={ListStories:`<method name="ListStories"><arg type="s" direction="out" name="stories_json"/></method>`,GetCurrentStory:`<method name="GetCurrentStory"><arg type="s" direction="out" name="story_json"/></method>`,OpenStory:`<method name="OpenStory"><arg type="s" direction="in" name="title"/><arg type="b" direction="out" name="opened"/></method>`,SetStoryArg:`<method name="SetStoryArg"><arg type="s" direction="in" name="name"/><arg type="s" direction="in" name="value_json"/><arg type="b" direction="out" name="applied"/></method>`,GetStoryArgs:`<method name="GetStoryArgs"><arg type="s" direction="out" name="args_json"/></method>`};function storybookDevtoolsExtension(n){let r=e(n.controller),i=[],a={},o={};for(let e of r.methods){let n=t[e.name];n&&i.push(n),a[e.name]=e.handler,o[e.name]=e.kind}return{methodsXml:i,handlers:a,methodKinds:o,contributeStatus:r.contributeStatus}}export{storybookDevtoolsExtension};
|
package/lib/esm/discover.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{collectStoryModules as e}from"@gjsify/storybook-core";function collectStoryModules(t){return e(t)}export{collectStoryModules};
|
package/lib/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{storybookDevtoolsExtension as e}from"./devtools-extension.js";import{StorybookWindow as t}from"./window.js";import{StorybookApplication as n}from"./application.js";import{installActionGroup as r,withActionGroup as i}from"./decorators.js";import{collectStoryModules as a}from"./discover.js";import{StoryWidget as o}from"./story-widget.js";import{StoryRegistryService as s}from"./registry.js";import{runStorybook as c}from"./run.js";import{ControlType as l,argsFromControls as u,isStoryModule as d}from"@gjsify/stories";export{l as ControlType,s as StoryRegistryService,o as StoryWidget,n as StorybookApplication,t as StorybookWindow,u as argsFromControls,a as collectStoryModules,r as installActionGroup,d as isStoryModule,c as runStorybook,e as storybookDevtoolsExtension,i as withActionGroup};
|
package/lib/esm/registry.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{StoryRegistry as e,StoryRegistry as t}from"@gjsify/storybook-core";var StoryRegistryService=class extends t{};export{e as StoryRegistry,StoryRegistryService};
|
package/lib/esm/story-widget.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"@girs/adw-1";import t from"@girs/gobject-2.0";import n from"@girs/gtk-4.0";import{
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"@girs/adw-1";import t from"@girs/gobject-2.0";import n from"@girs/gtk-4.0";import{StoryViewBase as r}from"@gjsify/storybook-core";import{argsFromControls as i}from"@gjsify/stories";function buildGtkChrome(t){let r=new e.PreferencesPage,i=new e.PreferencesGroup,a=new n.Box({orientation:n.Orientation.VERTICAL,halign:n.Align.CENTER,valign:n.Align.CENTER,margin_top:12,margin_bottom:12,spacing:12,hexpand:!0});return a.add_css_class(`story-stage`),i.add(a),r.add(i),t.set_child(r),{root:t,hasStage:!0,setStageContent(e){let t=a.get_first_child();for(;t;)t.unparent(),t=a.get_first_child();a.append(e)},setChromeText(e,t){i.set_title(e),i.set_description(t)}}}var StoryCore=class extends r{constructor(e,t,n){super(),this._widget=e,this.initBase(t,n)}createChrome(e){return buildGtkChrome(this._widget)}initialize(){this._widget.initialize()}updateArgs(e){this._widget.updateArgs(e)}teardown(){this._widget.teardown()}emitArgs(e){super.emitArgs(e),this._widget.notify(`args`)}},a=class StoryWidget extends e.Bin{static{t.registerClass({GTypeName:`StoryWidget`,Properties:{meta:t.ParamSpec.object(`meta`,`Meta`,`Story metadata`,t.ParamFlags.READWRITE,t.Object),story:t.ParamSpec.string(`story`,`Story Name`,`Story name`,t.ParamFlags.READWRITE,``),args:t.ParamSpec.object(`args`,`Args`,`Story arguments`,t.ParamFlags.READWRITE,t.Object)}},StoryWidget)}constructor(e,t={}){super(t),this._core=new StoryCore(this,e.meta,e.story)}static fromMeta(e,t){return{meta:e,story:t,args:i(e.controls)}}get meta(){return this._core.meta}get story(){return this._core.story}get args(){return this._core.args}set args(e){this._core.args=e}onArgsChanged(e){return this._core.onArgsChanged(e)}setArg(e,t){this._core.setArg(e,t)}initialize(){}updateArgs(e){}teardown(){}addContent(e){this._core.addContent(e)}};t.type_ensure(a.$gtype);export{a as StoryWidget};
|
package/lib/esm/styles.js
CHANGED
|
@@ -7,4 +7,22 @@ const e=`
|
|
|
7
7
|
.story-range-row > box {
|
|
8
8
|
border-radius: 12px;
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
/* Controls panel shares the window (story) background; only the left
|
|
12
|
+
navigation sidebar keeps a distinct shade. The overlay-split-view sidebar is
|
|
13
|
+
otherwise drawn on the sidebar shade — flatten it onto the window colour. */
|
|
14
|
+
.storybook-controls > .sidebar,
|
|
15
|
+
.storybook-controls > .sidebar > * {
|
|
16
|
+
background-color: @window_bg_color;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Subtle dashed frame around the live preview so the widget's bounds stay
|
|
20
|
+
locatable even when it is transparent or in an empty state (e.g. a collapsed
|
|
21
|
+
bottom sheet, a status page, a bare button). @window_fg_color flips with the
|
|
22
|
+
theme (alpha(currentColor, …) does not resolve in a Gtk.CssProvider). */
|
|
23
|
+
.story-stage {
|
|
24
|
+
border: 1px dashed alpha(@window_fg_color, 0.28);
|
|
25
|
+
border-radius: 12px;
|
|
26
|
+
padding: 18px;
|
|
27
|
+
}
|
|
10
28
|
`;export{e as STORYBOOK_CSS};
|
package/lib/esm/window.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"@girs/adw-1";import t from"@girs/gdk-4.0";import n from"@girs/gobject-2.0";import r from"@girs/gtk-4.0";import{
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"@girs/adw-1";import t from"@girs/gdk-4.0";import n from"@girs/gobject-2.0";import r from"@girs/gtk-4.0";import{StorybookController as i,bindControl as a}from"@gjsify/storybook-core";function adwControlWidgetFactory(){return{text(t,n){let r=new e.EntryRow({title:t});n&&r.set_tooltip_text(n);let i=null;return r.connect(`changed`,()=>i?.(r.get_text())),{node:r,get:()=>r.get_text(),set:e=>r.set_text(e),onChange:e=>{i=e}}},boolean(t,n){let r=new e.SwitchRow({title:t,subtitle:n??``}),i=null;return r.connect(`notify::active`,()=>i?.(r.get_active())),{node:r,get:()=>r.get_active(),set:e=>r.set_active(e),onChange:e=>{i=e}}},number(t){let n=e.SpinRow.new_with_range(t.min??0,t.max??100,t.step??1);n.set_title(t.label||t.name),t.description&&n.set_subtitle(t.description);let r=null;return n.connect(`changed`,()=>r?.(n.get_value())),{node:n,get:()=>n.get_value(),set:e=>n.set_value(e),onChange:e=>{r=e}}},range(e){return buildRangeWidget(e)},select(e){return buildSelectWidget(e)},color(e,t){return buildColorWidget(e,t)}}}function buildRangeWidget(e){let t=e.min??0,n=e.max??100,i=e.step??1,a=typeof e.min==`number`?e.min:0,o=Number.isInteger(i)&&Number.isInteger(a),s=new r.Adjustment({lower:t,upper:n,step_increment:i,value:a});s.step_increment=i;let c=new r.ListBoxRow({selectable:!1,activatable:!1});c.add_css_class(`story-range-row`);let l=new r.Box({orientation:r.Orientation.VERTICAL,spacing:6,margin_top:12,margin_bottom:12,margin_start:12,margin_end:12}),u=new r.Box({orientation:r.Orientation.HORIZONTAL,spacing:12}),d=new r.Label({label:e.label||e.name,halign:r.Align.START,hexpand:!0,ellipsize:3});d.add_css_class(`heading`);let formatValue=e=>o?String(Math.round(e)):e.toFixed(2),f=new r.Label({label:formatValue(a),halign:r.Align.END});if(f.add_css_class(`numeric`),f.add_css_class(`dim-label`),u.append(d),u.append(f),l.append(u),e.description){let t=new r.Label({label:e.description,halign:r.Align.START,xalign:0,wrap:!0,max_width_chars:32});t.add_css_class(`caption`),t.add_css_class(`dim-label`),l.append(t)}let p=new r.Scale({orientation:r.Orientation.HORIZONTAL,adjustment:s,draw_value:!1,hexpand:!0}),m=null,h=!1;return p.connect(`value-changed`,()=>{if(h)return;let e=p.get_value();if(o){let t=Math.round(e);if(t!==e){p.set_value(t);return}e=t}f.set_label(formatValue(e)),m?.(e)}),l.append(p),c.set_child(l),{node:c,get:()=>p.get_value(),set:e=>{h=!0,p.set_value(e),h=!1,f.set_label(formatValue(e))},onChange:e=>{m=e}}}function buildSelectWidget(t){let n=t.options??[],i=r.StringList.new(n.map(e=>e.label)),a=new e.ComboRow({title:t.label||t.name,subtitle:t.description??``,model:i}),o=null;return a.connect(`notify::selected`,()=>o?.(a.get_selected())),{node:a,get:()=>a.get_selected(),set:e=>a.set_selected(e),onChange:e=>{o=e}}}function buildColorWidget(n,i){let a=new e.ActionRow({title:n,subtitle:i??``}),o=new r.ColorDialogButton({dialog:new r.ColorDialog({title:n}),valign:r.Align.CENTER});a.add_suffix(o),a.set_activatable_widget(o);let channel=e=>Math.round(Math.max(0,Math.min(1,e))*255).toString(16).padStart(2,`0`),rgbaToHex=e=>`#${channel(e.red)}${channel(e.green)}${channel(e.blue)}`,s=null,c=!1;return o.connect(`notify::rgba`,()=>{c||s?.(rgbaToHex(o.get_rgba()))}),{node:a,get:()=>rgbaToHex(o.get_rgba()),set:e=>{let n=new t.RGBA;n.parse(e)&&(c=!0,o.set_rgba(n),c=!1)},onChange:e=>{s=e}}}var o=class StorybookWindow extends e.ApplicationWindow{static{n.registerClass({GTypeName:`StorybookWindow`},StorybookWindow)}constructor(e){super(e),this._controlRows=[],this._rowByTitle=new Map,this._onSelect=null,this._suppressSelect=!1,this.set_default_size(1200,800),this.set_size_request(360,320),this.set_title(`Storybook`),this._buildUI(),this._controller=new i(this,e=>this._buildControls(e)),this._sidebar_list.connect(`row-selected`,this._onRowSelected.bind(this)),this._show_controls_button.connect(`toggled`,this._onToggleControls.bind(this)),this._controls_split_view.set_show_sidebar(!0)}_onRowSelected(e,t){if(this._suppressSelect||!t)return;let n=t;n.storyWidget&&this._onSelect?.(n.storyWidget)}get controller(){return this._controller}_buildControls(e){let t=e.meta.controls;if(!Array.isArray(t))return[];let n=adwControlWidgetFactory(),r=[];for(let i of t){if(!i?.name||!i?.type){console.warn(`Invalid control configuration:`,i);continue}let t=a(e,i,n);t&&r.push(t)}return r}_buildUI(){this._sidebar_list=new r.ListBox({selection_mode:r.SelectionMode.SINGLE}),this._sidebar_list.add_css_class(`navigation-sidebar`);let t=new r.ScrolledWindow({hexpand:!0,vexpand:!0,child:this._sidebar_list}),n=new e.HeaderBar({title_widget:new e.WindowTitle({title:`Stories`}),show_end_title_buttons:!1}),i=new e.ToolbarView({content:t,top_bar_style:e.ToolbarStyle.FLAT});i.add_top_bar(n);let a=new e.NavigationPage({title:`Stories`,tag:`stories`,child:i});this._content_area=new e.Bin({hexpand:!0,vexpand:!0});let o=new r.ScrolledWindow({hexpand:!0,vexpand:!0,child:this._content_area});this._control_panel=new e.PreferencesGroup({title:`Controls`});let s=new e.PreferencesPage;s.add(this._control_panel);let c=new r.ScrolledWindow({vexpand:!0,child:s});this._controls_split_view=new e.OverlaySplitView({show_sidebar:!0,sidebar_position:r.PackType.END,min_sidebar_width:280,max_sidebar_width:360,content:o,sidebar:c,css_classes:[`storybook-controls`]}),this._preview_title=new e.WindowTitle({title:`Preview`}),this._show_controls_button=new r.ToggleButton({icon_name:`sidebar-show-right-symbolic`,tooltip_text:`Toggle Controls`,active:!0});let l=new e.HeaderBar({title_widget:this._preview_title});l.pack_end(this._show_controls_button);let u=new e.ToolbarView({content:this._controls_split_view,top_bar_style:e.ToolbarStyle.FLAT});u.add_top_bar(l);let d=new e.NavigationPage({title:`Preview`,tag:`preview`,child:u});this._main_split_view=new e.NavigationSplitView({min_sidebar_width:220,max_sidebar_width:320,sidebar:a,content:d}),this.set_content(this._main_split_view);let f=e.BreakpointCondition.parse(`max-width: 720sp`);if(f){let t=new e.Breakpoint({condition:f});t.connect(`apply`,()=>{this._main_split_view.collapsed=!0,this._controls_split_view.collapsed=!0}),t.connect(`unapply`,()=>{this._main_split_view.collapsed=!1,this._controls_split_view.collapsed=!1}),this.add_breakpoint(t)}}_onToggleControls(e){this._controls_split_view.set_show_sidebar(e.get_active())}populateSidebar(e){this._controller.mount(e,!0)}renderSidebar(e,t){this._onSelect=t,this._suppressSelect=!0,this._clearSidebar(),this._rowByTitle.clear();for(let t of e){this._addCategoryToSidebar(t.category);for(let{instance:e,name:n}of t.stories)this._addStoryToSidebar(e,n)}this._suppressSelect=!1}markSelected(e){let t=this._rowByTitle.get(e);t&&this._sidebar_list.get_selected_row()!==t&&(this._suppressSelect=!0,this._sidebar_list.select_row(t),this._suppressSelect=!1)}setPreviewTitle(e){this._preview_title.set_title(e)}showPreview(e){this._content_area.set_child(e),this._main_split_view.get_collapsed()&&this._main_split_view.set_show_content(!0)}renderControls(e){this._clearControlPanel();for(let t of e){let e=t.view;this._control_panel.add(e),this._controlRows.push(e)}this._show_controls_button.set_active(!0)}_clearSidebar(){let e=this._sidebar_list.get_first_child();for(;e;){let t=e.get_next_sibling();e.unparent(),e=t}}_addCategoryToSidebar(e){let t=new r.ListBoxRow({selectable:!1}),n=new r.Label({label:e,halign:r.Align.START,margin_top:10,margin_bottom:4,margin_start:12,margin_end:12});n.add_css_class(`heading`),n.add_css_class(`dim-label`),t.set_child(n),this._sidebar_list.append(t)}_addStoryToSidebar(e,t){let n=new r.ListBoxRow,i=new r.Label({label:t||`Unnamed Story`,halign:r.Align.START,margin_start:20,margin_top:6,margin_bottom:6});n.set_child(i),this._sidebar_list.append(n),n.storyWidget=e,this._rowByTitle.set(e.meta.title,n)}_clearControlPanel(){for(let e of this._controlRows)this._control_panel.remove(e);this._controlRows=[]}get activeStory(){return this._controller.activeStory}openStoryByTitle(e){return this._controller.openStoryByTitle(e)}setActiveArg(e,t){return this._controller.setActiveArg(e,t)}};n.type_ensure(o.$gtype);export{o as StorybookWindow};
|
|
@@ -10,6 +10,8 @@ export interface StorybookOptions {
|
|
|
10
10
|
stories: StoryModule[];
|
|
11
11
|
/** Consumer's own widget stylesheet, layered on top of the built-in chrome CSS. */
|
|
12
12
|
css?: string;
|
|
13
|
+
/** Force-enable the devtools control plane (otherwise gated on `GJSIFY_DEVTOOLS`). */
|
|
14
|
+
devtools?: boolean;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* Hosts the storybook: loads styles on startup, builds the window and populates
|
|
@@ -18,7 +20,6 @@ export interface StorybookOptions {
|
|
|
18
20
|
*/
|
|
19
21
|
export declare class StorybookApplication extends Adw.Application {
|
|
20
22
|
private _window;
|
|
21
|
-
private _registry;
|
|
22
23
|
private _options;
|
|
23
24
|
constructor(options: StorybookOptions);
|
|
24
25
|
private _initStyles;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DevtoolsExtension } from '@gjsify/devtools';
|
|
2
|
+
import type { StorybookWindow } from './window.js';
|
|
3
|
+
/**
|
|
4
|
+
* Build a {@link DevtoolsExtension} that exposes the storybook's story surface
|
|
5
|
+
* — list/open stories, read/set the active story's args — so an agent (via the
|
|
6
|
+
* MCP bridge) can drive and debug widgets in isolation. Wired by
|
|
7
|
+
* {@link StorybookApplication} when `GJSIFY_DEVTOOLS` is set.
|
|
8
|
+
*
|
|
9
|
+
* Delegates the method set to the window's {@link StorybookController}.
|
|
10
|
+
*/
|
|
11
|
+
export declare function storybookDevtoolsExtension(window: StorybookWindow): DevtoolsExtension;
|
package/lib/types/discover.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { StoryModule
|
|
1
|
+
import type { StoryModule } from './story-widget.js';
|
|
2
2
|
/**
|
|
3
3
|
* Flatten a list of module namespaces (the `import * as m from './x.story.js'`
|
|
4
|
-
* objects the `gjsify storybook` command generates) into the story modules
|
|
4
|
+
* objects the `gjsify storybook` command generates) into the GTK story modules
|
|
5
5
|
* they export — regardless of the export name. Any exported value shaped like a
|
|
6
|
-
*
|
|
6
|
+
* story module (an object with a `stories` array) is collected.
|
|
7
7
|
*/
|
|
8
|
-
export declare function collectStoryModules(namespaces: Array<Record<string, unknown>>):
|
|
8
|
+
export declare function collectStoryModules(namespaces: Array<Record<string, unknown>>): StoryModule[];
|
package/lib/types/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export type { StoryDecorator, StoryModule, StoryWidgetConstructor } from './stor
|
|
|
4
4
|
export { StoryRegistryService } from './registry.js';
|
|
5
5
|
export { installActionGroup, withActionGroup, type StoryAction } from './decorators.js';
|
|
6
6
|
export { StorybookWindow } from './window.js';
|
|
7
|
+
export { storybookDevtoolsExtension } from './devtools-extension.js';
|
|
7
8
|
export { StorybookApplication, type StorybookOptions } from './application.js';
|
|
8
9
|
export { runStorybook } from './run.js';
|
|
9
10
|
export { collectStoryModules } from './discover.js';
|
package/lib/types/registry.d.ts
CHANGED
|
@@ -1,22 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { StoryRegistry } from '@gjsify/storybook-core';
|
|
2
|
+
import type { StoryWidget } from './story-widget.js';
|
|
3
|
+
export { StoryRegistry } from '@gjsify/storybook-core';
|
|
2
4
|
/**
|
|
3
|
-
* Manages story-module registration and instantiation
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Manages story-module registration and instantiation for the GTK renderer.
|
|
6
|
+
* One registry per {@link runStorybook} run (no shared singleton). All behaviour
|
|
7
|
+
* — validation, defensive copies, decorator `reduceRight` composition — is the
|
|
8
|
+
* core {@link StoryRegistry}.
|
|
7
9
|
*/
|
|
8
|
-
export declare class StoryRegistryService {
|
|
9
|
-
private modules;
|
|
10
|
-
/** Register a single story module. */
|
|
11
|
-
registerStory(storyModule: StoryModule): void;
|
|
12
|
-
/** Register multiple story modules (invalid ones are filtered out). */
|
|
13
|
-
registerStories(storyModules: StoryModule[]): void;
|
|
14
|
-
/** All registered story modules (a shallow copy). */
|
|
15
|
-
getStories(): StoryModule[];
|
|
16
|
-
/**
|
|
17
|
-
* Instantiate every registered story widget and prepare it for display.
|
|
18
|
-
* Call once GTK is ready.
|
|
19
|
-
*/
|
|
20
|
-
createStoryInstances(): StoryModule[];
|
|
21
|
-
private instantiateStoriesForModule;
|
|
10
|
+
export declare class StoryRegistryService extends StoryRegistry<StoryWidget> {
|
|
22
11
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Adw from '@girs/adw-1';
|
|
2
2
|
import GObject from '@girs/gobject-2.0';
|
|
3
3
|
import Gtk from '@girs/gtk-4.0';
|
|
4
|
-
import { type StoryArgs, type StoryMeta } from '@gjsify/stories';
|
|
4
|
+
import { type StoryArgs, type StoryArgValue, type StoryMeta } from '@gjsify/stories';
|
|
5
5
|
export declare namespace StoryWidget {
|
|
6
6
|
interface ConstructorProps {
|
|
7
7
|
meta: StoryMeta;
|
|
@@ -10,7 +10,8 @@ export declare namespace StoryWidget {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Base class for GJS story widgets
|
|
13
|
+
* Base class for GJS story widgets — a thin GTK adapter over
|
|
14
|
+
* {@link StoryViewBase}.
|
|
14
15
|
*
|
|
15
16
|
* Provides default chrome — a centered `Adw.PreferencesPage` /
|
|
16
17
|
* `Adw.PreferencesGroup` with title + description above a content slot — built
|
|
@@ -19,11 +20,7 @@ export declare namespace StoryWidget {
|
|
|
19
20
|
* providing their own composite template (then {@link addContent} is a no-op).
|
|
20
21
|
*/
|
|
21
22
|
export declare class StoryWidget extends Adw.Bin {
|
|
22
|
-
private
|
|
23
|
-
private _story;
|
|
24
|
-
private _args;
|
|
25
|
-
private _storyContent;
|
|
26
|
-
private _group;
|
|
23
|
+
private _core;
|
|
27
24
|
constructor(params: StoryWidget.ConstructorProps, adwParams?: Partial<Adw.Bin.ConstructorProps>);
|
|
28
25
|
/**
|
|
29
26
|
* Build the constructor params from a story's metadata, deriving the initial
|
|
@@ -31,11 +28,13 @@ export declare class StoryWidget extends Adw.Bin {
|
|
|
31
28
|
*/
|
|
32
29
|
static fromMeta(meta: StoryMeta, story: string): StoryWidget.ConstructorProps;
|
|
33
30
|
get meta(): StoryMeta;
|
|
34
|
-
set meta(value: StoryMeta);
|
|
35
31
|
get story(): string;
|
|
36
|
-
set story(value: string);
|
|
37
32
|
get args(): StoryArgs;
|
|
38
33
|
set args(value: StoryArgs);
|
|
34
|
+
/** Subscribe to args changes; returns an unsubscribe function. */
|
|
35
|
+
onArgsChanged(listener: (args: StoryArgs) => void): () => void;
|
|
36
|
+
/** Set a single arg — drives {@link updateArgs} and notifies listeners. */
|
|
37
|
+
setArg(name: string, value: StoryArgValue): void;
|
|
39
38
|
/** Override in subclasses — build the preview. Runs in the registry init path. */
|
|
40
39
|
initialize(): void;
|
|
41
40
|
/** Override in subclasses — react to a control change. */
|
|
@@ -47,8 +46,6 @@ export declare class StoryWidget extends Adw.Bin {
|
|
|
47
46
|
* installed its own composite template.
|
|
48
47
|
*/
|
|
49
48
|
addContent(widget: Gtk.Widget): void;
|
|
50
|
-
private _installDefaultChrome;
|
|
51
|
-
private _refreshChromeText;
|
|
52
49
|
}
|
|
53
50
|
/** Wraps a story's content-build step (e.g. to install a shared action group). */
|
|
54
51
|
export type StoryDecorator = (build: () => void, widget: StoryWidget) => void;
|
package/lib/types/styles.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const STORYBOOK_CSS = "\n/* Range-control card in the controls sidebar \u2014 keeps the label + description\n from being squashed into a single column when the sidebar is narrow. */\n.story-range-row {\n padding: 0;\n}\n.story-range-row > box {\n border-radius: 12px;\n}\n";
|
|
1
|
+
export declare const STORYBOOK_CSS = "\n/* Range-control card in the controls sidebar \u2014 keeps the label + description\n from being squashed into a single column when the sidebar is narrow. */\n.story-range-row {\n padding: 0;\n}\n.story-range-row > box {\n border-radius: 12px;\n}\n\n/* Controls panel shares the window (story) background; only the left\n navigation sidebar keeps a distinct shade. The overlay-split-view sidebar is\n otherwise drawn on the sidebar shade \u2014 flatten it onto the window colour. */\n.storybook-controls > .sidebar,\n.storybook-controls > .sidebar > * {\n background-color: @window_bg_color;\n}\n\n/* Subtle dashed frame around the live preview so the widget's bounds stay\n locatable even when it is transparent or in an empty state (e.g. a collapsed\n bottom sheet, a status page, a bare button). @window_fg_color flips with the\n theme (alpha(currentColor, \u2026) does not resolve in a Gtk.CssProvider). */\n.story-stage {\n border: 1px dashed alpha(@window_fg_color, 0.28);\n border-radius: 12px;\n padding: 18px;\n}\n";
|
package/lib/types/window.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import Adw from '@girs/adw-1';
|
|
2
|
-
import type {
|
|
2
|
+
import type { StoryArgValue } from '@gjsify/stories';
|
|
3
|
+
import { type CategoryGroup, type ControlRow, StorybookController, type StorybookView } from '@gjsify/storybook-core';
|
|
4
|
+
import type { StoryModule, StoryWidget } from './story-widget.js';
|
|
3
5
|
/**
|
|
4
6
|
* Main window for the storybook. The sidebar lists story instances grouped by
|
|
5
7
|
* the `Category/Name` title prefix; the preview pane holds the active
|
|
6
8
|
* {@link StoryWidget} and an `Adw.PreferencesGroup` of controls drives its
|
|
7
|
-
* `args` with two-way binding.
|
|
9
|
+
* `args` with two-way binding. Implements {@link StorybookView} so the shared
|
|
10
|
+
* {@link StorybookController} drives it.
|
|
8
11
|
*/
|
|
9
|
-
export declare class StorybookWindow extends Adw.ApplicationWindow {
|
|
12
|
+
export declare class StorybookWindow extends Adw.ApplicationWindow implements StorybookView<StoryWidget> {
|
|
10
13
|
private _sidebar_list;
|
|
11
14
|
private _content_area;
|
|
12
15
|
private _control_panel;
|
|
@@ -15,30 +18,44 @@ export declare class StorybookWindow extends Adw.ApplicationWindow {
|
|
|
15
18
|
private _controls_split_view;
|
|
16
19
|
private _main_split_view;
|
|
17
20
|
private _controlRows;
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
private
|
|
21
|
+
private _rowByTitle;
|
|
22
|
+
private _controller;
|
|
23
|
+
private _onSelect;
|
|
24
|
+
private _suppressSelect;
|
|
21
25
|
constructor(params: Partial<Adw.ApplicationWindow.ConstructorProps>);
|
|
26
|
+
private _onRowSelected;
|
|
27
|
+
/** The controller driving this window (exposed for the devtools extension). */
|
|
28
|
+
get controller(): StorybookController<StoryWidget>;
|
|
29
|
+
private _buildControls;
|
|
22
30
|
private _buildUI;
|
|
23
31
|
private _onToggleControls;
|
|
24
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Populate the sidebar with story modules. Registers + instantiates them via
|
|
34
|
+
* the controller (which renders the sidebar through this view's
|
|
35
|
+
* {@link renderSidebar} seam) and opens the first story.
|
|
36
|
+
*/
|
|
25
37
|
populateSidebar(storyModules: StoryModule[]): void;
|
|
38
|
+
renderSidebar(groups: Array<CategoryGroup<StoryWidget>>, onSelect: (instance: StoryWidget) => void): void;
|
|
39
|
+
markSelected(title: string): void;
|
|
40
|
+
setPreviewTitle(title: string): void;
|
|
41
|
+
showPreview(instance: StoryWidget): void;
|
|
42
|
+
renderControls(rows: Array<ControlRow<unknown>>): void;
|
|
26
43
|
private _clearSidebar;
|
|
27
|
-
private _groupStoriesByCategory;
|
|
28
44
|
private _addCategoryToSidebar;
|
|
29
45
|
private _addStoryToSidebar;
|
|
30
|
-
private _onStorySelected;
|
|
31
|
-
private _showStory;
|
|
32
|
-
private _updateControlPanel;
|
|
33
46
|
private _clearControlPanel;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
/** The currently-displayed story, or null. */
|
|
48
|
+
get activeStory(): StoryWidget | null;
|
|
49
|
+
/**
|
|
50
|
+
* Select + show a story by its full `Category/Name` title; the sidebar
|
|
51
|
+
* selection updates too, so the UI stays in sync. Returns false when no
|
|
52
|
+
* story with that title exists.
|
|
53
|
+
*/
|
|
54
|
+
openStoryByTitle(title: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Set one arg on the active story — drives the same `args` path as the
|
|
57
|
+
* control panel, so the visible control rows refresh via the controller's
|
|
58
|
+
* args subscription. Returns false when no story is active.
|
|
59
|
+
*/
|
|
60
|
+
setActiveArg(name: string, value: StoryArgValue): boolean;
|
|
44
61
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/storybook",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Reusable GTK/Adwaita storybook for GJS — author *.story.ts and browse them in a generic component explorer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -41,11 +41,13 @@
|
|
|
41
41
|
"@girs/glib-2.0": "2.88.0-4.0.4",
|
|
42
42
|
"@girs/gobject-2.0": "2.88.0-4.0.4",
|
|
43
43
|
"@girs/gtk-4.0": "4.23.0-4.0.4",
|
|
44
|
-
"@gjsify/
|
|
44
|
+
"@gjsify/devtools": "^0.12.0",
|
|
45
|
+
"@gjsify/stories": "^0.12.0",
|
|
46
|
+
"@gjsify/storybook-core": "^0.12.0"
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
|
47
|
-
"@gjsify/cli": "^0.
|
|
48
|
-
"@gjsify/unit": "^0.
|
|
49
|
+
"@gjsify/cli": "^0.12.0",
|
|
50
|
+
"@gjsify/unit": "^0.12.0",
|
|
49
51
|
"@types/node": "^25.9.2",
|
|
50
52
|
"typescript": "^6.0.3"
|
|
51
53
|
},
|