@react-x11/components 0.14.1 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/code-editor/node.d.ts +13 -0
- package/dist/code-editor/node.d.ts.map +1 -1
- package/dist/code-editor/node.js +23 -5
- package/dist/code-editor/node.js.map +1 -1
- package/dist/html/css/cascade.d.ts +171 -26
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +616 -216
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +25 -0
- package/dist/html/css/color.d.ts.map +1 -1
- package/dist/html/css/color.js +307 -19
- package/dist/html/css/color.js.map +1 -1
- package/dist/html/css/content.d.ts +11 -6
- package/dist/html/css/content.d.ts.map +1 -1
- package/dist/html/css/content.js +171 -12
- package/dist/html/css/content.js.map +1 -1
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +62 -9
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/shapes.d.ts +18 -0
- package/dist/html/css/shapes.d.ts.map +1 -1
- package/dist/html/css/shapes.js +21 -1
- package/dist/html/css/shapes.js.map +1 -1
- package/dist/html/css/style.d.ts +42 -5
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +74 -12
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/ua.js +27 -8
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +5 -0
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +18 -9
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +7 -0
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/block.d.ts +29 -9
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +141 -52
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +29 -2
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +172 -23
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/css-grid.d.ts.map +1 -1
- package/dist/html/layout/css-grid.js +11 -9
- package/dist/html/layout/css-grid.js.map +1 -1
- package/dist/html/layout/flex.d.ts.map +1 -1
- package/dist/html/layout/flex.js +1759 -238
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/inline.d.ts +15 -3
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +64 -19
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/table.d.ts +27 -1
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +886 -324
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/node.d.ts +35 -4
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +122 -26
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +558 -178
- package/dist/html/paint.js.map +1 -1
- package/dist/html/resources.js +14 -1
- package/dist/html/resources.js.map +1 -1
- package/dist/html/svg.d.ts +23 -7
- package/dist/html/svg.d.ts.map +1 -1
- package/dist/html/svg.js +264 -59
- package/dist/html/svg.js.map +1 -1
- package/dist/html/widgets.d.ts.map +1 -1
- package/dist/html/widgets.js +57 -4
- package/dist/html/widgets.js.map +1 -1
- package/package.json +3 -3
- package/src/code-editor/node.ts +24 -5
- package/src/html/css/cascade.ts +697 -221
- package/src/html/css/color.ts +345 -18
- package/src/html/css/content.ts +173 -15
- package/src/html/css/parse.ts +60 -8
- package/src/html/css/shapes.ts +35 -1
- package/src/html/css/style.ts +122 -17
- package/src/html/css/ua.ts +27 -8
- package/src/html/css/values.ts +23 -9
- package/src/html/index.ts +7 -0
- package/src/html/layout/block.ts +149 -58
- package/src/html/layout/boxes.ts +211 -27
- package/src/html/layout/css-grid.ts +12 -9
- package/src/html/layout/flex.ts +1975 -231
- package/src/html/layout/inline.ts +70 -16
- package/src/html/layout/table.ts +961 -332
- package/src/html/node.ts +155 -27
- package/src/html/paint.ts +692 -234
- package/src/html/resources.ts +13 -1
- package/src/html/svg.ts +299 -56
- package/src/html/widgets.ts +61 -4
package/src/html/node.ts
CHANGED
|
@@ -56,8 +56,15 @@ import {
|
|
|
56
56
|
HOVER_PSEUDO_NONE,
|
|
57
57
|
HOVER_PSEUDO_OTHER,
|
|
58
58
|
HOVER_UNTOUCHED,
|
|
59
|
+
NO_FOCUS,
|
|
60
|
+
} from './css/cascade.js';
|
|
61
|
+
import type {
|
|
62
|
+
FocusState,
|
|
63
|
+
HoverTouch,
|
|
64
|
+
KeptStyles,
|
|
65
|
+
MetricFace,
|
|
66
|
+
PointerState,
|
|
59
67
|
} from './css/cascade.js';
|
|
60
|
-
import type { HoverTouch, KeptStyles, MetricFace } from './css/cascade.js';
|
|
61
68
|
import { mediaMatches, parseStylesheet } from './css/parse.js';
|
|
62
69
|
import type { MediaCondition, Stylesheet } from './css/parse.js';
|
|
63
70
|
import type { ShapeStyles } from './css/shapes.js';
|
|
@@ -129,7 +136,7 @@ import {
|
|
|
129
136
|
stacksLayers,
|
|
130
137
|
} from './paint.js';
|
|
131
138
|
import type { PaintContext } from './paint.js';
|
|
132
|
-
import { controlRectsOf, measureControl } from './controls.js';
|
|
139
|
+
import { controlRectsOf, measureControl, styledField } from './controls.js';
|
|
133
140
|
import type { BareField, ControlRect } from './controls.js';
|
|
134
141
|
import { ResourceStore } from './resources.js';
|
|
135
142
|
import type { ResourceRequest, ResourceResult } from './resources.js';
|
|
@@ -290,6 +297,8 @@ export class HtmlViewNode extends Node {
|
|
|
290
297
|
* the text carries surrogate pairs. null until checked. */
|
|
291
298
|
private _pointsAreUnits: boolean | null = null;
|
|
292
299
|
private _hovered: Element[] = [];
|
|
300
|
+
/** Which element's widget holds the focus (`setFocus`). */
|
|
301
|
+
private _focus: FocusState = NO_FOCUS;
|
|
293
302
|
/** Where the pointer last moved to, in logical window pixels, while it
|
|
294
303
|
* is over the element (`defaultMouseMove`). */
|
|
295
304
|
private _pointerAt: { x: number; y: number } | null = null;
|
|
@@ -402,6 +411,12 @@ export class HtmlViewNode extends Node {
|
|
|
402
411
|
controlBorder: look.controlBorder * s,
|
|
403
412
|
controlRadius: look.controlRadius * s,
|
|
404
413
|
controlFontSize: (look.controlFontSize ?? look.fontSize) * s,
|
|
414
|
+
...(look.focusRingWidth !== undefined && {
|
|
415
|
+
focusRingWidth: look.focusRingWidth * s,
|
|
416
|
+
}),
|
|
417
|
+
...(look.focusRingOffset !== undefined && {
|
|
418
|
+
focusRingOffset: look.focusRingOffset * s,
|
|
419
|
+
}),
|
|
405
420
|
};
|
|
406
421
|
this._deviceLookFor = look;
|
|
407
422
|
this._deviceLookAt = s;
|
|
@@ -711,6 +726,7 @@ export class HtmlViewNode extends Node {
|
|
|
711
726
|
hovered: new Set(this._hovered),
|
|
712
727
|
active: EMPTY_SET,
|
|
713
728
|
});
|
|
729
|
+
this._cascade.setFocus(this._focus);
|
|
714
730
|
this._mediaBand = this._cascade.mediaBand(width);
|
|
715
731
|
}
|
|
716
732
|
|
|
@@ -1031,6 +1047,14 @@ export class HtmlViewNode extends Node {
|
|
|
1031
1047
|
scale: this._scale,
|
|
1032
1048
|
imageSize: (el) => this._resources.imageSize(imageUrlOf(el) ?? ''),
|
|
1033
1049
|
urlSize: (url) => this._resources.imageSize(url),
|
|
1050
|
+
faceAscent: (style) => {
|
|
1051
|
+
const fonts = this._fonts();
|
|
1052
|
+
return fonts ? faceExtentOf(fonts, style).ascent : undefined;
|
|
1053
|
+
},
|
|
1054
|
+
faceExtent: (style) => {
|
|
1055
|
+
const fonts = this._fonts();
|
|
1056
|
+
return fonts ? faceExtentOf(fonts, style) : undefined;
|
|
1057
|
+
},
|
|
1034
1058
|
controlSize: (el, kind, style) =>
|
|
1035
1059
|
measureControl(el, kind, style, this._fonts(), look),
|
|
1036
1060
|
});
|
|
@@ -1539,37 +1563,120 @@ export class HtmlViewNode extends Node {
|
|
|
1539
1563
|
* with the styles of every element the move did not reach kept.
|
|
1540
1564
|
*/
|
|
1541
1565
|
private _restyleHover(was: readonly Element[], now: readonly Element[]) {
|
|
1566
|
+
const cascade = this._cascade;
|
|
1542
1567
|
const reach = this._hoverReach(was, now);
|
|
1543
|
-
if (reach !== null) {
|
|
1568
|
+
if (reach !== null && cascade) {
|
|
1544
1569
|
if (!reach.size) return;
|
|
1545
|
-
|
|
1570
|
+
const before = { hovered: new Set(was), active: EMPTY_SET };
|
|
1571
|
+
if (this._hoverInPlace(reach, before, this._focus, cascade.hoverPseudo)) {
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1546
1574
|
}
|
|
1547
1575
|
this._invalidate(Stale.Boxes, reach);
|
|
1548
1576
|
}
|
|
1549
1577
|
|
|
1578
|
+
/** The element whose widget holds the focus, or null (`setFocus`). */
|
|
1579
|
+
get focusedElement(): Element | null {
|
|
1580
|
+
return this._focus.element;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
/**
|
|
1584
|
+
* The focus moved: `element`'s widget took it, or, given null, no widget
|
|
1585
|
+
* of this document holds it now — it went to something else in the
|
|
1586
|
+
* window, or nowhere. `visible` is whether it shows, `:focus-visible`,
|
|
1587
|
+
* which it always does in a text field. Restyles what `:focus` and its
|
|
1588
|
+
* kin reach as a hover does (`_restyleHover`), and returns whether the
|
|
1589
|
+
* cascade's answer could have changed.
|
|
1590
|
+
*
|
|
1591
|
+
* No element of a document takes the focus: a control's widget, mounted
|
|
1592
|
+
* beside it, does, and says so here. Only a text field's does, so far —
|
|
1593
|
+
* the widgets core draws as components keep their own focus to
|
|
1594
|
+
* themselves.
|
|
1595
|
+
*/
|
|
1596
|
+
setFocus(element: Element | null, visible = true): boolean {
|
|
1597
|
+
const was = this._focus;
|
|
1598
|
+
if (was.element === element && (!element || was.visible === visible)) {
|
|
1599
|
+
return false;
|
|
1600
|
+
}
|
|
1601
|
+
const within = new Set<Element>();
|
|
1602
|
+
for (
|
|
1603
|
+
let at: Element | null = element;
|
|
1604
|
+
at;
|
|
1605
|
+
at = isElement(at.parent) ? at.parent : null
|
|
1606
|
+
) {
|
|
1607
|
+
within.add(at);
|
|
1608
|
+
}
|
|
1609
|
+
const now: FocusState = element ? { element, visible, within } : NO_FOCUS;
|
|
1610
|
+
this._focus = now;
|
|
1611
|
+
const cascade = this._cascade;
|
|
1612
|
+
cascade?.setFocus(now);
|
|
1613
|
+
if (!cascade || !cascade.focusSensitive) return false;
|
|
1614
|
+
const reach = cascade.focusLocal
|
|
1615
|
+
? this._stateReach(
|
|
1616
|
+
[...was.within],
|
|
1617
|
+
[...now.within],
|
|
1618
|
+
// one element, whose ring came or went
|
|
1619
|
+
was.element === element ? element : null,
|
|
1620
|
+
(el) => cascade.focusTouches(el),
|
|
1621
|
+
(el, into) => cascade.focusAnchors(el, into),
|
|
1622
|
+
)
|
|
1623
|
+
: null;
|
|
1624
|
+
if (reach !== null) {
|
|
1625
|
+
if (!reach.size) return true;
|
|
1626
|
+
const pointer = { hovered: new Set(this._hovered), active: EMPTY_SET };
|
|
1627
|
+
if (this._hoverInPlace(reach, pointer, was, cascade.focusPseudo)) {
|
|
1628
|
+
return true;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
this._invalidate(Stale.Boxes, reach);
|
|
1632
|
+
return true;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1550
1635
|
/**
|
|
1551
1636
|
* The elements whose styles a move of the hovered chain can change, or
|
|
1552
1637
|
* null where that cannot be said (`Cascade.hoverLocal`).
|
|
1638
|
+
*/
|
|
1639
|
+
private _hoverReach(
|
|
1640
|
+
was: readonly Element[],
|
|
1641
|
+
now: readonly Element[],
|
|
1642
|
+
): Set<Element> | null {
|
|
1643
|
+
const cascade = this._cascade;
|
|
1644
|
+
if (!cascade || !cascade.hoverLocal) return null;
|
|
1645
|
+
return this._stateReach(
|
|
1646
|
+
was,
|
|
1647
|
+
now,
|
|
1648
|
+
null,
|
|
1649
|
+
(el) => cascade.hoverTouches(el),
|
|
1650
|
+
(el, into) => cascade.hoverAnchors(el, into),
|
|
1651
|
+
);
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
/**
|
|
1655
|
+
* The elements whose styles a move of the hovered chain can change, or
|
|
1656
|
+
* of the focus's chain.
|
|
1553
1657
|
*
|
|
1554
1658
|
* Only an element whose hover state flipped and that a compound testing
|
|
1555
1659
|
* the pointer could match can change (`Cascade.hoverTouches`), with its
|
|
1556
1660
|
* subtree, and its later siblings' where a sibling combinator is in play;
|
|
1557
1661
|
* and the elements a `:has()` testing the pointer may flip, which are
|
|
1558
1662
|
* around the ones that changed. A move between two paragraphs under
|
|
1559
|
-
* `a:hover` reaches nothing.
|
|
1663
|
+
* `a:hover` reaches nothing. The focus's the same way, its chain the
|
|
1664
|
+
* focused element and every element around it, and `also` one whose
|
|
1665
|
+
* state flipped though it is in both — the ring coming or going.
|
|
1560
1666
|
*/
|
|
1561
|
-
private
|
|
1667
|
+
private _stateReach(
|
|
1562
1668
|
was: readonly Element[],
|
|
1563
1669
|
now: readonly Element[],
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1670
|
+
also: Element | null,
|
|
1671
|
+
touches: (el: Element) => HoverTouch,
|
|
1672
|
+
anchors: (el: Element, into: Map<Element, HoverTouch>) => void,
|
|
1673
|
+
): Set<Element> {
|
|
1567
1674
|
const before = new Set(was);
|
|
1568
1675
|
const after = new Set(now);
|
|
1569
1676
|
const roots = new Map<Element, HoverTouch>();
|
|
1570
|
-
const flipped = (el: Element, other: Set<Element>): void => {
|
|
1571
|
-
if (other
|
|
1572
|
-
const touch =
|
|
1677
|
+
const flipped = (el: Element, other: Set<Element> | null): void => {
|
|
1678
|
+
if (other?.has(el)) return;
|
|
1679
|
+
const touch = touches(el);
|
|
1573
1680
|
if (touch > (roots.get(el) ?? HOVER_UNTOUCHED)) roots.set(el, touch);
|
|
1574
1681
|
};
|
|
1575
1682
|
for (const el of was) flipped(el, after);
|
|
@@ -1578,10 +1685,14 @@ export class HtmlViewNode extends Node {
|
|
|
1578
1685
|
// side is where a `:has()` is looked for from
|
|
1579
1686
|
const deepest = (chain: readonly Element[], other: Set<Element>) => {
|
|
1580
1687
|
const el = chain[0];
|
|
1581
|
-
if (el && !other.has(el))
|
|
1688
|
+
if (el && !other.has(el)) anchors(el, roots);
|
|
1582
1689
|
};
|
|
1583
1690
|
deepest(was, after);
|
|
1584
1691
|
deepest(now, before);
|
|
1692
|
+
if (also) {
|
|
1693
|
+
flipped(also, null);
|
|
1694
|
+
anchors(also, roots);
|
|
1695
|
+
}
|
|
1585
1696
|
|
|
1586
1697
|
// the roots' subtrees, which inherit from them and a descendant
|
|
1587
1698
|
// combinator reaches, and their later siblings' too where a sibling
|
|
@@ -1626,8 +1737,10 @@ export class HtmlViewNode extends Node {
|
|
|
1626
1737
|
* - The boxes take their new styles: an element's own, the text in it,
|
|
1627
1738
|
* the anonymous boxes the fix-up made around what is in it, and its
|
|
1628
1739
|
* `::before` and `::after`, styled again by their own rules. A box
|
|
1629
|
-
* whose style is derived some other way — a marker, a first letter
|
|
1630
|
-
*
|
|
1740
|
+
* whose style is derived some other way — a marker, a first letter —
|
|
1741
|
+
* is not one to restyle here. A control's is, and its widget is told
|
|
1742
|
+
* (`_reportControls`), unless the page took to drawing the field or
|
|
1743
|
+
* stopped.
|
|
1631
1744
|
* - Each layout of their text is made again from the runs it was made
|
|
1632
1745
|
* from (`TextLayoutCache.inputsOf`) with the new ink (`runFor`), where
|
|
1633
1746
|
* its geometry comes out the same.
|
|
@@ -1637,10 +1750,16 @@ export class HtmlViewNode extends Node {
|
|
|
1637
1750
|
* costs what it changed, in a document of any length. True where it was
|
|
1638
1751
|
* restyled here, or had nothing to restyle; false where the boxes have to
|
|
1639
1752
|
* be built again.
|
|
1753
|
+
*
|
|
1754
|
+
* A focus change is answered the same way (`setFocus`): `before` and
|
|
1755
|
+
* `beforeFocus` are the states the change was from, and `pseudoRules`
|
|
1756
|
+
* which pseudo-elements' rules test the state that changed.
|
|
1640
1757
|
*/
|
|
1641
1758
|
private _hoverInPlace(
|
|
1642
1759
|
reach: ReadonlySet<Element>,
|
|
1643
|
-
|
|
1760
|
+
before: PointerState,
|
|
1761
|
+
beforeFocus: FocusState,
|
|
1762
|
+
pseudoRules: 0 | 1 | 2,
|
|
1644
1763
|
): boolean {
|
|
1645
1764
|
const cascade = this._cascade;
|
|
1646
1765
|
const tree = this._tree;
|
|
@@ -1649,17 +1768,15 @@ export class HtmlViewNode extends Node {
|
|
|
1649
1768
|
if (this._stale !== Stale.Nothing || this._laidOutWidth < 0) return false;
|
|
1650
1769
|
if (reach.size > HOVER_RESTYLE_LIMIT) return false;
|
|
1651
1770
|
// a first line's, a first letter's and a marker's styles are layout's
|
|
1652
|
-
const pseudoRules = cascade.hoverPseudo;
|
|
1653
1771
|
if (pseudoRules === HOVER_PSEUDO_OTHER) return false;
|
|
1654
1772
|
|
|
1655
|
-
// whether the rules that test the pointer
|
|
1656
|
-
// element than they did before the
|
|
1657
|
-
const before = { hovered: new Set(was), active: EMPTY_SET };
|
|
1773
|
+
// whether the rules that test the pointer or the focus answer
|
|
1774
|
+
// differently for an element than they did before the change
|
|
1658
1775
|
const flips = new Map<Element, boolean>();
|
|
1659
1776
|
const flipped = (el: Element): boolean => {
|
|
1660
1777
|
let flip = flips.get(el);
|
|
1661
1778
|
if (flip === undefined) {
|
|
1662
|
-
flip = cascade.pointerChanged(el, before);
|
|
1779
|
+
flip = cascade.pointerChanged(el, before, beforeFocus);
|
|
1663
1780
|
flips.set(el, flip);
|
|
1664
1781
|
}
|
|
1665
1782
|
return flip;
|
|
@@ -1677,6 +1794,8 @@ export class HtmlViewNode extends Node {
|
|
|
1677
1794
|
let reaches = false;
|
|
1678
1795
|
let reorders = false;
|
|
1679
1796
|
const moving = new Set<Element>();
|
|
1797
|
+
/** Whether a control's box was restyled: its widget is told. */
|
|
1798
|
+
let widgets = false;
|
|
1680
1799
|
const styleOf = (el: Element): ComputedStyle | null => {
|
|
1681
1800
|
const kept = tree.styles.get(el);
|
|
1682
1801
|
if (!kept) return null;
|
|
@@ -1729,7 +1848,7 @@ export class HtmlViewNode extends Node {
|
|
|
1729
1848
|
const box = this._firstBoxesOf(tree).get(el);
|
|
1730
1849
|
const was = box && SHAPE_STYLES.get(box);
|
|
1731
1850
|
if (!box || was === undefined) continue;
|
|
1732
|
-
const shapes = cascade.shapeStyles(el, style);
|
|
1851
|
+
const shapes = cascade.shapeStyles(el, style, tree.shapeCopies);
|
|
1733
1852
|
if (shapes?.key !== was?.key) redrawn.push([box, shapes]);
|
|
1734
1853
|
}
|
|
1735
1854
|
}
|
|
@@ -1820,11 +1939,20 @@ export class HtmlViewNode extends Node {
|
|
|
1820
1939
|
if (!style) continue;
|
|
1821
1940
|
const kept = tree.styles.get(el)!.style;
|
|
1822
1941
|
// a style derived from the element's, or drawn from it somewhere
|
|
1823
|
-
// else
|
|
1824
|
-
// it
|
|
1825
|
-
//
|
|
1942
|
+
// else. A widget mounted beside the document takes its look from
|
|
1943
|
+
// it, and is told again once it is restyled — unless the page took
|
|
1944
|
+
// to drawing the field, or stopped, which is another size of box.
|
|
1945
|
+
// An image, a drawing or a rule is drawn here, from its box, like
|
|
1946
|
+
// any.
|
|
1826
1947
|
if (box.style !== kept) return false;
|
|
1827
|
-
if (box.marker
|
|
1948
|
+
if (box.marker) return false;
|
|
1949
|
+
if (WIDGETS.has(box.replaced)) {
|
|
1950
|
+
const kind = box.replaced!;
|
|
1951
|
+
if (styledField(kind, kept) !== styledField(kind, style)) {
|
|
1952
|
+
return false;
|
|
1953
|
+
}
|
|
1954
|
+
widgets = true;
|
|
1955
|
+
}
|
|
1828
1956
|
if (moving.has(el) && !movable(box, kept, style)) return false;
|
|
1829
1957
|
ink = !quiet.has(el);
|
|
1830
1958
|
} else if (above) {
|
|
@@ -1944,7 +2072,7 @@ export class HtmlViewNode extends Node {
|
|
|
1944
2072
|
relayout = true;
|
|
1945
2073
|
}
|
|
1946
2074
|
}
|
|
1947
|
-
if (moved.length) this._reportControls();
|
|
2075
|
+
if (moved.length || widgets) this._reportControls();
|
|
1948
2076
|
if (relayout) {
|
|
1949
2077
|
this._invalidate(Stale.Layout);
|
|
1950
2078
|
return true;
|