@gjsify/adwaita-web 0.32.0 → 0.33.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 +72 -50
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/elements/adw-combo-row.d.ts +10 -0
- package/lib/types/elements/adw-inline-view-switcher.d.ts +37 -1
- package/lib/types/elements/adw-navigation-split-view.d.ts +42 -0
- package/lib/types/elements/adw-overlay-split-view.d.ts +56 -0
- package/lib/types/elements/adw-spinner.d.ts +23 -0
- package/lib/types/elements/adw-view-stack.d.ts +12 -0
- package/lib/types/elements/adw-view-switcher-bar.d.ts +7 -5
- package/lib/types/elements/adw-view-switcher.d.ts +55 -3
- package/lib/types/elements/adw-wrap-box.d.ts +58 -3
- package/lib/types/styles.generated.d.ts +1 -1
- package/package.json +6 -6
- package/scss/_combo_row.scss +19 -0
- package/scss/_navigation_split_view.scss +47 -8
- package/scss/_overlay_split_view.scss +117 -32
- package/scss/_spinner.scss +35 -21
- package/scss/_tab_view.scss +12 -13
- package/scss/_wrap_box.scss +9 -0
- package/src/adw-avatar.spec.ts +37 -0
- package/src/adw-button-content.spec.ts +24 -0
- package/src/adw-row-state.spec.ts +49 -0
- package/src/adw-wrap-box.spec.ts +148 -1
- package/src/chrome.spec.ts +111 -12
- package/src/elements/adw-action-row.ts +11 -1
- package/src/elements/adw-combo-row.ts +17 -0
- package/src/elements/adw-inline-view-switcher.ts +91 -8
- package/src/elements/adw-navigation-split-view.ts +179 -14
- package/src/elements/adw-overlay-split-view.ts +378 -20
- package/src/elements/adw-spinner.ts +165 -21
- package/src/elements/adw-tab-view.ts +20 -2
- package/src/elements/adw-view-stack.ts +21 -0
- package/src/elements/adw-view-switcher-bar.ts +13 -5
- package/src/elements/adw-view-switcher.ts +103 -11
- package/src/elements/adw-wrap-box.ts +290 -135
- package/src/split-views.spec.ts +586 -2
- package/src/styles.generated.ts +1 -1
- package/src/view-switcher.spec.ts +219 -0
|
@@ -1,103 +1,75 @@
|
|
|
1
1
|
// <adw-wrap-box> — A box-like container that lays its children out in a line and
|
|
2
|
-
// wraps them onto new lines when they run out of room (the web analog of
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
// wrap-reverse
|
|
19
|
-
//
|
|
20
|
-
//
|
|
2
|
+
// wraps them onto new lines when they run out of room (the web analog of flexbox
|
|
3
|
+
// `flex-wrap: wrap` with a gap). Mirrors Adw.WrapBox.
|
|
4
|
+
//
|
|
5
|
+
// Attributes — all fourteen of the widget's properties, each with a
|
|
6
|
+
// `notify::<property>` (adw-wrap-box.c:284-497). The element used to carry nine
|
|
7
|
+
// attributes and notify for two, so a consumer binding to any of the other
|
|
8
|
+
// twelve was listening to a signal that could not fire.
|
|
9
|
+
//
|
|
10
|
+
// child-spacing / line-spacing (int >= 0, default 0) -> column-gap / row-gap
|
|
11
|
+
// child-spacing-unit / line-spacing-unit ("px" | "pt" | "sp", default "px")
|
|
12
|
+
// orientation ("horizontal" | "vertical", default "horizontal")
|
|
13
|
+
// pack-direction ("start-to-end" | "end-to-start", default "start-to-end")
|
|
14
|
+
// align (0..1, default 0) — MAIN-axis offset of the whole line block
|
|
15
|
+
// justify ("none" | "fill" | "spread", default "none")
|
|
16
|
+
// justify-last-line (boolean)
|
|
17
|
+
// line-homogeneous (boolean)
|
|
18
|
+
// wrap-reverse (boolean)
|
|
19
|
+
// wrap-policy ("minimum" | "natural", default "natural")
|
|
20
|
+
// natural-line-length (int >= -1, default -1 = unset) + -unit
|
|
21
|
+
//
|
|
22
|
+
// The property CONTRACT — the normalisers and the justify/align/last-line
|
|
23
|
+
// decision — is `@gjsify/adwaita-core`'s `wrap-box.ts`, held to
|
|
24
|
+
// `WRAP_BOX_LINE_VECTORS` and friends, which the NativeScript suite drives too.
|
|
25
|
+
// This element used to carry its own copy of all of it.
|
|
26
|
+
//
|
|
21
27
|
// Reference: refs/libadwaita/src/adw-wrap-box.c / adw-wrap-layout.c (Adw.WrapBox)
|
|
22
28
|
// Reference: refs/adwaita-web/adwaita-web/scss/_wrap_box.scss
|
|
23
29
|
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
24
30
|
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
}
|
|
32
|
+
import {
|
|
33
|
+
ADW_WRAP_BOX_NATURAL_LINE_LENGTH_UNSET,
|
|
34
|
+
normalizeNaturalLineLength,
|
|
35
|
+
normalizeWrapBoxAlign,
|
|
36
|
+
normalizeWrapBoxJustify,
|
|
37
|
+
normalizeWrapBoxLengthUnit,
|
|
38
|
+
normalizeWrapBoxPackDirection,
|
|
39
|
+
normalizeWrapBoxSpacing,
|
|
40
|
+
normalizeWrapPolicy,
|
|
41
|
+
resolveWrapBoxChildOrder,
|
|
42
|
+
resolveWrapBoxLine,
|
|
43
|
+
wrapBoxLengthToPx,
|
|
44
|
+
wrapPolicyFlexShrink,
|
|
45
|
+
type AdwLengthUnit,
|
|
46
|
+
} from '@gjsify/adwaita-core';
|
|
74
47
|
|
|
75
48
|
/**
|
|
76
|
-
*
|
|
49
|
+
* The attributes that carry a property, in the order the C installs them.
|
|
77
50
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
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`.
|
|
51
|
+
* Doubles as the `notify::` roster: every entry gets an event on a real change,
|
|
52
|
+
* so adding an attribute without its notification is not expressible here.
|
|
83
53
|
*/
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
54
|
+
const PROPERTY_ATTRIBUTES = [
|
|
55
|
+
'child-spacing',
|
|
56
|
+
'child-spacing-unit',
|
|
57
|
+
'pack-direction',
|
|
58
|
+
'align',
|
|
59
|
+
'justify',
|
|
60
|
+
'justify-last-line',
|
|
61
|
+
'line-spacing',
|
|
62
|
+
'line-spacing-unit',
|
|
63
|
+
'line-homogeneous',
|
|
64
|
+
'natural-line-length',
|
|
65
|
+
'natural-line-length-unit',
|
|
66
|
+
'wrap-reverse',
|
|
67
|
+
'wrap-policy',
|
|
68
|
+
'orientation',
|
|
69
|
+
] as const;
|
|
96
70
|
|
|
97
|
-
/**
|
|
98
|
-
|
|
99
|
-
return JUSTIFY_MODES.includes(raw as JustifyMode) ? (raw as JustifyMode) : 'none';
|
|
100
|
-
}
|
|
71
|
+
/** One attribute's normalised value, for the "did it really change" comparison. */
|
|
72
|
+
type PropertyValue = string | number | boolean;
|
|
101
73
|
|
|
102
74
|
/**
|
|
103
75
|
* `align` as a `justify-content` keyword.
|
|
@@ -117,37 +89,186 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
117
89
|
private _initialized = false;
|
|
118
90
|
|
|
119
91
|
static get observedAttributes() {
|
|
120
|
-
return [
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
'justify-last-line',
|
|
127
|
-
'line-homogeneous',
|
|
128
|
-
'pack-direction',
|
|
129
|
-
'wrap-reverse',
|
|
130
|
-
];
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Spacing between children on the same line, in px (CSS column-gap). */
|
|
92
|
+
return [...PROPERTY_ATTRIBUTES];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// --- properties ---
|
|
96
|
+
|
|
97
|
+
/** Spacing between children on the same line, in `child-spacing-unit`. */
|
|
134
98
|
get childSpacing(): number {
|
|
135
|
-
return
|
|
99
|
+
return normalizeWrapBoxSpacing(this.getAttribute('child-spacing'));
|
|
136
100
|
}
|
|
137
101
|
|
|
138
102
|
set childSpacing(value: number) {
|
|
139
103
|
this.setAttribute('child-spacing', String(value));
|
|
140
104
|
}
|
|
141
105
|
|
|
142
|
-
/**
|
|
106
|
+
/** The unit `child-spacing` is written in. Defaults to `px`, as in C. */
|
|
107
|
+
get childSpacingUnit(): AdwLengthUnit {
|
|
108
|
+
return normalizeWrapBoxLengthUnit(this.getAttribute('child-spacing-unit'));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
set childSpacingUnit(value: AdwLengthUnit) {
|
|
112
|
+
this.setAttribute('child-spacing-unit', value);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Spacing between lines, in `line-spacing-unit`. */
|
|
143
116
|
get lineSpacing(): number {
|
|
144
|
-
return
|
|
117
|
+
return normalizeWrapBoxSpacing(this.getAttribute('line-spacing'));
|
|
145
118
|
}
|
|
146
119
|
|
|
147
120
|
set lineSpacing(value: number) {
|
|
148
121
|
this.setAttribute('line-spacing', String(value));
|
|
149
122
|
}
|
|
150
123
|
|
|
124
|
+
/** The unit `line-spacing` is written in. Defaults to `px`, as in C. */
|
|
125
|
+
get lineSpacingUnit(): AdwLengthUnit {
|
|
126
|
+
return normalizeWrapBoxLengthUnit(this.getAttribute('line-spacing-unit'));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
set lineSpacingUnit(value: AdwLengthUnit) {
|
|
130
|
+
this.setAttribute('line-spacing-unit', value);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Where the children sit ALONG the line (main axis): 0 start, 0.5 middle, 1 end. */
|
|
134
|
+
get align(): number {
|
|
135
|
+
return normalizeWrapBoxAlign(this.getAttribute('align'));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
set align(value: number) {
|
|
139
|
+
this.setAttribute('align', String(value));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Whether and how each line is stretched to fill the widget. */
|
|
143
|
+
get justify(): 'none' | 'fill' | 'spread' {
|
|
144
|
+
return normalizeWrapBoxJustify(this.getAttribute('justify'));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
set justify(value: 'none' | 'fill' | 'spread') {
|
|
148
|
+
this.setAttribute('justify', value);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Whether the FINAL line is justified too. Default false, as in C. */
|
|
152
|
+
get justifyLastLine(): boolean {
|
|
153
|
+
return this.hasAttribute('justify-last-line');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
set justifyLastLine(value: boolean) {
|
|
157
|
+
this.toggleAttribute('justify-last-line', !!value);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Whether an overflowing line squeezes its children or lets them spill. */
|
|
161
|
+
get wrapPolicy(): 'minimum' | 'natural' {
|
|
162
|
+
return normalizeWrapPolicy(this.getAttribute('wrap-policy'));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
set wrapPolicy(value: 'minimum' | 'natural') {
|
|
166
|
+
this.setAttribute('wrap-policy', value);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** The direction children are packed in each line. */
|
|
170
|
+
get packDirection(): 'start-to-end' | 'end-to-start' {
|
|
171
|
+
return normalizeWrapBoxPackDirection(this.getAttribute('pack-direction'));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
set packDirection(value: 'start-to-end' | 'end-to-start') {
|
|
175
|
+
this.setAttribute('pack-direction', value);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Whether lines wrap upwards (horizontal) / towards the start (vertical). */
|
|
179
|
+
get wrapReverse(): boolean {
|
|
180
|
+
return this.hasAttribute('wrap-reverse');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
set wrapReverse(value: boolean) {
|
|
184
|
+
this.toggleAttribute('wrap-reverse', !!value);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Whether every line takes the same amount of space. */
|
|
188
|
+
get lineHomogeneous(): boolean {
|
|
189
|
+
return this.hasAttribute('line-homogeneous');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
set lineHomogeneous(value: boolean) {
|
|
193
|
+
this.toggleAttribute('line-homogeneous', !!value);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** The natural line length in `natural-line-length-unit`, or `-1` when unset. */
|
|
197
|
+
get naturalLineLength(): number {
|
|
198
|
+
return normalizeNaturalLineLength(this.getAttribute('natural-line-length'));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
set naturalLineLength(value: number) {
|
|
202
|
+
this.setAttribute('natural-line-length', String(value));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** The unit `natural-line-length` is written in. Defaults to `px`, as in C. */
|
|
206
|
+
get naturalLineLengthUnit(): AdwLengthUnit {
|
|
207
|
+
return normalizeWrapBoxLengthUnit(this.getAttribute('natural-line-length-unit'));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
set naturalLineLengthUnit(value: AdwLengthUnit) {
|
|
211
|
+
this.setAttribute('natural-line-length-unit', value);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** The axis children are packed along. */
|
|
215
|
+
get orientation(): 'horizontal' | 'vertical' {
|
|
216
|
+
return this.getAttribute('orientation') === 'vertical' ? 'vertical' : 'horizontal';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
set orientation(value: 'horizontal' | 'vertical') {
|
|
220
|
+
this.setAttribute('orientation', value);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// --- child list (adw_wrap_box_insert_child_after / reorder / remove_all) ---
|
|
224
|
+
//
|
|
225
|
+
// `adw_wrap_box_append`, `_prepend` and `_remove` are deliberately NOT
|
|
226
|
+
// redeclared: `ParentNode.append` / `.prepend` and `Node.removeChild` are
|
|
227
|
+
// those three, with the same semantics, and shadowing them would give this
|
|
228
|
+
// element two spellings of one operation. Only the three the DOM has no
|
|
229
|
+
// counterpart for are added.
|
|
230
|
+
|
|
231
|
+
/** The element children, which are what the layout actually lays out. */
|
|
232
|
+
private get _children(): Element[] {
|
|
233
|
+
return [...this.children];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* `adw_wrap_box_insert_child_after` (adw-wrap-box.c:1283-1300).
|
|
238
|
+
*
|
|
239
|
+
* A NULL/absent `sibling` inserts at the FIRST position, not the last —
|
|
240
|
+
* `gtk_widget_insert_after`'s documented rule, pinned by
|
|
241
|
+
* `WRAP_BOX_CHILD_ORDER_VECTORS`. Returns whether the insert happened; a
|
|
242
|
+
* refusal is where C would have hit a `g_return_if_fail`.
|
|
243
|
+
*/
|
|
244
|
+
insertChildAfter(child: Element, sibling: Element | null = null): boolean {
|
|
245
|
+
return this._applyOrder('insert-after', child, sibling);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** `adw_wrap_box_reorder_child_after` (adw-wrap-box.c:1315-1332). Same NULL rule. */
|
|
249
|
+
reorderChildAfter(child: Element, sibling: Element | null = null): boolean {
|
|
250
|
+
return this._applyOrder('reorder-after', child, sibling);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** `adw_wrap_box_remove_all` (adw-wrap-box.c:1406-1414). */
|
|
254
|
+
removeAll(): void {
|
|
255
|
+
for (const child of this._children) this.removeChild(child);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private _applyOrder(op: 'insert-after' | 'reorder-after', child: Element, sibling: Element | null): boolean {
|
|
259
|
+
const next = resolveWrapBoxChildOrder({ children: this._children, child, sibling, op });
|
|
260
|
+
if (next === null) return false;
|
|
261
|
+
// Move exactly the one node: `insertBefore` relocates a node already in
|
|
262
|
+
// the tree, and a null reference node appends. Re-appending the whole
|
|
263
|
+
// resolved list would reach the same order while detaching and
|
|
264
|
+
// re-attaching every sibling, which resets focus and any element state.
|
|
265
|
+
const at = next.indexOf(child);
|
|
266
|
+
this.insertBefore(child, next[at + 1] ?? null);
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// --- lifecycle ---
|
|
271
|
+
|
|
151
272
|
connectedCallback() {
|
|
152
273
|
if (this._initialized) return;
|
|
153
274
|
this._initialized = true;
|
|
@@ -159,40 +280,56 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
159
280
|
this._sync();
|
|
160
281
|
// C compares AFTER normalising and returns early when nothing changed
|
|
161
282
|
// (adw-wrap-box.c:592-593), so `child-spacing="-5"` on a box already at 0
|
|
162
|
-
// notifies nobody.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
283
|
+
// notifies nobody. The same gate applies to every property, not just the
|
|
284
|
+
// two spacings this element used to special-case.
|
|
285
|
+
const next = this._normalized(name, value);
|
|
286
|
+
if (next === this._normalized(name, old)) return;
|
|
287
|
+
this.dispatchEvent(new CustomEvent(`notify::${name}`, { bubbles: true, detail: { [name]: next } }));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** One attribute's value as the widget stores it — the notify comparison key. */
|
|
291
|
+
private _normalized(name: string, raw: string | null): PropertyValue {
|
|
292
|
+
switch (name) {
|
|
293
|
+
case 'child-spacing':
|
|
294
|
+
case 'line-spacing':
|
|
295
|
+
return normalizeWrapBoxSpacing(raw);
|
|
296
|
+
case 'child-spacing-unit':
|
|
297
|
+
case 'line-spacing-unit':
|
|
298
|
+
case 'natural-line-length-unit':
|
|
299
|
+
return normalizeWrapBoxLengthUnit(raw);
|
|
300
|
+
case 'align':
|
|
301
|
+
return normalizeWrapBoxAlign(raw);
|
|
302
|
+
case 'justify':
|
|
303
|
+
return normalizeWrapBoxJustify(raw);
|
|
304
|
+
case 'wrap-policy':
|
|
305
|
+
return normalizeWrapPolicy(raw);
|
|
306
|
+
case 'pack-direction':
|
|
307
|
+
return normalizeWrapBoxPackDirection(raw);
|
|
308
|
+
case 'natural-line-length':
|
|
309
|
+
return normalizeNaturalLineLength(raw);
|
|
310
|
+
case 'orientation':
|
|
311
|
+
return raw === 'vertical' ? 'vertical' : 'horizontal';
|
|
312
|
+
default:
|
|
313
|
+
// The three booleans: a present attribute is true whatever it says.
|
|
314
|
+
return raw !== null;
|
|
175
315
|
}
|
|
176
316
|
}
|
|
177
317
|
|
|
178
318
|
private _sync() {
|
|
179
319
|
const style = this.style;
|
|
180
|
-
const vertical = this.
|
|
181
|
-
const reverseWrap = this.hasAttribute('wrap-reverse');
|
|
182
|
-
const packEndToStart = this.getAttribute('pack-direction') === 'end-to-start';
|
|
320
|
+
const vertical = this.orientation === 'vertical';
|
|
183
321
|
|
|
184
322
|
// Main axis is the packing direction; lines wrap along the cross axis.
|
|
185
323
|
const direction = vertical ? 'column' : 'row';
|
|
186
|
-
|
|
187
|
-
style.
|
|
188
|
-
style.flexWrap = reverseWrap ? 'wrap-reverse' : 'wrap';
|
|
324
|
+
style.flexDirection = this.packDirection === 'end-to-start' ? `${direction}-reverse` : direction;
|
|
325
|
+
style.flexWrap = this.wrapReverse ? 'wrap-reverse' : 'wrap';
|
|
189
326
|
|
|
190
327
|
// child-spacing is along the line (main axis), line-spacing is between
|
|
191
328
|
// lines (cross axis). For a horizontal box that maps to column-gap /
|
|
192
|
-
// row-gap respectively; the mapping flips for a vertical box.
|
|
193
|
-
|
|
194
|
-
const childGap = `${childSpacing}px`;
|
|
195
|
-
const lineGap = `${this.lineSpacing}px`;
|
|
329
|
+
// row-gap respectively; the mapping flips for a vertical box. Both are
|
|
330
|
+
// resolved through their OWN unit first, which is why they can disagree.
|
|
331
|
+
const childGap = `${wrapBoxLengthToPx(this.childSpacing, this.childSpacingUnit)}px`;
|
|
332
|
+
const lineGap = `${wrapBoxLengthToPx(this.lineSpacing, this.lineSpacingUnit)}px`;
|
|
196
333
|
if (vertical) {
|
|
197
334
|
style.rowGap = childGap;
|
|
198
335
|
style.columnGap = lineGap;
|
|
@@ -204,9 +341,9 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
204
341
|
// main-axis gap so it can never push a full line into a new one.
|
|
205
342
|
style.setProperty('--adw-wrap-box-child-spacing', childGap);
|
|
206
343
|
|
|
207
|
-
const justify =
|
|
208
|
-
const justifyLastLine = this.
|
|
209
|
-
const align =
|
|
344
|
+
const justify = this.justify;
|
|
345
|
+
const justifyLastLine = this.justifyLastLine;
|
|
346
|
+
const align = this.align;
|
|
210
347
|
|
|
211
348
|
// A flex container has ONE `justify-content` and applies it to every
|
|
212
349
|
// line, so it carries the COMPLETE-line rule; the final-line rule is
|
|
@@ -216,8 +353,8 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
216
353
|
// The pair is deliberately never collapsed into one attribute: flexbox
|
|
217
354
|
// cannot express "every line but the last", and pretending otherwise is
|
|
218
355
|
// what made `justify-last-line` a no-op in the first place.
|
|
219
|
-
const line =
|
|
220
|
-
const lastLine =
|
|
356
|
+
const line = resolveWrapBoxLine({ justify, justifyLastLine, align, lastLine: false, childrenInLine: 2 });
|
|
357
|
+
const lastLine = resolveWrapBoxLine({ justify, justifyLastLine, align, lastLine: true, childrenInLine: 2 });
|
|
221
358
|
this.dataset.lineJustify = line.justify;
|
|
222
359
|
this.dataset.lastLineJustify = lastLine.justify;
|
|
223
360
|
|
|
@@ -228,7 +365,25 @@ export class AdwWrapBox extends HTMLElement {
|
|
|
228
365
|
|
|
229
366
|
// line-homogeneous makes every line take the same amount of space, which
|
|
230
367
|
// flexbox approximates by stretching the lines across the cross axis.
|
|
231
|
-
style.alignContent = this.
|
|
368
|
+
style.alignContent = this.lineHomogeneous ? 'stretch' : 'flex-start';
|
|
369
|
+
|
|
370
|
+
// `wrap-policy` decides whether an overflowing line squeezes its children
|
|
371
|
+
// or lets them spill. CSS defaults `flex-shrink` to 1, i.e. to
|
|
372
|
+
// ADW_WRAP_MINIMUM — the value libadwaita does NOT default to, so an
|
|
373
|
+
// unset policy has been drawing the wrong one on every wrap box. What
|
|
374
|
+
// flexbox cannot do either way is pack MORE children onto a line, since
|
|
375
|
+
// line breaking runs on hypothetical sizes; see `wrapPolicyFlexShrink`.
|
|
376
|
+
style.setProperty('--adw-wrap-box-child-shrink', String(wrapPolicyFlexShrink(this.wrapPolicy)));
|
|
377
|
+
|
|
378
|
+
// DELIBERATE DEVIATION: libadwaita's `natural-line-length` caps the box's
|
|
379
|
+
// NATURAL size request, leaving a larger allocation free to happen; CSS
|
|
380
|
+
// has no property that caps only the intrinsic contribution, so this is a
|
|
381
|
+
// max-size on the main axis and therefore caps the allocation too. It is
|
|
382
|
+
// the intended use (limiting line length inside a popover) either way.
|
|
383
|
+
const natural = wrapBoxLengthToPx(this.naturalLineLength, this.naturalLineLengthUnit);
|
|
384
|
+
const cap = natural === ADW_WRAP_BOX_NATURAL_LINE_LENGTH_UNSET ? '' : `${natural}px`;
|
|
385
|
+
style.maxWidth = vertical ? '' : cap;
|
|
386
|
+
style.maxHeight = vertical ? cap : '';
|
|
232
387
|
}
|
|
233
388
|
}
|
|
234
389
|
|