@gjsify/adwaita-web 0.31.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.
- package/dist/adwaita-web.css +786 -272
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/adw-about-dialog.spec.d.ts +1 -0
- package/lib/types/adw-action-rows.spec.d.ts +1 -0
- package/lib/types/adw-avatar.spec.d.ts +1 -0
- package/lib/types/adw-banner.spec.d.ts +1 -0
- package/lib/types/adw-button-content.spec.d.ts +1 -0
- package/lib/types/adw-carousel.spec.d.ts +1 -0
- package/lib/types/adw-checks.spec.d.ts +1 -0
- package/lib/types/adw-header-bar.spec.d.ts +1 -0
- package/lib/types/adw-icon.spec.d.ts +1 -0
- package/lib/types/adw-progress-bar.spec.d.ts +1 -0
- package/lib/types/adw-sidebar.spec.d.ts +1 -0
- package/lib/types/adw-switch.spec.d.ts +1 -0
- package/lib/types/adw-wrap-box.spec.d.ts +1 -0
- package/lib/types/bottom-sheet.spec.d.ts +1 -0
- package/lib/types/breakpoints.d.ts +22 -0
- package/lib/types/breakpoints.spec.d.ts +1 -0
- package/lib/types/chrome.spec.d.ts +1 -0
- package/lib/types/elements/adw-about-dialog.d.ts +47 -8
- package/lib/types/elements/adw-action-row.d.ts +35 -0
- package/lib/types/elements/adw-avatar.d.ts +11 -0
- package/lib/types/elements/adw-bottom-sheet.d.ts +33 -4
- package/lib/types/elements/adw-button-content.d.ts +12 -0
- package/lib/types/elements/adw-button-row.d.ts +10 -1
- package/lib/types/elements/adw-carousel.d.ts +111 -8
- package/lib/types/elements/adw-checks.d.ts +57 -0
- package/lib/types/elements/adw-clamp.d.ts +4 -1
- package/lib/types/elements/adw-data-grid.d.ts +11 -31
- package/lib/types/elements/adw-drop-down.d.ts +17 -20
- package/lib/types/elements/adw-entry-row.d.ts +93 -3
- package/lib/types/elements/adw-expander-row.d.ts +7 -1
- package/lib/types/elements/adw-header-bar.d.ts +15 -0
- package/lib/types/elements/adw-icon.d.ts +25 -0
- package/lib/types/elements/adw-inline-view-switcher.d.ts +37 -11
- package/lib/types/elements/adw-menu-button.d.ts +6 -6
- package/lib/types/elements/adw-navigation-split-view.d.ts +6 -0
- package/lib/types/elements/adw-navigation-view.d.ts +63 -20
- package/lib/types/elements/adw-overlay-split-view.d.ts +38 -0
- package/lib/types/elements/adw-password-entry-row.d.ts +19 -10
- package/lib/types/elements/adw-popover.d.ts +58 -0
- package/lib/types/elements/adw-preferences-dialog.d.ts +57 -2
- package/lib/types/elements/adw-preferences-group.d.ts +31 -0
- package/lib/types/elements/adw-progress-bar.d.ts +38 -0
- package/lib/types/elements/adw-sidebar.d.ts +37 -5
- package/lib/types/elements/adw-split-button.d.ts +53 -7
- package/lib/types/elements/adw-switch-row.d.ts +11 -2
- package/lib/types/elements/adw-switch.d.ts +15 -0
- package/lib/types/elements/adw-tab-view.d.ts +129 -12
- package/lib/types/elements/adw-toolbar-view.d.ts +5 -0
- package/lib/types/elements/adw-view-stack.d.ts +27 -19
- package/lib/types/elements/adw-view-switcher-bar.d.ts +23 -7
- package/lib/types/elements/adw-view-switcher.d.ts +22 -11
- package/lib/types/elements/adw-window-title.d.ts +3 -1
- package/lib/types/elements/view-switcher-dom.d.ts +44 -0
- package/lib/types/entry-rows.spec.d.ts +1 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/navigation-view.spec.d.ts +1 -0
- package/lib/types/preferences-search.d.ts +20 -0
- package/lib/types/preferences.spec.d.ts +1 -0
- package/lib/types/split-button.spec.d.ts +1 -0
- package/lib/types/split-views.spec.d.ts +1 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/lib/types/tab-view.spec.d.ts +1 -0
- package/lib/types/view-stack.spec.d.ts +1 -0
- package/lib/types/view-switcher.spec.d.ts +1 -0
- package/package.json +6 -6
- package/scss/_banner.scss +13 -0
- package/scss/_bottom_sheet.scss +5 -6
- package/scss/_button.scss +3 -26
- package/scss/_button_content.scss +28 -0
- package/scss/_checks.scss +228 -0
- package/scss/_clamp.scss +9 -3
- package/scss/_data_grid.scss +15 -7
- package/scss/_drop_down.scss +12 -55
- package/scss/_expander_row.scss +5 -50
- package/scss/_icon.scss +51 -0
- package/scss/_icons.generated.scss +6 -0
- package/scss/_inline_view_switcher.scss +34 -0
- package/scss/_labels.scss +135 -0
- package/scss/_menu_button.scss +10 -70
- package/scss/_popover.scss +186 -0
- package/scss/_preferences.scss +29 -0
- package/scss/_preferences_dialog.scss +17 -0
- package/scss/_progress_bar.scss +161 -0
- package/scss/_reset.scss +18 -7
- package/scss/_spinner.scss +7 -3
- package/scss/_split_button.scss +6 -50
- package/scss/_switch.scss +90 -0
- package/scss/_switch_row.scss +6 -52
- package/scss/_tab_view.scss +64 -0
- package/scss/_theme.scss +10 -0
- package/scss/_toolbar_view.scss +74 -0
- package/scss/_variables.scss +34 -0
- package/scss/_view_switcher.scss +40 -0
- package/scss/_view_switcher_bar.scss +37 -0
- package/scss/_wrap_box.scss +56 -6
- package/scss/adwaita-skin.scss +23 -0
- package/src/adw-about-dialog.spec.ts +350 -0
- package/src/adw-action-rows.spec.ts +342 -0
- package/src/adw-avatar.spec.ts +139 -0
- package/src/adw-banner.spec.ts +152 -0
- package/src/adw-button-content.spec.ts +183 -0
- package/src/adw-button-row.spec.ts +12 -6
- package/src/adw-carousel.spec.ts +389 -0
- package/src/adw-checks.spec.ts +368 -0
- package/src/adw-drop-down.spec.ts +123 -0
- package/src/adw-header-bar.spec.ts +83 -0
- package/src/adw-icon.spec.ts +167 -0
- package/src/adw-progress-bar.spec.ts +173 -0
- package/src/adw-sidebar.spec.ts +332 -0
- package/src/adw-switch.spec.ts +242 -0
- package/src/adw-tab-view.spec.ts +12 -3
- package/src/adw-view-switcher-bar.spec.ts +61 -13
- package/src/adw-wrap-box.spec.ts +194 -0
- package/src/bottom-sheet.spec.ts +325 -0
- package/src/breakpoints.spec.ts +147 -0
- package/src/breakpoints.ts +67 -0
- package/src/chrome.spec.ts +301 -0
- package/src/elements/adw-about-dialog.ts +223 -163
- package/src/elements/adw-action-row.ts +120 -10
- package/src/elements/adw-avatar.ts +48 -54
- package/src/elements/adw-banner.ts +46 -10
- package/src/elements/adw-bottom-sheet.ts +145 -60
- package/src/elements/adw-button-content.ts +107 -33
- package/src/elements/adw-button-row.ts +61 -37
- package/src/elements/adw-button.ts +5 -7
- package/src/elements/adw-carousel.ts +467 -105
- package/src/elements/adw-checks.ts +299 -0
- package/src/elements/adw-clamp.ts +80 -10
- package/src/elements/adw-combo-row.ts +15 -7
- package/src/elements/adw-data-grid.ts +43 -91
- package/src/elements/adw-drop-down.ts +117 -128
- package/src/elements/adw-entry-row.ts +404 -36
- package/src/elements/adw-expander-row.ts +61 -29
- package/src/elements/adw-header-bar.ts +31 -6
- package/src/elements/adw-icon.ts +148 -0
- package/src/elements/adw-inline-view-switcher.ts +240 -129
- package/src/elements/adw-menu-button.ts +93 -70
- package/src/elements/adw-navigation-split-view.ts +48 -7
- package/src/elements/adw-navigation-view.ts +286 -148
- package/src/elements/adw-overlay-split-view.ts +164 -14
- package/src/elements/adw-password-entry-row.ts +111 -89
- package/src/elements/adw-popover.ts +283 -0
- package/src/elements/adw-preferences-dialog.ts +120 -21
- package/src/elements/adw-preferences-group.ts +128 -22
- package/src/elements/adw-progress-bar.ts +189 -0
- package/src/elements/adw-sidebar.ts +301 -142
- package/src/elements/adw-spin-row.ts +11 -5
- package/src/elements/adw-spinner.ts +23 -8
- package/src/elements/adw-split-button.ts +371 -92
- package/src/elements/adw-status-page.ts +9 -9
- package/src/elements/adw-switch-row.ts +100 -30
- package/src/elements/adw-switch.ts +129 -0
- package/src/elements/adw-tab-view.ts +682 -129
- package/src/elements/adw-toggle-group.ts +5 -7
- package/src/elements/adw-toolbar-view.ts +84 -21
- package/src/elements/adw-view-stack.ts +162 -85
- package/src/elements/adw-view-switcher-bar.ts +163 -81
- package/src/elements/adw-view-switcher.ts +231 -112
- package/src/elements/adw-window-title.ts +44 -11
- package/src/elements/adw-wrap-box.ts +131 -35
- package/src/elements/view-switcher-dom.ts +108 -0
- package/src/entry-rows.spec.ts +391 -0
- package/src/index.ts +23 -0
- package/src/navigation-view.spec.ts +435 -0
- package/src/preferences-search.ts +135 -0
- package/src/preferences.spec.ts +250 -0
- package/src/source-view/adw-source-view.ts +2 -5
- package/src/split-button.spec.ts +470 -0
- package/src/split-views.spec.ts +309 -0
- package/src/styles.generated.ts +1 -1
- package/src/tab-view.spec.ts +451 -0
- package/src/test.browser.mts +49 -0
- package/src/view-stack.spec.ts +272 -0
- package/src/view-switcher.spec.ts +446 -0
|
@@ -7,28 +7,111 @@
|
|
|
7
7
|
// line-spacing (px, default 0) — spacing between lines → CSS row-gap
|
|
8
8
|
// orientation ("horizontal" | "vertical", default "horizontal") — the main
|
|
9
9
|
// axis children are packed along
|
|
10
|
-
// align (0..1, default 0) —
|
|
11
|
-
// (
|
|
10
|
+
// align (0..1, default 0) — where the children sit ALONG the line
|
|
11
|
+
// (main axis); 0 = start, 0.5 = middle, 1 = end
|
|
12
12
|
// justify ("none" | "fill" | "spread", default "none") — whether/how
|
|
13
13
|
// each line is stretched to fill the widget
|
|
14
|
-
// justify-last-line (boolean) — also justify the last (
|
|
14
|
+
// justify-last-line (boolean) — also justify the last (final) line
|
|
15
15
|
// line-homogeneous (boolean) — make every line take the same amount of space
|
|
16
16
|
// pack-direction ("start-to-end" | "end-to-start", default "start-to-end") —
|
|
17
17
|
// direction children are packed within a line
|
|
18
18
|
// wrap-reverse (boolean) — reverse the wrap direction (lines wrap upwards)
|
|
19
19
|
// Events: notify::child-spacing, notify::line-spacing (CustomEvent, bubbles —
|
|
20
|
-
// mirrors GObject signal naming).
|
|
20
|
+
// mirrors GObject signal naming, including its "only on a real change" rule).
|
|
21
21
|
// Reference: refs/libadwaita/src/adw-wrap-box.c / adw-wrap-layout.c (Adw.WrapBox)
|
|
22
22
|
// Reference: refs/adwaita-web/adwaita-web/scss/_wrap_box.scss
|
|
23
23
|
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
24
24
|
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
/** `AdwJustifyMode` (adw-wrap-layout.c:74-83). */
|
|
27
|
+
type JustifyMode = 'none' | 'fill' | 'spread';
|
|
28
|
+
|
|
29
|
+
/** The three modes, for validating the attribute against the C enum. */
|
|
30
|
+
const JUSTIFY_MODES: readonly JustifyMode[] = ['none', 'fill', 'spread'];
|
|
31
|
+
|
|
32
|
+
/** What one line does with the space its children do not use. */
|
|
33
|
+
interface LineLayout {
|
|
34
|
+
/** The mode governing this line, after the last-line gate. */
|
|
35
|
+
justify: JustifyMode;
|
|
36
|
+
/** Whether the CHILDREN absorb the leftover (adw-wrap-layout.c:336-341). */
|
|
37
|
+
growChildren: boolean;
|
|
38
|
+
/** Whether the GAPS absorb it (adw-wrap-layout.c:338-339, :752-757). */
|
|
39
|
+
growGaps: boolean;
|
|
40
|
+
/** The main-axis offset factor for an un-justified line (adw-wrap-layout.c:717-725). */
|
|
41
|
+
align: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The line-layout decision, straight from the C.
|
|
46
|
+
*
|
|
47
|
+
* `lastLine` is the FINAL line, complete or not (`i == *n_lines - 1`,
|
|
48
|
+
* adw-wrap-layout.c:463-464), so a wrap box whose children all fit on one line
|
|
49
|
+
* has that line governed by `justify-last-line` rather than by `justify`.
|
|
50
|
+
*
|
|
51
|
+
* The conformance table this must agree with is
|
|
52
|
+
* `@gjsify/adwaita-core/conformance` → `WRAP_BOX_LINE_VECTORS`; the same rows
|
|
53
|
+
* are asserted against the NativeScript port, so the two cannot drift apart
|
|
54
|
+
* without a test naming the input.
|
|
55
|
+
*/
|
|
56
|
+
function resolveLine(
|
|
57
|
+
justify: JustifyMode,
|
|
58
|
+
justifyLastLine: boolean,
|
|
59
|
+
align: number,
|
|
60
|
+
lastLine: boolean,
|
|
61
|
+
childrenInLine: number,
|
|
62
|
+
): LineLayout {
|
|
63
|
+
// adw-wrap-layout.c:397-400 / :705-706 — the final line is only justified on
|
|
64
|
+
// request; otherwise it falls back to ADW_JUSTIFY_NONE and to `align`.
|
|
65
|
+
const effective: JustifyMode = lastLine && !justifyLastLine ? 'none' : justify;
|
|
66
|
+
if (effective === 'none') return { justify: 'none', growChildren: false, growGaps: false, align };
|
|
67
|
+
// adw-wrap-layout.c:338 — SPREAD keeps children at their minimum size and
|
|
68
|
+
// widens the gaps, but the branch is guarded by `n_children > 1`: a lone
|
|
69
|
+
// child has nothing to spread against and is stretched instead, which the
|
|
70
|
+
// property documentation states outright (adw-wrap-box.c:349-352).
|
|
71
|
+
const spreadsGaps = effective === 'spread' && childrenInLine > 1;
|
|
72
|
+
return { justify: effective, growChildren: !spreadsGaps, growGaps: spreadsGaps, align: 0 };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* `Adw.WrapBox:child-spacing` / `:line-spacing` normalisation.
|
|
77
|
+
*
|
|
78
|
+
* C clamps a negative value to 0 before it reaches the layout
|
|
79
|
+
* (adw-wrap-box.c:587-588, :927-928) — the property is declared with a minimum
|
|
80
|
+
* of 0, so without the clamp GObject would reject it. The non-numeric cases have
|
|
81
|
+
* no C counterpart (the property is an `int`); they resolve to the default so a
|
|
82
|
+
* typo cannot put `NaN` into a `column-gap`.
|
|
83
|
+
*/
|
|
84
|
+
function normalizeSpacing(raw: string | null): number {
|
|
85
|
+
const value = Number.parseFloat(raw ?? '');
|
|
86
|
+
if (!Number.isFinite(value) || value < 0) return 0;
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** `Adw.WrapBox:align` — `g_param_spec_float (…, 0, 1, 0, …)`, adw-wrap-box.c:335-337. */
|
|
91
|
+
function normalizeAlign(raw: string | null): number {
|
|
92
|
+
const value = Number.parseFloat(raw ?? '');
|
|
93
|
+
if (!Number.isFinite(value)) return 0;
|
|
94
|
+
return Math.min(1, Math.max(0, value));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** An out-of-range enum value leaves a GObject property at its default. */
|
|
98
|
+
function normalizeJustify(raw: string | null): JustifyMode {
|
|
99
|
+
return JUSTIFY_MODES.includes(raw as JustifyMode) ? (raw as JustifyMode) : 'none';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* `align` as a `justify-content` keyword.
|
|
104
|
+
*
|
|
105
|
+
* C offsets the whole line block by `roundf (length_delta * align)` — a
|
|
106
|
+
* continuum. Flexbox has three main-axis positions, so the nearest one is taken;
|
|
107
|
+
* that is the renderer's approximation, not libadwaita's rule, which is why it
|
|
108
|
+
* lives here and not in the conformance table.
|
|
109
|
+
*/
|
|
110
|
+
function alignToJustifyContent(align: number): string {
|
|
111
|
+
if (align < 0.25) return 'flex-start';
|
|
112
|
+
if (align < 0.75) return 'center';
|
|
113
|
+
return 'flex-end';
|
|
114
|
+
}
|
|
32
115
|
|
|
33
116
|
export class AdwWrapBox extends HTMLElement {
|
|
34
117
|
private _initialized = false;
|
|
@@ -49,7 +132,7 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
49
132
|
|
|
50
133
|
/** Spacing between children on the same line, in px (CSS column-gap). */
|
|
51
134
|
get childSpacing(): number {
|
|
52
|
-
return
|
|
135
|
+
return normalizeSpacing(this.getAttribute('child-spacing'));
|
|
53
136
|
}
|
|
54
137
|
|
|
55
138
|
set childSpacing(value: number) {
|
|
@@ -58,7 +141,7 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
58
141
|
|
|
59
142
|
/** Spacing between lines, in px (CSS row-gap). */
|
|
60
143
|
get lineSpacing(): number {
|
|
61
|
-
return
|
|
144
|
+
return normalizeSpacing(this.getAttribute('line-spacing'));
|
|
62
145
|
}
|
|
63
146
|
|
|
64
147
|
set lineSpacing(value: number) {
|
|
@@ -74,20 +157,20 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
74
157
|
attributeChangedCallback(name: string, old: string | null, value: string | null) {
|
|
75
158
|
if (!this._initialized) return;
|
|
76
159
|
this._sync();
|
|
77
|
-
|
|
160
|
+
// C compares AFTER normalising and returns early when nothing changed
|
|
161
|
+
// (adw-wrap-box.c:592-593), so `child-spacing="-5"` on a box already at 0
|
|
162
|
+
// notifies nobody.
|
|
78
163
|
if (name === 'child-spacing') {
|
|
164
|
+
const next = normalizeSpacing(value);
|
|
165
|
+
if (next === normalizeSpacing(old)) return;
|
|
79
166
|
this.dispatchEvent(
|
|
80
|
-
new CustomEvent('notify::child-spacing', {
|
|
81
|
-
bubbles: true,
|
|
82
|
-
detail: { childSpacing: this.childSpacing },
|
|
83
|
-
}),
|
|
167
|
+
new CustomEvent('notify::child-spacing', { bubbles: true, detail: { childSpacing: next } }),
|
|
84
168
|
);
|
|
85
169
|
} else if (name === 'line-spacing') {
|
|
170
|
+
const next = normalizeSpacing(value);
|
|
171
|
+
if (next === normalizeSpacing(old)) return;
|
|
86
172
|
this.dispatchEvent(
|
|
87
|
-
new CustomEvent('notify::line-spacing', {
|
|
88
|
-
bubbles: true,
|
|
89
|
-
detail: { lineSpacing: this.lineSpacing },
|
|
90
|
-
}),
|
|
173
|
+
new CustomEvent('notify::line-spacing', { bubbles: true, detail: { lineSpacing: next } }),
|
|
91
174
|
);
|
|
92
175
|
}
|
|
93
176
|
}
|
|
@@ -107,7 +190,8 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
107
190
|
// child-spacing is along the line (main axis), line-spacing is between
|
|
108
191
|
// lines (cross axis). For a horizontal box that maps to column-gap /
|
|
109
192
|
// row-gap respectively; the mapping flips for a vertical box.
|
|
110
|
-
const
|
|
193
|
+
const childSpacing = this.childSpacing;
|
|
194
|
+
const childGap = `${childSpacing}px`;
|
|
111
195
|
const lineGap = `${this.lineSpacing}px`;
|
|
112
196
|
if (vertical) {
|
|
113
197
|
style.rowGap = childGap;
|
|
@@ -116,19 +200,31 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
116
200
|
style.columnGap = childGap;
|
|
117
201
|
style.rowGap = lineGap;
|
|
118
202
|
}
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
203
|
+
// Read back by the last-line filler, which has to cancel exactly one
|
|
204
|
+
// main-axis gap so it can never push a full line into a new one.
|
|
205
|
+
style.setProperty('--adw-wrap-box-child-spacing', childGap);
|
|
206
|
+
|
|
207
|
+
const justify = normalizeJustify(this.getAttribute('justify'));
|
|
208
|
+
const justifyLastLine = this.hasAttribute('justify-last-line');
|
|
209
|
+
const align = normalizeAlign(this.getAttribute('align'));
|
|
210
|
+
|
|
211
|
+
// A flex container has ONE `justify-content` and applies it to every
|
|
212
|
+
// line, so it carries the COMPLETE-line rule; the final-line rule is
|
|
213
|
+
// published beside it for the stylesheet, which reaches that line through
|
|
214
|
+
// the only two selectors CSS offers — `:only-child` (a box with one child
|
|
215
|
+
// has one line, and it is the last) and the generated `::after` filler.
|
|
216
|
+
// The pair is deliberately never collapsed into one attribute: flexbox
|
|
217
|
+
// cannot express "every line but the last", and pretending otherwise is
|
|
218
|
+
// what made `justify-last-line` a no-op in the first place.
|
|
219
|
+
const line = resolveLine(justify, justifyLastLine, align, false, 2);
|
|
220
|
+
const lastLine = resolveLine(justify, justifyLastLine, align, true, 2);
|
|
221
|
+
this.dataset.lineJustify = line.justify;
|
|
222
|
+
this.dataset.lastLineJustify = lastLine.justify;
|
|
223
|
+
|
|
224
|
+
// SPREAD widens the gaps; FILL grows the children (stylesheet) and leaves
|
|
225
|
+
// the gaps alone; NONE offsets the whole line block by `align` — along
|
|
226
|
+
// the MAIN axis, never the cross one.
|
|
227
|
+
style.justifyContent = line.growGaps ? 'space-between' : alignToJustifyContent(line.align);
|
|
132
228
|
|
|
133
229
|
// line-homogeneous makes every line take the same amount of space, which
|
|
134
230
|
// flexbox approximates by stretching the lines across the cross axis.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// The DOM half of the view-switcher family — what `@gjsify/adwaita-core` cannot
|
|
2
|
+
// decide because it is genuinely per-renderer.
|
|
3
|
+
//
|
|
4
|
+
// Everything that decides WHAT a switcher shows (the button-visibility rule, the
|
|
5
|
+
// `image-missing` fallback, the badge label + screen-reader description, the
|
|
6
|
+
// mnemonic-stripped label, the tooltip, the reveal gate, the two index spaces)
|
|
7
|
+
// lives in `@gjsify/adwaita-core` and is pinned by the conformance vectors.
|
|
8
|
+
// What is left, and lives here, is how a derived model becomes nodes: an icon
|
|
9
|
+
// NAME turned into a CSS mask class, an indicator span, and a `setTimeout`
|
|
10
|
+
// wrapped in the scheduler seam the core takes for the drag-hover dwell.
|
|
11
|
+
//
|
|
12
|
+
// Shared by all three switcher elements because it was three copies before:
|
|
13
|
+
// `<adw-view-switcher>`, `<adw-inline-view-switcher>` and
|
|
14
|
+
// `<adw-view-switcher-bar>` each built their own icon span and their own page
|
|
15
|
+
// parsing, and the copies had already drifted (a titleless page rendered `''` in
|
|
16
|
+
// one and `page-<index>` in another).
|
|
17
|
+
//
|
|
18
|
+
// Reference: refs/libadwaita/src/adw-view-switcher.c
|
|
19
|
+
// Reference: refs/libadwaita/src/adw-indicator-bin.c
|
|
20
|
+
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
21
|
+
// Modifications: Implemented for @gjsify/adwaita-web Web Components.
|
|
22
|
+
|
|
23
|
+
import { viewSwitcherIconName } from '@gjsify/adwaita-core';
|
|
24
|
+
import type { AdwViewSwitcherPageInit, ViewSwitcherScheduler, ViewSwitcherTimerHandle } from '@gjsify/adwaita-core';
|
|
25
|
+
|
|
26
|
+
import { type AdwIcon, createAdwIcon } from './adw-icon.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The browser's timer behind the core's scheduler seam.
|
|
30
|
+
*
|
|
31
|
+
* One shared instance rather than one per element: it holds no state, and the
|
|
32
|
+
* seam exists so the CORE stays free of a global timer, not so each element
|
|
33
|
+
* invents its own.
|
|
34
|
+
*/
|
|
35
|
+
export const domViewSwitcherScheduler: ViewSwitcherScheduler = {
|
|
36
|
+
schedule(callback: () => void, ms: number): ViewSwitcherTimerHandle {
|
|
37
|
+
return setTimeout(callback, ms);
|
|
38
|
+
},
|
|
39
|
+
cancel(handle: ViewSwitcherTimerHandle): void {
|
|
40
|
+
clearTimeout(handle as ReturnType<typeof setTimeout>);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Build a switcher button's icon node, carrying its own position class.
|
|
46
|
+
*
|
|
47
|
+
* The core resolves NULL/empty to `image-missing` (which the stylesheet carries
|
|
48
|
+
* a real glyph for); the `-symbolic` strip and the CSS-token guard are
|
|
49
|
+
* `normalizeIconName`'s, applied by `<adw-icon>` — that strip is this package's
|
|
50
|
+
* own mask-class convention and has no counterpart in C, where the name reaches
|
|
51
|
+
* `GtkImage` untouched.
|
|
52
|
+
*/
|
|
53
|
+
export function createSwitcherIcon(iconName: string, extra: string): AdwIcon {
|
|
54
|
+
return createAdwIcon(viewSwitcherIconName(iconName), extra);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Repaint an existing switcher icon from a page's declared name. */
|
|
58
|
+
export function applySwitcherIcon(icon: AdwIcon, iconName: string): void {
|
|
59
|
+
icon.iconName = viewSwitcherIconName(iconName);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Read a declared page element into the core's page init.
|
|
64
|
+
*
|
|
65
|
+
* `getAttribute` returns `null` for an absent attribute, which is EXACTLY C's
|
|
66
|
+
* NULL — so the values are passed through unchanged rather than defaulted to
|
|
67
|
+
* `''`. That `?? ''` is what made the button-visibility rule unimplementable in
|
|
68
|
+
* the old code: once an absent title has become the empty string, "the page has
|
|
69
|
+
* no title" is no longer expressible.
|
|
70
|
+
*/
|
|
71
|
+
export function readSwitcherPage(element: Element): AdwViewSwitcherPageInit {
|
|
72
|
+
const badge = Number.parseInt(element.getAttribute('badge-number') ?? '', 10);
|
|
73
|
+
return {
|
|
74
|
+
// A page with no `name` is the page named '' — the same choice
|
|
75
|
+
// `<adw-view-stack>` made, and for the same reason: C stores the name
|
|
76
|
+
// verbatim (adw-view-stack.c:1170) and an invented `page-<index>` is
|
|
77
|
+
// addressable by a name the author never wrote.
|
|
78
|
+
name: element.getAttribute('name') ?? '',
|
|
79
|
+
title: element.getAttribute('title'),
|
|
80
|
+
iconName: element.getAttribute('icon-name'),
|
|
81
|
+
// `hidden` is the DOM spelling of AdwViewStackPage:visible.
|
|
82
|
+
visible: !element.hasAttribute('hidden'),
|
|
83
|
+
useUnderline: element.hasAttribute('use-underline'),
|
|
84
|
+
badgeNumber: Number.isNaN(badge) ? 0 : badge,
|
|
85
|
+
needsAttention: element.hasAttribute('needs-attention'),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Paint `AdwIndicatorBin`'s badge/dot onto a span: the badge text when there is
|
|
91
|
+
* one, a bare dot when only `needs-attention` is set, nothing otherwise
|
|
92
|
+
* (adw-indicator-bin.c:58-68 + the `.needs-attention` style class).
|
|
93
|
+
*/
|
|
94
|
+
export function applyIndicator(indicator: HTMLElement, badgeLabel: string, needsAttention: boolean): void {
|
|
95
|
+
indicator.textContent = badgeLabel;
|
|
96
|
+
indicator.classList.toggle('needs-attention', needsAttention && badgeLabel.length === 0);
|
|
97
|
+
indicator.hidden = badgeLabel.length === 0 && !needsAttention;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Mirror the derived screen-reader description onto the element, REMOVING the
|
|
102
|
+
* attribute when there is none — `update_description_cb` resets the accessible
|
|
103
|
+
* property rather than setting it to `""` (adw-view-switcher-button.c:104-113).
|
|
104
|
+
*/
|
|
105
|
+
export function applyDescription(element: HTMLElement, description: string): void {
|
|
106
|
+
if (description) element.setAttribute('aria-description', description);
|
|
107
|
+
else element.removeAttribute('aria-description');
|
|
108
|
+
}
|