@gjsify/adwaita-nativescript 0.30.0 → 0.32.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 (146) hide show
  1. package/lib/esm/index.js +1 -1
  2. package/lib/esm/widgets/adw-action-row.js +1 -1
  3. package/lib/esm/widgets/adw-avatar.js +1 -1
  4. package/lib/esm/widgets/adw-banner.js +1 -1
  5. package/lib/esm/widgets/adw-bottom-sheet.js +1 -1
  6. package/lib/esm/widgets/adw-button-content.js +1 -1
  7. package/lib/esm/widgets/adw-button-row.js +1 -1
  8. package/lib/esm/widgets/adw-carousel.js +1 -1
  9. package/lib/esm/widgets/adw-clamp.js +1 -1
  10. package/lib/esm/widgets/adw-combo-row.js +1 -1
  11. package/lib/esm/widgets/adw-data-grid.js +1 -0
  12. package/lib/esm/widgets/adw-drop-down.js +1 -0
  13. package/lib/esm/widgets/adw-entry-row.js +1 -1
  14. package/lib/esm/widgets/adw-entry.js +1 -0
  15. package/lib/esm/widgets/adw-expander-row.js +1 -1
  16. package/lib/esm/widgets/adw-header-bar.js +1 -1
  17. package/lib/esm/widgets/adw-inline-view-switcher.js +1 -1
  18. package/lib/esm/widgets/adw-navigation-split-view.js +1 -1
  19. package/lib/esm/widgets/adw-navigation-view.js +1 -1
  20. package/lib/esm/widgets/adw-overlay-split-view.js +1 -1
  21. package/lib/esm/widgets/adw-password-entry-row.js +1 -1
  22. package/lib/esm/widgets/adw-preferences-dialog.js +1 -1
  23. package/lib/esm/widgets/adw-preferences-group.js +1 -1
  24. package/lib/esm/widgets/adw-preferences-page.js +1 -1
  25. package/lib/esm/widgets/adw-sidebar.js +1 -1
  26. package/lib/esm/widgets/adw-spin-row.js +1 -1
  27. package/lib/esm/widgets/adw-spinner.js +1 -1
  28. package/lib/esm/widgets/adw-split-button.js +1 -1
  29. package/lib/esm/widgets/adw-status-page.js +1 -1
  30. package/lib/esm/widgets/adw-switch-row.js +1 -1
  31. package/lib/esm/widgets/adw-tab-view.js +1 -1
  32. package/lib/esm/widgets/adw-toolbar-view.js +1 -1
  33. package/lib/esm/widgets/adw-view-stack.js +1 -1
  34. package/lib/esm/widgets/adw-view-switcher-bar.js +1 -1
  35. package/lib/esm/widgets/adw-window-title.js +1 -1
  36. package/lib/esm/widgets/adw-wrap-box.js +1 -1
  37. package/lib/esm/widgets/avatar-color.js +1 -0
  38. package/lib/esm/widgets/bottom-sheet-state.js +1 -0
  39. package/lib/esm/widgets/button-content.js +1 -0
  40. package/lib/esm/widgets/carousel-state.js +1 -0
  41. package/lib/esm/widgets/chrome.js +1 -0
  42. package/lib/esm/widgets/data-grid-model.js +1 -0
  43. package/lib/esm/widgets/entry-row-view.js +1 -0
  44. package/lib/esm/widgets/icon-path.js +2 -2
  45. package/lib/esm/widgets/icons.ios.js +1 -0
  46. package/lib/esm/widgets/index.js +1 -1
  47. package/lib/esm/widgets/navigation-stack.js +1 -0
  48. package/lib/esm/widgets/preferences-group-state.js +1 -0
  49. package/lib/esm/widgets/preferences-search.js +1 -0
  50. package/lib/esm/widgets/row-state.js +1 -0
  51. package/lib/esm/widgets/sidebar-model.js +1 -0
  52. package/lib/esm/widgets/split-button.js +1 -0
  53. package/lib/esm/widgets/split-view-base.js +1 -1
  54. package/lib/esm/widgets/split-view-state.js +1 -0
  55. package/lib/esm/widgets/split-view-width.js +1 -0
  56. package/lib/esm/widgets/status-page-content.js +1 -0
  57. package/lib/esm/widgets/svg-path.js +2 -0
  58. package/lib/esm/widgets/tab-view-state.js +1 -0
  59. package/lib/esm/widgets/view-stack-state.js +1 -0
  60. package/lib/esm/widgets/view-switcher-base.js +1 -1
  61. package/lib/esm/widgets/view-switcher-model.js +1 -0
  62. package/lib/esm/widgets/wrap-box-layout.js +1 -0
  63. package/lib/types/banner.spec.d.ts +2 -0
  64. package/lib/types/bottom-sheet.spec.d.ts +2 -0
  65. package/lib/types/button-content.spec.d.ts +2 -0
  66. package/lib/types/carousel.spec.d.ts +1 -0
  67. package/lib/types/chrome.spec.d.ts +2 -0
  68. package/lib/types/data-grid.spec.d.ts +2 -0
  69. package/lib/types/drop-down.spec.d.ts +2 -0
  70. package/lib/types/entry-rows.spec.d.ts +2 -0
  71. package/lib/types/entry.spec.d.ts +2 -0
  72. package/lib/types/index.d.ts +2 -2
  73. package/lib/types/navigation-view.spec.d.ts +2 -0
  74. package/lib/types/preferences.spec.d.ts +2 -0
  75. package/lib/types/row-state.spec.d.ts +2 -0
  76. package/lib/types/sidebar.spec.d.ts +1 -0
  77. package/lib/types/split-button.spec.d.ts +1 -0
  78. package/lib/types/split-view-state.spec.d.ts +2 -0
  79. package/lib/types/split-view-width.spec.d.ts +2 -0
  80. package/lib/types/status-page.spec.d.ts +2 -0
  81. package/lib/types/svg-path.spec.d.ts +2 -0
  82. package/lib/types/tab-view.spec.d.ts +2 -0
  83. package/lib/types/view-stack.spec.d.ts +2 -0
  84. package/lib/types/view-switcher.spec.d.ts +1 -0
  85. package/lib/types/widgets/adw-action-row.d.ts +63 -7
  86. package/lib/types/widgets/adw-avatar.d.ts +2 -7
  87. package/lib/types/widgets/adw-banner.d.ts +26 -7
  88. package/lib/types/widgets/adw-bottom-sheet.d.ts +29 -11
  89. package/lib/types/widgets/adw-button-content.d.ts +41 -6
  90. package/lib/types/widgets/adw-button-row.d.ts +31 -9
  91. package/lib/types/widgets/adw-carousel.d.ts +70 -15
  92. package/lib/types/widgets/adw-clamp.d.ts +21 -4
  93. package/lib/types/widgets/adw-data-grid.d.ts +73 -0
  94. package/lib/types/widgets/adw-drop-down.d.ts +45 -0
  95. package/lib/types/widgets/adw-entry-row.d.ts +98 -2
  96. package/lib/types/widgets/adw-entry.d.ts +43 -0
  97. package/lib/types/widgets/adw-expander-row.d.ts +3 -0
  98. package/lib/types/widgets/adw-header-bar.d.ts +11 -2
  99. package/lib/types/widgets/adw-inline-view-switcher.d.ts +26 -0
  100. package/lib/types/widgets/adw-navigation-split-view.d.ts +2 -1
  101. package/lib/types/widgets/adw-navigation-view.d.ts +71 -16
  102. package/lib/types/widgets/adw-overlay-split-view.d.ts +29 -2
  103. package/lib/types/widgets/adw-password-entry-row.d.ts +33 -3
  104. package/lib/types/widgets/adw-preferences-dialog.d.ts +18 -0
  105. package/lib/types/widgets/adw-preferences-group.d.ts +56 -8
  106. package/lib/types/widgets/adw-preferences-page.d.ts +32 -1
  107. package/lib/types/widgets/adw-sidebar.d.ts +49 -7
  108. package/lib/types/widgets/adw-spinner.d.ts +8 -3
  109. package/lib/types/widgets/adw-split-button.d.ts +48 -13
  110. package/lib/types/widgets/adw-status-page.d.ts +5 -10
  111. package/lib/types/widgets/adw-switch-row.d.ts +21 -1
  112. package/lib/types/widgets/adw-tab-view.d.ts +129 -15
  113. package/lib/types/widgets/adw-toolbar-view.d.ts +39 -0
  114. package/lib/types/widgets/adw-view-stack.d.ts +30 -27
  115. package/lib/types/widgets/adw-view-switcher-bar.d.ts +22 -10
  116. package/lib/types/widgets/adw-window-title.d.ts +12 -8
  117. package/lib/types/widgets/adw-wrap-box.d.ts +21 -4
  118. package/lib/types/widgets/avatar-color.d.ts +14 -0
  119. package/lib/types/widgets/bottom-sheet-state.d.ts +73 -0
  120. package/lib/types/widgets/button-content.d.ts +43 -0
  121. package/lib/types/widgets/carousel-state.d.ts +85 -0
  122. package/lib/types/widgets/chrome.d.ts +159 -0
  123. package/lib/types/widgets/data-grid-model.d.ts +104 -0
  124. package/lib/types/widgets/entry-row-view.d.ts +88 -0
  125. package/lib/types/widgets/icon-path.d.ts +20 -0
  126. package/lib/types/widgets/icons.ios.d.ts +13 -0
  127. package/lib/types/widgets/index.d.ts +20 -5
  128. package/lib/types/widgets/navigation-stack.d.ts +153 -0
  129. package/lib/types/widgets/preferences-group-state.d.ts +52 -0
  130. package/lib/types/widgets/preferences-search.d.ts +68 -0
  131. package/lib/types/widgets/row-state.d.ts +71 -0
  132. package/lib/types/widgets/sidebar-model.d.ts +18 -0
  133. package/lib/types/widgets/split-button.d.ts +55 -0
  134. package/lib/types/widgets/split-view-base.d.ts +55 -12
  135. package/lib/types/widgets/split-view-state.d.ts +196 -0
  136. package/lib/types/widgets/split-view-width.d.ts +76 -0
  137. package/lib/types/widgets/status-page-content.d.ts +23 -0
  138. package/lib/types/widgets/svg-path.d.ts +28 -0
  139. package/lib/types/widgets/tab-view-state.d.ts +74 -0
  140. package/lib/types/widgets/view-stack-state.d.ts +35 -0
  141. package/lib/types/widgets/view-switcher-base.d.ts +61 -32
  142. package/lib/types/widgets/view-switcher-model.d.ts +114 -0
  143. package/lib/types/widgets/wrap-box-layout.d.ts +43 -0
  144. package/lib/types/wrap-box.spec.d.ts +2 -0
  145. package/package.json +7 -7
  146. package/src/theme/adwaita.css +393 -8
@@ -0,0 +1,68 @@
1
+ import type { PreferencesSearchPage, PreferencesSearchResult, SearchPreferencesOptions } from '@gjsify/adwaita-core';
2
+ /**
3
+ * What the search reads off a row widget.
4
+ *
5
+ * `isActionRow` is a declared property rather than an `instanceof` test,
6
+ * because the NativeScript hierarchy does NOT match the GObject one:
7
+ * `AdwEntryRow extends AdwActionRow` here so it can reuse the row chrome, while
8
+ * in C it derives from `AdwPreferencesRow` (adw-entry-row.c:90) and its text is
9
+ * therefore deliberately NOT searchable. The row classes carry the C answer.
10
+ */
11
+ export interface NsSearchableRow {
12
+ /** `AdwPreferencesRow:title`. */
13
+ readonly title?: string;
14
+ /** `AdwActionRow:subtitle`; only consulted when `isActionRow`. */
15
+ readonly subtitle?: string;
16
+ /** Whether the row derives from `AdwActionRow` in libadwaita. */
17
+ readonly isActionRow?: boolean;
18
+ /** NS `View.visibility`. */
19
+ readonly visibility?: string;
20
+ }
21
+ /** What the search reads off a group widget. */
22
+ export interface NsSearchableGroup {
23
+ /** `AdwPreferencesGroup:title`. */
24
+ readonly title?: string;
25
+ /** NS `View.visibility`. */
26
+ readonly visibility?: string;
27
+ /** The group's boxed-list rows, in order. */
28
+ searchRows(): readonly NsSearchableRow[];
29
+ }
30
+ /** What the search reads off a page widget. */
31
+ export interface NsSearchablePage {
32
+ /** `AdwPreferencesPage:title`. */
33
+ readonly title?: string;
34
+ /** `AdwPreferencesPage:name` — the view-stack child name. */
35
+ readonly name?: string;
36
+ /** `AdwPreferencesPage:use-underline`. */
37
+ readonly useUnderline?: boolean;
38
+ /** NS `View.visibility`. */
39
+ readonly visibility?: string;
40
+ /** The page's groups, in order. */
41
+ searchGroups(): readonly NsSearchableGroup[];
42
+ }
43
+ /** Any node a search result can point back at. */
44
+ export type NsSearchableNode = NsSearchablePage | NsSearchableGroup | NsSearchableRow;
45
+ /** A described NS preferences tree, ready for `searchPreferences`. */
46
+ export type NsPreferencesSearchPage = PreferencesSearchPage<NsSearchableNode>;
47
+ /** One NS search result, carrying the page and row widgets it came from. */
48
+ export type NsPreferencesSearchResult = PreferencesSearchResult<NsSearchableNode>;
49
+ /**
50
+ * `gtk_widget_get_visible` for a NativeScript view.
51
+ *
52
+ * NS has THREE values where GTK has a boolean, and only `'visible'` counts as
53
+ * shown: `'collapse'` removes the view from layout and `'hidden'` keeps its
54
+ * space but paints nothing — neither is something a user can read or reach, so
55
+ * neither belongs in a search index. An undefined value is a view that never
56
+ * set the property, i.e. the NS default `'visible'`.
57
+ */
58
+ export declare function isNsVisible(visibility: string | undefined): boolean;
59
+ /** Describe a list of page widgets as the tree `searchPreferences` indexes. */
60
+ export declare function describeNsPreferencesPages(pages: readonly NsSearchablePage[]): NsPreferencesSearchPage[];
61
+ /**
62
+ * Search a list of NativeScript preferences pages.
63
+ *
64
+ * An empty query returns the WHOLE corpus, which is what C does
65
+ * (`strstr (title, "")` is non-NULL) and what keeps the results list populated
66
+ * before the user has typed.
67
+ */
68
+ export declare function searchNsPreferences(pages: readonly NsSearchablePage[], query: string, options?: SearchPreferencesOptions): NsPreferencesSearchResult[];
@@ -0,0 +1,71 @@
1
+ import { ActionRowState, ButtonRowState, SwitchRowState, WindowTitleState } from '@gjsify/adwaita-core';
2
+ import type { AdwRowLabelInput, AdwRowLabels, ButtonRowRenderState } from '@gjsify/adwaita-core';
3
+ import type { View } from '@nativescript/core';
4
+ export { ActionRowState, ButtonRowState, SwitchRowState, WindowTitleState };
5
+ export type { AdwRowLabels, ButtonRowRenderState };
6
+ /** The two `View.visibility` values an Adwaita row ever assigns. */
7
+ export type NsVisibility = 'visible' | 'collapse';
8
+ /**
9
+ * `visibility` for a shown/hidden view.
10
+ *
11
+ * `'collapse'` rather than `'hidden'`: a hidden NS view still occupies its
12
+ * space, so an empty subtitle would leave its whole line behind — which is the
13
+ * one thing the binding exists to prevent.
14
+ */
15
+ export declare function nsVisibility(shown: boolean): NsVisibility;
16
+ /** The NativeScript form of a title/subtitle label pair. */
17
+ export interface NsRowLabelVisuals {
18
+ /** Text for the title `Label`. */
19
+ title: string;
20
+ /** `visibility` for the title `Label`. */
21
+ titleVisibility: NsVisibility;
22
+ /** Text for the subtitle `Label`. */
23
+ subtitle: string;
24
+ /** `visibility` for the subtitle `Label`. */
25
+ subtitleVisibility: NsVisibility;
26
+ }
27
+ /** What a row must apply to its two labels for the given title/subtitle. */
28
+ export declare function rowLabelVisuals(input: AdwRowLabelInput): NsRowLabelVisuals;
29
+ /** The same mapping, for a state object that already holds the derivation. */
30
+ export declare function toLabelVisuals(labels: AdwRowLabels): NsRowLabelVisuals;
31
+ /** The NativeScript form of an `Adw.ButtonRow`'s two icons. */
32
+ export interface NsButtonRowIconVisuals {
33
+ /** Payload for the leading icon. */
34
+ startIcon: string;
35
+ /** `visibility` for the leading icon. */
36
+ startIconVisibility: NsVisibility;
37
+ /** Payload for the trailing icon. */
38
+ endIcon: string;
39
+ /** `visibility` for the trailing icon. */
40
+ endIconVisibility: NsVisibility;
41
+ }
42
+ /**
43
+ * What a button row must apply to its two icons.
44
+ *
45
+ * The TITLE half of `ButtonRowRenderState` is deliberately not mapped here: the
46
+ * NativeScript button row reuses the action row's title `Label` and therefore
47
+ * its title state, so routing the title through a second state object would give
48
+ * one label two sources of truth — the exact shape this package exists to
49
+ * remove. {@link rowLabelVisuals} paints it.
50
+ *
51
+ * NOTE ON THE ICON PAYLOAD: GTK stores an icon NAME and resolves it through the
52
+ * icon theme; this port stores the symbolic SVG source itself, because `AdwIcon`
53
+ * renders SVG rather than looking a name up. `ButtonRowState` is indifferent —
54
+ * the rule it applies is `string_is_not_empty`, which reads the first byte and
55
+ * does not care what the string means.
56
+ */
57
+ export declare function buttonRowIconVisuals(state: ButtonRowRenderState): NsButtonRowIconVisuals;
58
+ /**
59
+ * Whether a view is "sensitive" in the sense the `activatable-widget` binding
60
+ * reads (`GtkWidget:sensitive` → `GtkListBoxRow:activatable`,
61
+ * adw-action-row.c:729-732).
62
+ *
63
+ * NativeScript has no `sensitive`; `isUserInteractionEnabled` is the nearest
64
+ * flag it surfaces (its own docs map it to `gtk_widget_set_can_target`). The two
65
+ * are not identical in GTK — an insensitive widget is also greyed out, a
66
+ * can't-target one is not — but `isUserInteractionEnabled` is the only property
67
+ * a NativeScript view has for "the user cannot operate this", so it is what the
68
+ * binding reads here. A view that has never been touched reports `true`, which
69
+ * is also GTK's default.
70
+ */
71
+ export declare function isViewSensitive(view: Pick<View, 'isUserInteractionEnabled'> | null | undefined): boolean;
@@ -0,0 +1,18 @@
1
+ import { SidebarState } from '@gjsify/adwaita-core';
2
+ import type { AdwSidebarItemSpec, AdwSidebarSectionSpec, SidebarItemFilter } from '@gjsify/adwaita-core';
3
+ export { SidebarState };
4
+ export type { AdwSidebarItemSpec, AdwSidebarSectionSpec, SidebarItemFilter };
5
+ /**
6
+ * The section list a flat `AdwSidebar.setItems(labels)` call means: one untitled
7
+ * section, which renders no header at all (a first + untitled section's header is
8
+ * bound to a non-empty title, adw-sidebar.c:1521-1527).
9
+ */
10
+ export declare function sidebarSectionsFromLabels(labels: readonly string[]): AdwSidebarSectionSpec[];
11
+ /**
12
+ * The class string one navigation row carries.
13
+ *
14
+ * `selectionVisible` is false in page mode, where libadwaita tracks the
15
+ * selection but never paints it (adw-sidebar.c:2948-2951) — its rows are plain
16
+ * boxed-list `AdwActionRow`s with no selected state.
17
+ */
18
+ export declare function sidebarRowClassName(selected: boolean, selectionVisible: boolean): string;
@@ -0,0 +1,55 @@
1
+ import type { AdwArrowIcon, AdwMenuEntry, SplitButtonDirection, SplitButtonState } from '@gjsify/adwaita-core';
2
+ export type { AdwMenuEntry, SplitButtonDirection };
3
+ /** Text of the sheet's dismiss button. */
4
+ export declare const MENU_CANCEL_LABEL = "Cancel";
5
+ /**
6
+ * The libadwaita arrow glyph names mapped to real Adwaita symbolic SVGs.
7
+ *
8
+ * Keyed by {@link AdwArrowIcon} and therefore TOTAL: which glyph a direction gets
9
+ * is decided in core, and a glyph this table has no SVG for is a compile error
10
+ * rather than a fallback arrow.
11
+ */
12
+ export declare const ARROW_SVGS: Readonly<Record<AdwArrowIcon, string>>;
13
+ /**
14
+ * Normalise a menu assigned from XML or app code into entries.
15
+ *
16
+ * A bare `string[]` is accepted because that is what `AdwSplitButton.menu` used
17
+ * to be and what the storybook still passes; it widens to the shared
18
+ * {@link AdwMenuEntry} without breaking a caller.
19
+ */
20
+ export declare function toMenuEntries(value: readonly (string | AdwMenuEntry)[] | null | undefined): AdwMenuEntry[];
21
+ /**
22
+ * The strings handed to `Dialogs.action()`, one per entry and each unique.
23
+ *
24
+ * A label that collides with another entry — or with the dismiss button — gets
25
+ * zero-width spaces appended until it is distinct. Nothing changes on screen;
26
+ * what changes is that {@link resolveMenuChoice} can now tell the entries apart.
27
+ */
28
+ export declare function menuSheetActions(entries: readonly AdwMenuEntry[], cancelLabel?: string): string[];
29
+ /**
30
+ * The position the user chose, or `-1` when the sheet was dismissed.
31
+ *
32
+ * Feed it the SAME array {@link menuSheetActions} produced: the strings are
33
+ * unique there, so the lookup is a position and not a guess.
34
+ */
35
+ export declare function resolveMenuChoice(sheetActions: readonly string[], chosen: string | null | undefined): number;
36
+ /**
37
+ * The arrow SVG for a direction, keyed off the SPLIT BUTTON's glyph map — so
38
+ * `none` is the down caret (_buttons.scss:621-623), not the hamburger this widget
39
+ * used to render for it.
40
+ */
41
+ export declare function splitButtonArrowSvg(direction: SplitButtonDirection): string;
42
+ /**
43
+ * Apply `AdwSplitButton.actionIcon = svg` to the content machine.
44
+ *
45
+ * The SVG string IS the icon identity on NativeScript (no icon theme is
46
+ * resolved), so it goes in where GTK puts the icon NAME. Clearing it is the
47
+ * mapping worth having in one place: C offers no "unset the icon", only the
48
+ * side effect of filling another slot (adw-split-button.c:749-771), so an empty
49
+ * SVG clears the content and lets the label half take over again — which is what
50
+ * every caller assigning `actionIcon` from a nullable lookup expects.
51
+ *
52
+ * Lives here rather than in the widget so it is unit-testable off-device: the
53
+ * widget module `extends GridLayout` and cannot be imported on GJS/Node.
54
+ */
55
+ export declare function setActionIcon(state: SplitButtonState, svg: string | null | undefined): void;
@@ -1,4 +1,6 @@
1
1
  import { type Cancelable, type EventData, GridLayout, type View } from '@nativescript/core';
2
+ import { type SidebarWidthProps, type SplitViewWidthRule } from './split-view-width.js';
3
+ import type { AdwPackType, NsShowSidebarNotification, NsSplitViewState } from './split-view-state.js';
2
4
  /** Event name emitted when the sidebar visibility changes. */
3
5
  export declare const NOTIFY_SHOW_SIDEBAR = "notify::show-sidebar";
4
6
  /** Payload of the `notify::show-sidebar` event. */
@@ -8,24 +10,38 @@ export interface NotifyShowSidebarEventData extends EventData {
8
10
  /** Whether the view is in its collapsed (narrow) mode. */
9
11
  collapsed: boolean;
10
12
  }
11
- /** Default sidebar width, in DIPs. */
12
- export declare const DEFAULT_SIDEBAR_WIDTH = 240;
13
- export declare abstract class AdwSplitViewBase extends GridLayout {
13
+ export declare abstract class AdwSplitViewBase<TState extends NsSplitViewState = NsSplitViewState> extends GridLayout {
14
+ /** Which widget's width rule applies — they differ once a pane has a minimum. */
15
+ protected readonly _widthRule: SplitViewWidthRule;
16
+ /** The headless state machine this widget renders (`split-view-state.ts`). */
17
+ protected readonly _state: TState;
14
18
  protected _sidebar: View | null;
15
19
  protected _content: View | null;
16
- protected _collapsed: boolean;
17
- protected _showSidebar: boolean;
18
- protected _sidebarWidth: number;
19
- protected _sidebarPosition: 'start' | 'end';
20
- constructor(rootClass: string);
20
+ /** The three width PROPERTIES; the drawn width is derived from them. */
21
+ protected _widthProps: SidebarWidthProps;
22
+ /** The container width the sidebar was last sized against, in DIPs. */
23
+ protected _measuredWidth: number;
24
+ /** An explicit `sidebarWidth` assignment, which overrides the derivation. */
25
+ protected _sidebarWidthOverride: number | null;
26
+ constructor(rootClass: string,
27
+ /** Which widget's width rule applies — they differ once a pane has a minimum. */
28
+ _widthRule: SplitViewWidthRule,
29
+ /** The headless state machine this widget renders (`split-view-state.ts`). */
30
+ _state: TState);
21
31
  /**
22
32
  * (Re)declare the two columns so the sidebar's column is fixed-width ('auto')
23
33
  * and the content's is expanding ('star'), ordered by {@link sidebarPosition}:
24
34
  * `start` → [sidebar auto, content star]; `end` → [content star, sidebar auto].
25
35
  * Without this an `end` sidebar would land in the expanding column and float
26
36
  * away from the right edge (leaving a gap), with the content squeezed.
37
+ *
38
+ * `splitViewColumns()` is the other half of the same rule — which column each
39
+ * PANE is written into. The two must agree, or an `end` sidebar ends up in the
40
+ * expanding column with the content squeezed into the fixed one.
27
41
  */
28
42
  protected _syncColumns(): void;
43
+ /** Re-emit `notify::show-sidebar` for a state change. */
44
+ protected _emitShowSidebar(event: NsShowSidebarNotification): void;
29
45
  /** Subclass-specific layout application for the current collapsed/show state. */
30
46
  protected abstract _applyLayout(): void;
31
47
  /** Apply a user-initiated show/hide toggle. The default is an instant re-layout;
@@ -54,20 +70,47 @@ export declare abstract class AdwSplitViewBase extends GridLayout {
54
70
  showSidebarPane(): void;
55
71
  /** Hide the sidebar (relevant in collapsed mode). */
56
72
  hideSidebarPane(): void;
57
- /** Whether the view is in collapsed (narrow / single-pane) mode. */
73
+ /**
74
+ * Whether the view is in collapsed (narrow / single-pane) mode.
75
+ *
76
+ * On an OVERLAY split view this is not an independent flag: unless the sidebar
77
+ * is pinned, collapsing hides it and uncollapsing shows it, emitting
78
+ * `notify::show-sidebar` first — the state machine owns that, not this setter.
79
+ */
58
80
  get collapsed(): boolean;
59
81
  set collapsed(value: boolean);
60
82
  /** Whether the sidebar is shown. Toggling emits `notify::show-sidebar`. */
61
83
  get showSidebar(): boolean;
62
84
  set showSidebar(value: boolean);
63
- /** The sidebar pane width, in DIPs. */
85
+ /**
86
+ * The sidebar pane width in DIPs, DERIVED from the container size unless a
87
+ * caller assigned one. `Adw.OverlaySplitView` has no stored width — see
88
+ * `split-view-width.ts` for why the old fixed 240 could not be right.
89
+ */
64
90
  get sidebarWidth(): number;
65
91
  set sidebarWidth(value: number);
92
+ /** Lower bound in DIPs (`Adw.OverlaySplitView:min-sidebar-width`, default 180). */
93
+ get minSidebarWidth(): number;
94
+ set minSidebarWidth(value: number);
95
+ /** Upper bound in DIPs (`Adw.OverlaySplitView:max-sidebar-width`, default 280). */
96
+ get maxSidebarWidth(): number;
97
+ set maxSidebarWidth(value: number);
98
+ /** Share of the container the sidebar asks for (default 0.25). */
99
+ get sidebarWidthFraction(): number;
100
+ set sidebarWidthFraction(value: number);
101
+ /**
102
+ * Re-measure the container and re-size the sidebar.
103
+ *
104
+ * Called from `layoutChanged`, the same size source `addBreakpoints` uses —
105
+ * NativeScript has no window-resize signal, so a view's post-layout size is
106
+ * the closest thing to the window size Adwaita evaluates against.
107
+ */
108
+ protected _applySidebarWidth(): void;
66
109
  /** Which side the sidebar sits on — `'start'` (leading / left) or `'end'`
67
110
  * (trailing / right). Mirrors `Adw.OverlaySplitView`'s `sidebar-position`
68
111
  * (the storybook controls overlay uses `'end'`). */
69
- get sidebarPosition(): 'start' | 'end';
70
- set sidebarPosition(value: 'start' | 'end');
112
+ get sidebarPosition(): AdwPackType;
113
+ set sidebarPosition(value: AdwPackType);
71
114
  /** The sidebar pane, or `null`. */
72
115
  get sidebar(): View | null;
73
116
  /** The content pane, or `null`. */
@@ -0,0 +1,196 @@
1
+ import type { AdwPackType, NavigationStackPlan, OverlaySplitViewOptions, SplitViewPane } from '@gjsify/adwaita-core';
2
+ export type { AdwPackType, NavigationStackPlan, SplitViewPane };
3
+ /** Payload of the `notify::show-sidebar` a state change asks the widget to emit. */
4
+ export interface NsShowSidebarNotification {
5
+ /** Whether the sidebar is meant to be shown. */
6
+ showSidebar: boolean;
7
+ /** Whether the view is in its collapsed (narrow) mode. */
8
+ collapsed: boolean;
9
+ }
10
+ /**
11
+ * The NativeScript side of a split view: what a state change makes it do.
12
+ *
13
+ * Only the changes with real ordering or animation semantics come through here.
14
+ * Structural mutations (mounting a pane, moving the sidebar to the other side)
15
+ * stay the widget's own business, because they also have to re-declare the grid
16
+ * columns — a callback would only be able to run after that anyway.
17
+ */
18
+ export interface NsSplitViewHost {
19
+ /** Re-run the structural layout for the SETTLED state. Instant. */
20
+ applyLayout(): void;
21
+ /** Run the animated sidebar reveal / master⇄detail swap — a user-driven toggle. */
22
+ transitionSidebar(): void;
23
+ /** Re-emit `notify::show-sidebar`. */
24
+ notifyShowSidebar(event: NsShowSidebarNotification): void;
25
+ }
26
+ /** The `collapsed` + `show-sidebar` surface `AdwSplitViewBase` delegates to. */
27
+ export interface NsSplitViewState {
28
+ /** Whether the panes are stacked (one at a time) rather than side by side. */
29
+ readonly collapsed: boolean;
30
+ /** Whether the sidebar is meant to be shown. */
31
+ readonly showSidebar: boolean;
32
+ /** Which side the sidebar is packed on. */
33
+ readonly sidebarPosition: AdwPackType;
34
+ /** Attach the widget. Called exactly once, from the base constructor. */
35
+ bind(host: NsSplitViewHost): void;
36
+ /** Collapse or expand. Returns whether it changed. */
37
+ setCollapsed(value: boolean): boolean;
38
+ /** Show or hide the sidebar. Returns whether it changed. */
39
+ setShowSidebar(value: boolean): boolean;
40
+ /** Move the sidebar to the other side. Returns whether it changed. */
41
+ setSidebarPosition(position: AdwPackType): boolean;
42
+ /** Record that a pane was mounted or unmounted. Returns whether it changed. */
43
+ setPaneMounted(pane: SplitViewPane, mounted: boolean): boolean;
44
+ }
45
+ /**
46
+ * Which of the two grid columns each pane takes.
47
+ *
48
+ * `AdwSplitViewBase._syncColumns` makes the SIDEBAR's column the fixed (`'auto'`)
49
+ * one and the content's the expanding (`'star'`) one, ordered by
50
+ * `sidebar-position`. So a pane placed in the wrong column is not merely
51
+ * mirrored — it also swaps its sizing mode, which is what made an
52
+ * `end`-positioned navigation split view fully inverted: it wrote the sidebar
53
+ * into column 0 and the content into column 1 unconditionally, while the base had
54
+ * already made column 0 the star column. libadwaita allocates an `end` sidebar at
55
+ * `width - sidebar_width` (adw-navigation-split-view.c:306-316).
56
+ */
57
+ export declare function splitViewColumns(sidebarPosition: AdwPackType): {
58
+ sidebar: number;
59
+ content: number;
60
+ };
61
+ /**
62
+ * `Adw.OverlaySplitView` bound to a NativeScript widget.
63
+ *
64
+ * Holds an `OverlaySplitViewState` and turns its notifications into the two
65
+ * things NativeScript can do: re-lay the panes out, or animate the reveal. The
66
+ * widget keeps ZERO split-view state.
67
+ *
68
+ * The reveal itself is NOT driven from here. NativeScript animates with a native
69
+ * `View.animate()` on `translateX`/`opacity`, not by sampling a progress value,
70
+ * so the core's `SplitViewAnimator` seam stays on its instant default and
71
+ * `show-progress` settles at 0 or 1 — which is also what a renderer without a
72
+ * spring gets from `adw_animation_skip`.
73
+ */
74
+ export declare class NsOverlaySplitViewState implements NsSplitViewState {
75
+ private readonly _state;
76
+ private _host;
77
+ /**
78
+ * True while {@link setCollapsed} runs. The `show-sidebar` flip it couples is
79
+ * STRUCTURAL, not a user toggle: `set_collapsed` passes `animate = FALSE`
80
+ * (adw-overlay-split-view.c:1457-1458) and the `collapsed` notification right
81
+ * behind it re-lays the whole view out anyway.
82
+ */
83
+ private _coupling;
84
+ constructor(options?: OverlaySplitViewOptions);
85
+ bind(host: NsSplitViewHost): void;
86
+ /** Whether the sidebar overlays the content instead of sitting beside it. */
87
+ get collapsed(): boolean;
88
+ /** Whether the sidebar is meant to be shown. */
89
+ get showSidebar(): boolean;
90
+ /** Whether collapsing/uncollapsing leaves the sidebar's visibility alone. */
91
+ get pinSidebar(): boolean;
92
+ /** Which side the sidebar is packed on. */
93
+ get sidebarPosition(): AdwPackType;
94
+ /** The reveal progress: 0 hidden, 1 shown. */
95
+ get showProgress(): number;
96
+ /** Whether the tap-to-dismiss scrim takes input — `update_shield` (:249-256). */
97
+ get shieldVisible(): boolean;
98
+ /**
99
+ * Whether the SIDEBAR pane may take focus — `gtk_widget_set_can_focus
100
+ * (sidebar_bin, !collapsed || show_sidebar)` (:330, :1460).
101
+ *
102
+ * NativeScript's equivalent is `isUserInteractionEnabled` (the precedent is
103
+ * the decorative bottom-sheet handle, adw-bottom-sheet.c:1198). Without it the
104
+ * pane hidden behind the overlay keeps answering taps and stays in the
105
+ * screen-reader order.
106
+ */
107
+ get sidebarFocusable(): boolean;
108
+ /** Whether the CONTENT pane may take focus — the mirror of {@link sidebarFocusable} (:331, :1461). */
109
+ get contentFocusable(): boolean;
110
+ /**
111
+ * Collapse or expand. Unless the sidebar is pinned this also flips
112
+ * `show-sidebar` to match, notifying it FIRST — GTK freezes notifications
113
+ * across the whole setter and thaws them in queue order
114
+ * (adw-overlay-split-view.c:1449-1483).
115
+ */
116
+ setCollapsed(value: boolean): boolean;
117
+ /** Show or hide the sidebar — the animated, user-driven path. */
118
+ setShowSidebar(value: boolean): boolean;
119
+ /** Pin the sidebar so collapsing no longer hides it (`pin-sidebar`, :990-992). */
120
+ setPinSidebar(value: boolean): boolean;
121
+ /** Move the sidebar to the other side. The widget re-declares its columns. */
122
+ setSidebarPosition(position: AdwPackType): boolean;
123
+ /**
124
+ * No-op: `Adw.OverlaySplitView` has no navigation stack, so which children
125
+ * exist changes none of its state. Present so the two adapters share one seam.
126
+ */
127
+ setPaneMounted(_pane: SplitViewPane, _mounted: boolean): boolean;
128
+ /** Tap on the scrim — `released_cb` (:431-439) hides the sidebar unconditionally. */
129
+ dismissShield(): boolean;
130
+ private _apply;
131
+ }
132
+ /**
133
+ * `Adw.NavigationSplitView` bound to a NativeScript widget.
134
+ *
135
+ * NativeScript spells the visible pane as `showSidebar`, GTK as `show-content`;
136
+ * they are each other's negation and the core owns the meaning. What the core
137
+ * adds is the whole ordering table: which pane is on top for a given
138
+ * `sidebar-position` × `show-content` × which children exist, and whether
139
+ * reaching it is a push or a pop.
140
+ *
141
+ * Tags and the `navigation.push`/`navigation.pop` actions are NOT wired on
142
+ * NativeScript, so the panes are tracked by presence with a marker object rather
143
+ * than by handing the core a `View` — a `View` is not a `NavigationPageRef` and
144
+ * pretending otherwise would silently give a pane whatever `tag` property
145
+ * NativeScript happens to put on a view.
146
+ */
147
+ export declare class NsNavigationSplitViewState implements NsSplitViewState {
148
+ private readonly _state;
149
+ /** Presence markers — one per pane, so mounting one never looks like the other. */
150
+ private readonly _markers;
151
+ private _host;
152
+ private _plan;
153
+ constructor(options?: {
154
+ sidebarPosition?: AdwPackType;
155
+ collapsed?: boolean;
156
+ showContent?: boolean;
157
+ });
158
+ bind(host: NsSplitViewHost): void;
159
+ /** Whether the panes are stacked (one at a time) rather than side by side. */
160
+ get collapsed(): boolean;
161
+ /** Whether the SIDEBAR is the visible pane — GTK's `show-content`, negated. */
162
+ get showSidebar(): boolean;
163
+ /** Which side the sidebar is packed on. */
164
+ get sidebarPosition(): AdwPackType;
165
+ /** The settled navigation stack, root first. */
166
+ get stack(): readonly SplitViewPane[];
167
+ /**
168
+ * The pane on top of the stack — what a COLLAPSED view shows.
169
+ *
170
+ * Keyed on the stack, not on `showSidebar`: a LONE child stays visible
171
+ * whatever `show-content` says (adw-navigation-split-view.c:389-401), and
172
+ * keying on the flag alone is what rendered a sidebar-only split view blank.
173
+ */
174
+ get visiblePane(): SplitViewPane | null;
175
+ /** Whether `pane` is the one a collapsed view shows. */
176
+ isVisible(pane: SplitViewPane): boolean;
177
+ /**
178
+ * How the last `show-content` change reached its stack: `push`, `pop`, or
179
+ * `replace` for a structural rebuild that NativeScript paints instantly.
180
+ *
181
+ * This is the animation DIRECTION, and it is not `showSidebar`: with
182
+ * `sidebar-position: end` the content is the ROOT page, so showing it is a POP
183
+ * and hiding it a PUSH — the reverse of `start` (:1414-1428). Taking the
184
+ * direction from the flag ran an `end`-positioned swap backwards.
185
+ */
186
+ get transition(): NavigationStackPlan['transition'];
187
+ /** Collapse or expand. `Adw.NavigationSplitView` has no `show-content` coupling (:1341-1353). */
188
+ setCollapsed(value: boolean): boolean;
189
+ /** Show the sidebar (`true`) or the content (`false`) while collapsed. */
190
+ setShowSidebar(value: boolean): boolean;
191
+ /** Move the sidebar to the other side. The widget re-declares its columns. */
192
+ setSidebarPosition(position: AdwPackType): boolean;
193
+ /** Record that a pane was mounted or unmounted — it changes the stack. */
194
+ setPaneMounted(pane: SplitViewPane, mounted: boolean): boolean;
195
+ private _apply;
196
+ }
@@ -0,0 +1,76 @@
1
+ import { DEFAULT_MAX_SIDEBAR_WIDTH, DEFAULT_MIN_SIDEBAR_WIDTH, DEFAULT_SIDEBAR_WIDTH_FRACTION } from '@gjsify/adwaita-core';
2
+ export { DEFAULT_MAX_SIDEBAR_WIDTH, DEFAULT_MIN_SIDEBAR_WIDTH, DEFAULT_SIDEBAR_WIDTH_FRACTION };
3
+ /** The three width properties, as a split view holds them. */
4
+ export interface SidebarWidthProps {
5
+ /** Lower bound in DIPs. Defaults to libadwaita's 180. */
6
+ minSidebarWidth: number;
7
+ /** Upper bound in DIPs. Defaults to libadwaita's 280. */
8
+ maxSidebarWidth: number;
9
+ /** Share of the container the sidebar asks for. Defaults to 0.25. */
10
+ sidebarWidthFraction: number;
11
+ }
12
+ /** The property defaults a fresh split view starts with. */
13
+ export declare function defaultSidebarWidthProps(): SidebarWidthProps;
14
+ /** Which split view is asking — the two answer the same input differently. */
15
+ export type SplitViewWidthRule = 'navigation' | 'overlay';
16
+ /** What the renderer knows about the layout the width is being derived for. */
17
+ export interface SplitViewWidthContext {
18
+ /** The content pane's own minimum width. */
19
+ contentMin?: number;
20
+ /** The sidebar child's own minimum width. */
21
+ sidebarChildMin?: number;
22
+ /**
23
+ * Whether the view is collapsed. Overlay only, and not a detail: COLLAPSED
24
+ * `get_sidebar_width` IGNORES the fraction and clamps the VIEW width instead
25
+ * (adw-overlay-split-view.c:462-463), so on a 360 DIP phone GTK draws 280
26
+ * where a fraction would give 180.
27
+ */
28
+ collapsed?: boolean;
29
+ }
30
+ /**
31
+ * The sidebar width for a container of `totalWidth` DIPs.
32
+ *
33
+ * The two widgets genuinely differ, and not only in a corner: OVERLAY takes a
34
+ * final `min(width, totalWidth - contentMin)`, so it never claims more than the
35
+ * view has left; NAVIGATION folds that same limit into the clamp's UPPER bound,
36
+ * where the LOWER bound can still win — so it may exceed the view. A 100 DIP
37
+ * container with no content minimum at all already splits them: navigation
38
+ * answers 180 (its minimum), overlay answers 100 (all there is).
39
+ *
40
+ * `collapsed` only reaches the overlay rule, because only the overlay has a
41
+ * collapsed sidebar to size — a collapsed NAVIGATION pane fills the view and
42
+ * takes no derived width at all ({@link appliesDerivedSidebarWidth}).
43
+ *
44
+ * `totalWidth <= 0` means the view has not been laid out yet — NativeScript
45
+ * reports a zero size before the first pass — so the MINIMUM is returned rather
46
+ * than a fraction of nothing. That is the smallest thing libadwaita would ever
47
+ * draw, so the first layout can only widen it, never jump down.
48
+ */
49
+ export declare function sidebarWidthFor(totalWidth: number, props: SidebarWidthProps, rule?: SplitViewWidthRule, context?: SplitViewWidthContext): number;
50
+ /**
51
+ * Whether the sidebar pane takes a DERIVED width at all, or sizes itself.
52
+ *
53
+ * Only one case says no, and it is the one that cost a frame-late regression:
54
+ * a COLLAPSED navigation split view has no sidebar column. Its visible page
55
+ * fills the whole view (`gtk_bin_layout_new`,
56
+ * adw-navigation-split-view.c:538), which NativeScript expresses as
57
+ * `width = 'auto'` spanning both columns — so writing a number over it, as the
58
+ * post-layout re-measure did, snapped the full-screen pane back to 180-280 DIP
59
+ * one frame after the collapse.
60
+ *
61
+ * The overlay is deliberately NOT exempt. Its collapsed sidebar really is a
62
+ * clamped-width overlay drawn above the content
63
+ * (adw-overlay-split-view.c:462-463), so it still wants a number — a shared
64
+ * "collapsed means auto" rule would have been wrong for half the callers.
65
+ */
66
+ export declare function appliesDerivedSidebarWidth(collapsed: boolean, rule: SplitViewWidthRule): boolean;
67
+ /**
68
+ * Normalise one width property, keeping a nonsense value from reaching layout.
69
+ *
70
+ * A non-finite or negative input falls back to the default rather than to zero:
71
+ * a zero-width sidebar is indistinguishable from a missing one on screen, which
72
+ * turns a typo into a widget that looks broken instead of one that looks wrong.
73
+ */
74
+ export declare function normalizeWidthProp(value: number, fallback: number): number;
75
+ /** Clamp the fraction into the `[0, 1]` range its GTK property is declared with. */
76
+ export declare function normalizeWidthFraction(value: number): number;
@@ -0,0 +1,23 @@
1
+ /** NativeScript's `visible` / not-in-layout pair, the counterpart of GTK `visible`. */
2
+ export type StatusPageVisibility = 'visible' | 'collapse';
3
+ /**
4
+ * `string_is_not_empty` (adw-status-page.c:91-96), bound to the `visible` of BOTH
5
+ * the title and the description labels (adw-status-page.ui:41-46, :57-62).
6
+ *
7
+ * It is `string && string[0]` — one byte, no trim. A title of `" "` is a
8
+ * VISIBLE title in libadwaita, which is why this takes the raw text and never
9
+ * trims it: trimming would hide a widget GTK draws.
10
+ */
11
+ export declare function statusPageLabelVisibility(text: string | null | undefined): StatusPageVisibility;
12
+ /**
13
+ * `has_image` (adw-status-page.c:83-89), bound to the image's `visible`
14
+ * (adw-status-page.ui:23-28).
15
+ *
16
+ * C is `paintable || (icon_name && icon_name[0])` — two sources, either of which
17
+ * shows the image. This port has no `paintable` counterpart (the icon is an SVG
18
+ * string handed to `AdwIcon`), so only the second half applies; it is kept as its
19
+ * own predicate rather than folded into
20
+ * {@link statusPageLabelVisibility} because upstream really are two different
21
+ * closures, and the missing half is a real gap rather than a simplification.
22
+ */
23
+ export declare function statusPageIconVisibility(icon: string | null | undefined): StatusPageVisibility;
@@ -0,0 +1,28 @@
1
+ /** One absolute drawing command. Every SVG command reduces to these four. */
2
+ export type SvgPathCommand = {
3
+ type: 'M';
4
+ x: number;
5
+ y: number;
6
+ } | {
7
+ type: 'L';
8
+ x: number;
9
+ y: number;
10
+ } | {
11
+ type: 'C';
12
+ x1: number;
13
+ y1: number;
14
+ x2: number;
15
+ y2: number;
16
+ x: number;
17
+ y: number;
18
+ } | {
19
+ type: 'Z';
20
+ };
21
+ /**
22
+ * Parse SVG path data into absolute `M`/`L`/`C`/`Z` commands.
23
+ *
24
+ * Unparsable input yields the commands read so far rather than throwing: a
25
+ * single malformed icon must not take down the view that renders it, which is
26
+ * the same call the Android backend makes when `PathParser` rejects a subpath.
27
+ */
28
+ export declare function parseSvgPath(d: string): SvgPathCommand[];