@gjsify/storybook 0.37.0 → 0.38.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.
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import e from"@girs/adw-1";import t from"@girs/gdk-4.0";import n from"@girs/gtk-4.0";import{ADW_ACCENT_COLOR_NAMES as r,adwaitaAccentBgColor as i,adwaitaAccentColor as a}from"@gjsify/adwaita-core";import{STORYBOOK_COLOR_SCHEMES as o,StorybookSettings as s}from"@gjsify/storybook-core";const c={system:`Follow system`,light:`Light`,dark:`Dark`},l={blue:`Blue`,teal:`Teal`,green:`Green`,yellow:`Yellow`,orange:`Orange`,red:`Red`,pink:`Pink`,purple:`Purple`,slate:`Slate`};var StorybookAppearance=class{constructor(){this._provider=null,this._applying=!1,this._styleManager=e.StyleManager.get_default(),this.settings=new s(()=>this._styleManager.get_dark()),this.settings.subscribe(e=>this._apply(e)),this._styleManager.connect(`notify::dark`,()=>this.settings.systemChanged()),this._apply(this.settings.state)}_apply(t){if(!this._applying){this._applying=!0;try{this._styleManager.set_color_scheme(t.colorScheme===`light`?e.ColorScheme.FORCE_LIGHT:t.colorScheme===`dark`?e.ColorScheme.FORCE_DARK:e.ColorScheme.DEFAULT),this._applyAccent(this.settings.resolvedAccent)}finally{this._applying=!1}}}_applyAccent(e){let r=t.Display.get_default();if(!r)return;if(!this._provider){if(!e)return;this._provider=new n.CssProvider,n.StyleContext.add_provider_for_display(r,this._provider,n.STYLE_PROVIDER_PRIORITY_APPLICATION)}if(!e){this._provider.load_from_string(``);return}let o=i(e),s=a(e,this.settings.resolvedDark);this._provider.load_from_string(`:root { --accent-bg-color: ${o}; --accent-color: ${s}; }`)}};function buildSwatch(e,t,r){let i=new n.CheckButton({tooltip_text:t,halign:n.Align.CENTER,valign:n.Align.CENTER,focus_on_click:!1});for(let t of e)i.add_css_class(t);return i.update_property([n.AccessibleProperty.LABEL],[t]),r&&i.set_group(r),i}function buildSwatchCard(t=!1){let n=new e.WrapBox({align:.5,child_spacing:8,line_spacing:8,margin_top:12,margin_bottom:12,margin_start:12,margin_end:12}),r=new e.Bin({child:n,hexpand:!0});return r.add_css_class(`card`),t&&r.add_css_class(`storybook-card-attached`),{card:r,row:n}}function buildAppearanceDialog(t){let a=t.settings,s=new e.PreferencesPage,u=new e.PreferencesGroup({title:`Style`}),{card:d,row:f}=buildSwatchCard(),p=null,m=new Map;for(let e of o){let t=buildSwatch([`storybook-swatch`,`storybook-scheme-swatch`,`storybook-scheme-${e}`],c[e],p);p??=t,t.set_active(a.colorScheme===e),t.connect(`toggled`,()=>{t.get_active()&&(a.colorScheme=e)}),m.set(e,t),f.append(t)}u.add(d),s.add(u);let h=new e.PreferencesGroup({title:`Accent colour`});h.add_css_class(`storybook-attached-group`);let g=new e.SwitchRow({title:`Use a custom accent colour`,subtitle:`Off follows the desktop, which owns the accent`,active:a.accentMode===`custom`});h.add(g);let{card:_,row:v}=buildSwatchCard(!0),y=null,b=new Map;for(let e of r){let t=buildSwatch([`storybook-swatch`],l[e],y);y??=t,t.set_active(a.accent===e);let r=new n.CssProvider;r.load_from_string(`checkbutton { background-color: ${i(e)}; }`),t.get_style_context().add_provider(r,n.STYLE_PROVIDER_PRIORITY_APPLICATION),t.connect(`toggled`,()=>{t.get_active()&&(a.accent=e)}),b.set(e,t),v.append(t)}v.set_sensitive(a.accentMode===`custom`),g.connect(`notify::active`,()=>{a.accentMode=g.get_active()?`custom`:`system`}),h.add(_),s.add(h),a.subscribe(e=>{let t=m.get(e.colorScheme);t&&!t.get_active()&&t.set_active(!0);let n=b.get(e.accent);n&&!n.get_active()&&n.set_active(!0);let r=e.accentMode===`custom`;g.get_active()!==r&&g.set_active(r),v.set_sensitive(r)});let x=new e.PreferencesDialog({title:`Appearance`});return x.add(s),x}export{StorybookAppearance,buildAppearanceDialog};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{storybookDevtoolsExtension as e}from"./devtools-extension.js";import{installStorybookProbe as t,probeEnabled as n}from"./probe.js";import{STORYBOOK_CSS as r}from"./styles.js";import{StorybookWindow as i}from"./window.js";import a from"@girs/adw-1";import o from"@girs/gdk-4.0";import s from"@girs/gio-2.0";import c from"@girs/gobject-2.0";import l from"@girs/gtk-4.0";import{installDevtools as u}from"@gjsify/devtools";var d=class StorybookApplication extends a.Application{static{c.registerClass({GTypeName:`StorybookApplication`},StorybookApplication)}constructor(e){super({application_id:e.applicationId,flags:s.ApplicationFlags.DEFAULT_FLAGS}),this._window=null,this._options=e,this.connect(`startup`,()=>this._initStyles()),this.connect(`activate`,()=>this._onActivate())}_initStyles(){let e=new l.CssProvider;e.load_from_string(`${r}\n${this._options.css??``}`);let t=o.Display.get_default();if(!t){console.error(`No display found`);return}l.StyleContext.add_provider_for_display(t,e,l.STYLE_PROVIDER_PRIORITY_APPLICATION)}_onActivate(){if(!this._window){this._window=new i({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)}u(this,{enabled:this._options.devtools||void 0,extend:[e(this._window)]}),n()&&t(this,this._window,this._options.probe)}this._window.present()}};c.type_ensure(d.$gtype);export{d as StorybookApplication};
1
+ import"./_virtual/_rolldown/runtime.js";import{storybookDevtoolsExtension as e}from"./devtools-extension.js";import{installStorybookProbe as t,probeEnabled as n}from"./probe.js";import{STORYBOOK_CSS as r}from"./styles.js";import{StorybookWindow as i}from"./window.js";import a from"@girs/adw-1";import o from"@girs/gdk-4.0";import s from"@girs/gtk-4.0";import c from"@girs/gio-2.0";import l from"@girs/gobject-2.0";import{installDevtools as u}from"@gjsify/devtools";var d=class StorybookApplication extends a.Application{static{l.registerClass({GTypeName:`StorybookApplication`},StorybookApplication)}constructor(e){super({application_id:e.applicationId,flags:c.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(`${r}\n${this._options.css??``}`);let t=o.Display.get_default();if(!t){console.error(`No display found`);return}s.StyleContext.add_provider_for_display(t,e,s.STYLE_PROVIDER_PRIORITY_APPLICATION)}_onActivate(){if(!this._window){this._window=new i({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)}u(this,{enabled:this._options.devtools||void 0,extend:[e(this._window)]}),n()&&t(this,this._window,this._options.probe)}this._window.present()}};l.type_ensure(d.$gtype);export{d as StorybookApplication};
package/lib/esm/run.js CHANGED
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{StorybookApplication as e}from"./application.js";import t from"system";async function runStorybook(n){return new e(n).runAsync([t.programInvocationName,...t.programArgs])}export{runStorybook};
1
+ import"./_virtual/_rolldown/runtime.js";import{StorybookApplication as e}from"./application.js";import t from"system";import{runApplication as n}from"@gjsify/adwaita-app";async function runStorybook(r){return n(new e(r),[t.programInvocationName,...t.programArgs])}export{runStorybook};
@@ -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{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};
1
+ import"./_virtual/_rolldown/runtime.js";import e from"@girs/adw-1";import t from"@girs/gtk-4.0";import{StoryViewBase as n}from"@gjsify/storybook-core";import r from"@girs/gobject-2.0";import i from"@girs/glib-2.0";import{argsFromControls as a}from"@gjsify/stories";function buildGtkChrome(n){let r=new e.PreferencesPage,a=new e.PreferencesGroup,o=new t.Box({orientation:t.Orientation.VERTICAL,halign:t.Align.CENTER,valign:t.Align.CENTER,margin_top:12,margin_bottom:12,spacing:12,hexpand:!0});return o.add_css_class(`story-stage`),a.add(o),r.add(a),n.set_child(r),{root:n,hasStage:!0,setStageContent(e){let t=o.get_first_child();for(;t;)t.unparent(),t=o.get_first_child();o.append(e)},setChromeText(e,t){a.set_title(i.markup_escape_text(e,-1)),a.set_description(i.markup_escape_text(t,-1))}}}var StoryCore=class extends n{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`)}},o=class StoryWidget extends e.Bin{static{r.registerClass({GTypeName:`StoryWidget`,Properties:{meta:r.ParamSpec.object(`meta`,`Meta`,`Story metadata`,r.ParamFlags.READWRITE,r.Object),story:r.ParamSpec.string(`story`,`Story Name`,`Story name`,r.ParamFlags.READWRITE,``),args:r.ParamSpec.object(`args`,`Args`,`Story arguments`,r.ParamFlags.READWRITE,r.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:a(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)}};r.type_ensure(o.$gtype);export{o as StoryWidget};
package/lib/esm/styles.js CHANGED
@@ -1,4 +1,75 @@
1
1
  const e=`
2
+ /* Appearance dialog — round swatches with a selection ring, the shape GNOME's own
3
+ appearance switcher uses. Adapted from Learn6502's theme-mode-selector.css and
4
+ accent-color-selector.css (JumpLink/easy6502, MIT).
5
+
6
+ The inner \`radio\` indicator is switched off because the swatch IS the
7
+ indicator: a check mark drawn on top of a colour reads as two competing
8
+ signals, and the ring already says which one is selected.
9
+ \`background-clip: content-box\` is what keeps the ring outside the fill rather
10
+ than tinting it. */
11
+ .storybook-swatch {
12
+ min-width: 24px;
13
+ min-height: 24px;
14
+ padding: 6px;
15
+ border-radius: 9999px;
16
+ background-clip: content-box;
17
+ background-image: none;
18
+ box-shadow: inset 0 0 0 3px transparent;
19
+ }
20
+ .storybook-swatch:checked {
21
+ box-shadow: inset 0 0 0 3px var(--accent-bg-color);
22
+ }
23
+ .storybook-swatch radio {
24
+ -gtk-icon-source: none;
25
+ border: none;
26
+ background: none;
27
+ box-shadow: none;
28
+ min-width: 12px;
29
+ min-height: 12px;
30
+ padding: 0;
31
+ transform: none;
32
+ }
33
+ /* Desaturated rather than merely dimmed: while the accent follows the desktop the
34
+ palette has to read as unavailable, not as nine slightly faded choices. */
35
+ .storybook-swatch:disabled {
36
+ filter: saturate(0.4) brightness(1.05);
37
+ opacity: 0.7;
38
+ }
39
+ /* The scheme swatches are larger — they are the dialog's primary choice. */
40
+ .storybook-swatch.storybook-scheme-swatch {
41
+ min-width: 44px;
42
+ min-height: 44px;
43
+ }
44
+ /* "Follow system" is drawn as the two schemes meeting on a diagonal, so the option
45
+ looks like what it does instead of needing a word for it. */
46
+ .storybook-swatch.storybook-scheme-system {
47
+ background-image: linear-gradient(to bottom right, #f6f5f4 49.99%, #241f31 50.01%);
48
+ }
49
+ .storybook-swatch.storybook-scheme-light {
50
+ background-color: #f6f5f4;
51
+ }
52
+ .storybook-swatch.storybook-scheme-dark {
53
+ background-color: #241f31;
54
+ }
55
+ /* Squares the top corners so a swatch card sits flush under the row it belongs to,
56
+ instead of the two reading as separate cards with a seam between them. */
57
+ .storybook-card-attached {
58
+ border-top-left-radius: 0;
59
+ border-top-right-radius: 0;
60
+ }
61
+ /* …and the OTHER half, which squaring only the card cannot do: the row above lives
62
+ in the group's .boxed-list, whose own bottom corners are still round, so the two
63
+ met with a notch at each end. Both sides have to be squared for the join to read
64
+ as one list. The transparent bottom border keeps the boxed-list's height where it
65
+ was, so squaring it does not shift the card up by a pixel.
66
+ Adapted from Learn6502's views/preferences.dialog.css (JumpLink/easy6502, MIT). */
67
+ .storybook-attached-group .boxed-list {
68
+ border-bottom-left-radius: 0;
69
+ border-bottom-right-radius: 0;
70
+ border-bottom: 1px solid transparent;
71
+ }
72
+
2
73
  /* Range-control card in the controls sidebar — keeps the label + description
3
74
  from being squashed into a single column when the sidebar is narrow. */
4
75
  .story-range-row {
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{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};
1
+ import"./_virtual/_rolldown/runtime.js";import{StorybookAppearance as e,buildAppearanceDialog as t}from"./appearance.js";import n from"@girs/adw-1";import r from"@girs/gdk-4.0";import i from"@girs/gtk-4.0";import{StorybookController as a,bindControl as o}from"@gjsify/storybook-core";import s from"@girs/gobject-2.0";function adwControlWidgetFactory(){return{text(e,t){let r=new n.EntryRow({title:e});t&&r.set_tooltip_text(t);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(e,t){let r=new n.SwitchRow({title:e,subtitle:t??``}),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(e){let t=n.SpinRow.new_with_range(e.min??0,e.max??100,e.step??1);t.set_title(e.label||e.name),e.description&&t.set_subtitle(e.description);let r=null;return t.connect(`changed`,()=>r?.(t.get_value())),{node:t,get:()=>t.get_value(),set:e=>t.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,r=e.step??1,a=typeof e.min==`number`?e.min:0,o=Number.isInteger(r)&&Number.isInteger(a),s=new i.Adjustment({lower:t,upper:n,step_increment:r,value:a});s.step_increment=r;let c=new i.ListBoxRow({selectable:!1,activatable:!1});c.add_css_class(`story-range-row`);let l=new i.Box({orientation:i.Orientation.VERTICAL,spacing:6,margin_top:12,margin_bottom:12,margin_start:12,margin_end:12}),u=new i.Box({orientation:i.Orientation.HORIZONTAL,spacing:12}),d=new i.Label({label:e.label||e.name,halign:i.Align.START,hexpand:!0,ellipsize:3});d.add_css_class(`heading`);let formatValue=e=>o?String(Math.round(e)):e.toFixed(2),f=new i.Label({label:formatValue(a),halign:i.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 i.Label({label:e.description,halign:i.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 i.Scale({orientation:i.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(e){let t=e.options??[],r=i.StringList.new(t.map(e=>e.label)),a=new n.ComboRow({title:e.label||e.name,subtitle:e.description??``,model:r}),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(e,t){let a=new n.ActionRow({title:e,subtitle:t??``}),o=new i.ColorDialogButton({dialog:new i.ColorDialog({title:e}),valign:i.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 t=new r.RGBA;t.parse(e)&&(c=!0,o.set_rgba(t),c=!1)},onChange:e=>{s=e}}}var c=class StorybookWindow extends n.ApplicationWindow{static{s.registerClass({GTypeName:`StorybookWindow`},StorybookWindow)}constructor(t){super(t),this._appearance=new 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 a(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=o(e,i,n);t&&r.push(t)}return r}_buildUI(){this._sidebar_list=new i.ListBox({selection_mode:i.SelectionMode.SINGLE}),this._sidebar_list.add_css_class(`navigation-sidebar`);let e=new i.ScrolledWindow({hexpand:!0,vexpand:!0,child:this._sidebar_list}),r=new n.HeaderBar({title_widget:new n.WindowTitle({title:`Stories`}),show_end_title_buttons:!1}),a=new n.ToolbarView({content:e,top_bar_style:n.ToolbarStyle.FLAT});a.add_top_bar(r);let o=new n.NavigationPage({title:`Stories`,tag:`stories`,child:a});this._content_area=new n.Bin({hexpand:!0,vexpand:!0});let s=new i.ScrolledWindow({hexpand:!0,vexpand:!0,child:this._content_area});this._control_panel=new n.PreferencesGroup({title:`Controls`});let c=new n.PreferencesPage;c.add(this._control_panel);let l=new i.ScrolledWindow({vexpand:!0,child:c});this._controls_split_view=new n.OverlaySplitView({show_sidebar:!0,sidebar_position:i.PackType.END,min_sidebar_width:280,max_sidebar_width:360,content:s,sidebar:l,css_classes:[`storybook-controls`]}),this._preview_title=new n.WindowTitle({title:`Preview`}),this._show_controls_button=new i.ToggleButton({icon_name:`sidebar-show-right-symbolic`,tooltip_text:`Toggle Controls`,active:!0});let u=new n.HeaderBar({title_widget:this._preview_title});u.pack_end(this._show_controls_button);let d=new i.Button({icon_name:`applications-graphics-symbolic`,tooltip_text:`Appearance`});d.connect(`clicked`,()=>t(this._appearance).present(this)),u.pack_end(d);let f=new n.ToolbarView({content:this._controls_split_view,top_bar_style:n.ToolbarStyle.FLAT});f.add_top_bar(u);let p=new n.NavigationPage({title:`Preview`,tag:`preview`,child:f});this._main_split_view=new n.NavigationSplitView({min_sidebar_width:220,max_sidebar_width:320,sidebar:o,content:p}),this.set_content(this._main_split_view);let m=n.BreakpointCondition.parse(`max-width: 720sp`);if(m){let e=new n.Breakpoint({condition:m});e.connect(`apply`,()=>{this._main_split_view.collapsed=!0,this._controls_split_view.collapsed=!0}),e.connect(`unapply`,()=>{this._main_split_view.collapsed=!1,this._controls_split_view.collapsed=!1}),this.add_breakpoint(e)}}_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;e instanceof n.PreferencesRow&&e.set_use_markup(!1),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 i.ListBoxRow({selectable:!1}),n=new i.Label({label:e,halign:i.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 i.ListBoxRow,r=new i.Label({label:t||`Unnamed Story`,halign:i.Align.START,margin_start:20,margin_top:6,margin_bottom:6});n.set_child(r),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)}};s.type_ensure(c.$gtype);export{c as StorybookWindow};
@@ -0,0 +1,27 @@
1
+ import Adw from '@girs/adw-1';
2
+ import { StorybookSettings } from '@gjsify/storybook-core';
3
+ /** Owns the GTK side of {@link StorybookSettings} — the style manager and the accent provider. */
4
+ export declare class StorybookAppearance {
5
+ readonly settings: StorybookSettings;
6
+ private readonly _styleManager;
7
+ private _provider;
8
+ /** Re-entrancy guard: `set_color_scheme` can fire `notify::dark` synchronously. */
9
+ private _applying;
10
+ constructor();
11
+ private _apply;
12
+ /**
13
+ * @param accent The accent to force, or `null` to hand the choice back to the
14
+ * desktop. Clearing has to EMPTY the provider rather than skip the call: a
15
+ * stale override would otherwise keep winning over `StyleManager` forever,
16
+ * which is the failure that makes a "follow system" switch do nothing.
17
+ */
18
+ private _applyAccent;
19
+ }
20
+ /**
21
+ * The appearance dialog: the colour scheme, and the accent behind a switch.
22
+ *
23
+ * An `Adw.PreferencesDialog` rather than a popover — the palette is nine swatches
24
+ * plus a switch row, which a popover squeezes, and the sections need headings to
25
+ * say which choice is which.
26
+ */
27
+ export declare function buildAppearanceDialog(appearance: StorybookAppearance): Adw.PreferencesDialog;
@@ -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\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";
1
+ export declare const STORYBOOK_CSS = "\n/* Appearance dialog \u2014 round swatches with a selection ring, the shape GNOME's own\n appearance switcher uses. Adapted from Learn6502's theme-mode-selector.css and\n accent-color-selector.css (JumpLink/easy6502, MIT).\n\n The inner `radio` indicator is switched off because the swatch IS the\n indicator: a check mark drawn on top of a colour reads as two competing\n signals, and the ring already says which one is selected.\n `background-clip: content-box` is what keeps the ring outside the fill rather\n than tinting it. */\n.storybook-swatch {\n min-width: 24px;\n min-height: 24px;\n padding: 6px;\n border-radius: 9999px;\n background-clip: content-box;\n background-image: none;\n box-shadow: inset 0 0 0 3px transparent;\n}\n.storybook-swatch:checked {\n box-shadow: inset 0 0 0 3px var(--accent-bg-color);\n}\n.storybook-swatch radio {\n -gtk-icon-source: none;\n border: none;\n background: none;\n box-shadow: none;\n min-width: 12px;\n min-height: 12px;\n padding: 0;\n transform: none;\n}\n/* Desaturated rather than merely dimmed: while the accent follows the desktop the\n palette has to read as unavailable, not as nine slightly faded choices. */\n.storybook-swatch:disabled {\n filter: saturate(0.4) brightness(1.05);\n opacity: 0.7;\n}\n/* The scheme swatches are larger \u2014 they are the dialog's primary choice. */\n.storybook-swatch.storybook-scheme-swatch {\n min-width: 44px;\n min-height: 44px;\n}\n/* \"Follow system\" is drawn as the two schemes meeting on a diagonal, so the option\n looks like what it does instead of needing a word for it. */\n.storybook-swatch.storybook-scheme-system {\n background-image: linear-gradient(to bottom right, #f6f5f4 49.99%, #241f31 50.01%);\n}\n.storybook-swatch.storybook-scheme-light {\n background-color: #f6f5f4;\n}\n.storybook-swatch.storybook-scheme-dark {\n background-color: #241f31;\n}\n/* Squares the top corners so a swatch card sits flush under the row it belongs to,\n instead of the two reading as separate cards with a seam between them. */\n.storybook-card-attached {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n/* \u2026and the OTHER half, which squaring only the card cannot do: the row above lives\n in the group's .boxed-list, whose own bottom corners are still round, so the two\n met with a notch at each end. Both sides have to be squared for the join to read\n as one list. The transparent bottom border keeps the boxed-list's height where it\n was, so squaring it does not shift the card up by a pixel.\n Adapted from Learn6502's views/preferences.dialog.css (JumpLink/easy6502, MIT). */\n.storybook-attached-group .boxed-list {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom: 1px solid transparent;\n}\n\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";
@@ -15,6 +15,8 @@ export declare class StorybookWindow extends Adw.ApplicationWindow implements St
15
15
  private _control_panel;
16
16
  private _preview_title;
17
17
  private _show_controls_button;
18
+ /** Colour scheme + accent for the whole storybook, not for one story. */
19
+ private _appearance;
18
20
  private _controls_split_view;
19
21
  private _main_split_view;
20
22
  private _controlRows;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/storybook",
3
- "version": "0.37.0",
3
+ "version": "0.38.1",
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,13 +41,15 @@
41
41
  "@girs/glib-2.0": "^4.1.0",
42
42
  "@girs/gobject-2.0": "^4.1.0",
43
43
  "@girs/gtk-4.0": "^4.1.0",
44
- "@gjsify/devtools": "^0.37.0",
45
- "@gjsify/stories": "^0.37.0",
46
- "@gjsify/storybook-core": "^0.37.0"
44
+ "@gjsify/adwaita-app": "^0.38.1",
45
+ "@gjsify/adwaita-core": "^0.38.1",
46
+ "@gjsify/devtools": "^0.38.1",
47
+ "@gjsify/stories": "^0.38.1",
48
+ "@gjsify/storybook-core": "^0.38.1"
47
49
  },
48
50
  "devDependencies": {
49
- "@gjsify/cli": "^0.37.0",
50
- "@gjsify/unit": "^0.37.0",
51
+ "@gjsify/cli": "^0.38.1",
52
+ "@gjsify/unit": "^0.38.1",
51
53
  "@types/node": "^25.9.2",
52
54
  "typescript": "^6.0.3"
53
55
  },