ripple 0.2.207 → 0.2.208
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/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Ripple is an elegant TypeScript UI framework",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.208",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -97,6 +97,6 @@
|
|
|
97
97
|
"vscode-languageserver-types": "^3.17.5"
|
|
98
98
|
},
|
|
99
99
|
"peerDependencies": {
|
|
100
|
-
"ripple": "0.2.
|
|
100
|
+
"ripple": "0.2.208"
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -248,15 +248,35 @@ export function bindValue(maybe_tracked, set_func = undefined) {
|
|
|
248
248
|
});
|
|
249
249
|
} else {
|
|
250
250
|
var input = /** @type {HTMLInputElement} */ (node);
|
|
251
|
-
var selection_restore_needed = false;
|
|
252
251
|
|
|
253
252
|
clear_event = on(input, 'input', () => {
|
|
254
|
-
selection_restore_needed = true;
|
|
255
253
|
/** @type {any} */
|
|
256
254
|
var value = input.value;
|
|
257
255
|
value = is_numberlike_input(input) ? to_number(value) : value;
|
|
258
|
-
// the setter will schedule a microtask and the render block below will run
|
|
259
256
|
setter(value);
|
|
257
|
+
const getter_value = getter();
|
|
258
|
+
|
|
259
|
+
// Check the getter to see if it's different from the input.value
|
|
260
|
+
// The setter may have decided not to update its track value or update it to something else
|
|
261
|
+
// We treat the getter as the source of truth since we cannot verify the change otherwise
|
|
262
|
+
// If getter() !== input.value, we set the input value right away
|
|
263
|
+
// the `render` block may be scheduled only if the tracked value has changed
|
|
264
|
+
// but it will not do anything if getter() === input.value
|
|
265
|
+
// The result is: the `render` block will ALWAYS exit early if the microtask
|
|
266
|
+
// came from this event handler
|
|
267
|
+
if (value !== getter_value) {
|
|
268
|
+
var start = input.selectionStart;
|
|
269
|
+
var end = input.selectionEnd;
|
|
270
|
+
|
|
271
|
+
input.value = getter_value ?? '';
|
|
272
|
+
|
|
273
|
+
if (end !== null && start !== null) {
|
|
274
|
+
end = Math.min(end, input.value.length);
|
|
275
|
+
start = Math.min(start, end);
|
|
276
|
+
input.selectionStart = start;
|
|
277
|
+
input.selectionEnd = end;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
260
280
|
});
|
|
261
281
|
|
|
262
282
|
render(() => {
|
|
@@ -271,23 +291,9 @@ export function bindValue(maybe_tracked, set_func = undefined) {
|
|
|
271
291
|
}
|
|
272
292
|
|
|
273
293
|
if (value !== input.value) {
|
|
274
|
-
if
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
input.value = value ?? '';
|
|
279
|
-
|
|
280
|
-
// Restore selection
|
|
281
|
-
if (end !== null && start !== null) {
|
|
282
|
-
end = Math.min(end, input.value.length);
|
|
283
|
-
start = Math.min(start, end);
|
|
284
|
-
input.selectionStart = start;
|
|
285
|
-
input.selectionEnd = end;
|
|
286
|
-
}
|
|
287
|
-
selection_restore_needed = false;
|
|
288
|
-
} else {
|
|
289
|
-
input.value = value ?? '';
|
|
290
|
-
}
|
|
294
|
+
// this can only get here if the tracked value was changed directly,
|
|
295
|
+
// and not via the input event
|
|
296
|
+
input.value = value ?? '';
|
|
291
297
|
}
|
|
292
298
|
});
|
|
293
299
|
|
|
@@ -1516,207 +1516,389 @@ describe('use value()', () => {
|
|
|
1516
1516
|
// Should fall back to first non-disabled option
|
|
1517
1517
|
expect(select.options[1].selected).toBe(true);
|
|
1518
1518
|
});
|
|
1519
|
-
});
|
|
1520
|
-
|
|
1521
|
-
describe('bindClientWidth and bindClientHeight', () => {
|
|
1522
|
-
it('should bind element clientWidth', () => {
|
|
1523
|
-
const logs: number[] = [];
|
|
1524
1519
|
|
|
1520
|
+
it('should accurately reflect values mutated through a tracked setter', () => {
|
|
1525
1521
|
component App() {
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1522
|
+
let value = track(
|
|
1523
|
+
'',
|
|
1524
|
+
(val) => {
|
|
1525
|
+
return val;
|
|
1526
|
+
},
|
|
1527
|
+
(next) => {
|
|
1528
|
+
if (next.includes('c')) {
|
|
1529
|
+
next = next.replace(/c/g, '');
|
|
1530
|
+
}
|
|
1531
|
+
return next;
|
|
1532
|
+
},
|
|
1533
|
+
);
|
|
1531
1534
|
|
|
1532
|
-
<
|
|
1535
|
+
<input type="text" {ref bindValue(value)} />
|
|
1536
|
+
<div>{@value}</div>
|
|
1533
1537
|
}
|
|
1534
1538
|
|
|
1535
1539
|
render(App);
|
|
1536
1540
|
flushSync();
|
|
1537
1541
|
|
|
1542
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1538
1543
|
const div = container.querySelector('div') as HTMLDivElement;
|
|
1539
1544
|
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
get: () => 200,
|
|
1543
|
-
});
|
|
1545
|
+
expect(input.value).toBe('');
|
|
1546
|
+
expect(div.textContent).toBe('');
|
|
1544
1547
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
});
|
|
1548
|
+
input.value = 'abc';
|
|
1549
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1548
1550
|
flushSync();
|
|
1549
1551
|
|
|
1550
|
-
expect(
|
|
1552
|
+
expect(input.value).toBe('ab');
|
|
1553
|
+
expect(div.textContent).toBe('ab');
|
|
1551
1554
|
});
|
|
1552
1555
|
|
|
1553
|
-
it('should
|
|
1554
|
-
const logs: number[] = [];
|
|
1555
|
-
|
|
1556
|
+
it('should accurately reflect values when a getter modifies value', () => {
|
|
1556
1557
|
component App() {
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1558
|
+
let value = track(
|
|
1559
|
+
'',
|
|
1560
|
+
(val) => {
|
|
1561
|
+
if (val.includes('c')) {
|
|
1562
|
+
val = val.replace(/c/g, '');
|
|
1563
|
+
}
|
|
1564
|
+
return val;
|
|
1565
|
+
},
|
|
1566
|
+
(next) => {
|
|
1567
|
+
return next;
|
|
1568
|
+
},
|
|
1569
|
+
);
|
|
1562
1570
|
|
|
1563
|
-
<
|
|
1571
|
+
<input type="text" {ref bindValue(value)} />
|
|
1572
|
+
<div>{@value}</div>
|
|
1564
1573
|
}
|
|
1565
1574
|
|
|
1566
1575
|
render(App);
|
|
1567
1576
|
flushSync();
|
|
1568
1577
|
|
|
1578
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1569
1579
|
const div = container.querySelector('div') as HTMLDivElement;
|
|
1570
1580
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
get: () => 200,
|
|
1574
|
-
});
|
|
1581
|
+
expect(input.value).toBe('');
|
|
1582
|
+
expect(div.textContent).toBe('');
|
|
1575
1583
|
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
});
|
|
1584
|
+
input.value = 'abc';
|
|
1585
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1579
1586
|
flushSync();
|
|
1580
1587
|
|
|
1581
|
-
expect(
|
|
1588
|
+
expect(input.value).toBe('ab');
|
|
1589
|
+
expect(div.textContent).toBe('ab');
|
|
1582
1590
|
});
|
|
1583
1591
|
|
|
1584
|
-
it('should
|
|
1585
|
-
const logs: number[] = [];
|
|
1586
|
-
|
|
1592
|
+
it('should always prefer what getter returns even if setter mutates next', () => {
|
|
1587
1593
|
component App() {
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1594
|
+
let value = track(
|
|
1595
|
+
'',
|
|
1596
|
+
(val) => {
|
|
1597
|
+
return val.replace(/[c,b]+/g, '');
|
|
1598
|
+
},
|
|
1599
|
+
(next) => {
|
|
1600
|
+
if (next.includes('c')) {
|
|
1601
|
+
next = next.replace(/c/g, '');
|
|
1602
|
+
}
|
|
1603
|
+
return next;
|
|
1604
|
+
},
|
|
1605
|
+
);
|
|
1593
1606
|
|
|
1594
|
-
<
|
|
1607
|
+
<input type="text" {ref bindValue(value)} />
|
|
1608
|
+
<div>{@value}</div>
|
|
1595
1609
|
}
|
|
1596
1610
|
|
|
1597
1611
|
render(App);
|
|
1598
1612
|
flushSync();
|
|
1599
1613
|
|
|
1614
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1600
1615
|
const div = container.querySelector('div') as HTMLDivElement;
|
|
1601
1616
|
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
get: () => 150,
|
|
1605
|
-
});
|
|
1617
|
+
expect(input.value).toBe('');
|
|
1618
|
+
expect(div.textContent).toBe('');
|
|
1606
1619
|
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
});
|
|
1620
|
+
input.value = 'abc';
|
|
1621
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1610
1622
|
flushSync();
|
|
1611
1623
|
|
|
1612
|
-
expect(
|
|
1624
|
+
expect(input.value).toBe('a');
|
|
1625
|
+
expect(div.textContent).toBe('a');
|
|
1613
1626
|
});
|
|
1614
1627
|
|
|
1615
|
-
it(
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1628
|
+
it(
|
|
1629
|
+
'should accurately reflect values mutated through an effect even after a setter mutation',
|
|
1630
|
+
() => {
|
|
1631
|
+
component App() {
|
|
1632
|
+
let value = track(
|
|
1633
|
+
'',
|
|
1634
|
+
(val) => {
|
|
1635
|
+
return val;
|
|
1636
|
+
},
|
|
1637
|
+
(next) => {
|
|
1638
|
+
if (next.includes('c')) {
|
|
1639
|
+
next = next.replace(/c/g, '');
|
|
1640
|
+
}
|
|
1641
|
+
return next;
|
|
1642
|
+
},
|
|
1643
|
+
);
|
|
1623
1644
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1645
|
+
effect(() => {
|
|
1646
|
+
@value;
|
|
1626
1647
|
|
|
1627
|
-
|
|
1628
|
-
|
|
1648
|
+
untrack(() => {
|
|
1649
|
+
if (@value.includes('a')) {
|
|
1650
|
+
@value = @value.replace(/a/g, '');
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
});
|
|
1654
|
+
<input type="text" {ref bindValue(value)} />
|
|
1655
|
+
<div>{@value}</div>
|
|
1656
|
+
}
|
|
1629
1657
|
|
|
1630
|
-
|
|
1658
|
+
render(App);
|
|
1659
|
+
flushSync();
|
|
1631
1660
|
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
get: () => 150,
|
|
1635
|
-
});
|
|
1661
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1662
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
1636
1663
|
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
});
|
|
1640
|
-
flushSync();
|
|
1664
|
+
expect(input.value).toBe('');
|
|
1665
|
+
expect(div.textContent).toBe('');
|
|
1641
1666
|
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1667
|
+
input.value = 'abc';
|
|
1668
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1669
|
+
flushSync();
|
|
1645
1670
|
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1671
|
+
expect(input.value).toBe('b');
|
|
1672
|
+
expect(div.textContent).toBe('b');
|
|
1673
|
+
},
|
|
1674
|
+
);
|
|
1649
1675
|
|
|
1676
|
+
it('should accurately reflect values mutated through a tracked setter via bind accessors', () => {
|
|
1650
1677
|
component App() {
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1678
|
+
let value = track('');
|
|
1679
|
+
const value_accessors = [
|
|
1680
|
+
() => {
|
|
1681
|
+
return @value;
|
|
1682
|
+
},
|
|
1683
|
+
(v: string) => {
|
|
1684
|
+
if (v.includes('c')) {
|
|
1685
|
+
v = v.replace(/c/g, '');
|
|
1686
|
+
}
|
|
1687
|
+
@value = v;
|
|
1688
|
+
},
|
|
1689
|
+
];
|
|
1656
1690
|
|
|
1657
|
-
<
|
|
1691
|
+
<input type="text" {ref bindValue(...value_accessors)} />
|
|
1658
1692
|
}
|
|
1659
1693
|
|
|
1660
1694
|
render(App);
|
|
1661
1695
|
flushSync();
|
|
1662
1696
|
|
|
1663
|
-
const
|
|
1697
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1664
1698
|
|
|
1665
|
-
|
|
1666
|
-
configurable: true,
|
|
1667
|
-
get: () => 250,
|
|
1668
|
-
});
|
|
1699
|
+
expect(input.value).toBe('');
|
|
1669
1700
|
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
});
|
|
1701
|
+
input.value = 'abc';
|
|
1702
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1673
1703
|
flushSync();
|
|
1674
1704
|
|
|
1675
|
-
expect(
|
|
1705
|
+
expect(input.value).toBe('ab');
|
|
1676
1706
|
});
|
|
1677
1707
|
|
|
1678
|
-
it('should
|
|
1679
|
-
const logs: number[] = [];
|
|
1680
|
-
|
|
1708
|
+
it('should prefer what getter returns via bind accessors', () => {
|
|
1681
1709
|
component App() {
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1710
|
+
let value = track('');
|
|
1711
|
+
const value_accessors = [
|
|
1712
|
+
() => {
|
|
1713
|
+
if (@value.includes('c')) {
|
|
1714
|
+
return @value.replace(/c/g, '');
|
|
1715
|
+
}
|
|
1716
|
+
return @value;
|
|
1717
|
+
},
|
|
1718
|
+
(v: string) => {
|
|
1719
|
+
@value = v;
|
|
1720
|
+
},
|
|
1721
|
+
];
|
|
1687
1722
|
|
|
1688
|
-
<
|
|
1723
|
+
<input type="text" {ref bindValue(...value_accessors)} />
|
|
1689
1724
|
}
|
|
1690
1725
|
|
|
1691
1726
|
render(App);
|
|
1692
1727
|
flushSync();
|
|
1693
1728
|
|
|
1694
|
-
const
|
|
1729
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1695
1730
|
|
|
1696
|
-
|
|
1697
|
-
configurable: true,
|
|
1698
|
-
get: () => 250,
|
|
1699
|
-
});
|
|
1731
|
+
expect(input.value).toBe('');
|
|
1700
1732
|
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
});
|
|
1733
|
+
input.value = 'abc';
|
|
1734
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1704
1735
|
flushSync();
|
|
1705
1736
|
|
|
1706
|
-
expect(
|
|
1737
|
+
expect(input.value).toBe('ab');
|
|
1707
1738
|
});
|
|
1708
1739
|
|
|
1709
|
-
it(
|
|
1740
|
+
it(
|
|
1741
|
+
'should always prefer what getter returns even if setter mutates next via bind accessors',
|
|
1742
|
+
() => {
|
|
1743
|
+
component App() {
|
|
1744
|
+
let value = track('');
|
|
1745
|
+
const value_accessors = [
|
|
1746
|
+
() => {
|
|
1747
|
+
return @value.replace(/[c,b]+/g, '');
|
|
1748
|
+
},
|
|
1749
|
+
(v: string) => {
|
|
1750
|
+
if (v.includes('c')) {
|
|
1751
|
+
v = v.replace(/c/g, '');
|
|
1752
|
+
}
|
|
1753
|
+
@value = v;
|
|
1754
|
+
},
|
|
1755
|
+
];
|
|
1756
|
+
|
|
1757
|
+
<input type="text" {ref bindValue(...value_accessors)} />
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
render(App);
|
|
1761
|
+
flushSync();
|
|
1762
|
+
|
|
1763
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1764
|
+
|
|
1765
|
+
expect(input.value).toBe('');
|
|
1766
|
+
|
|
1767
|
+
input.value = 'abc';
|
|
1768
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1769
|
+
flushSync();
|
|
1770
|
+
|
|
1771
|
+
expect(input.value).toBe('a');
|
|
1772
|
+
},
|
|
1773
|
+
);
|
|
1774
|
+
|
|
1775
|
+
it(
|
|
1776
|
+
'should accurately reflect values mutated through an effect even after a setter mutation via bind accessors',
|
|
1777
|
+
() => {
|
|
1778
|
+
component App() {
|
|
1779
|
+
let value = track('');
|
|
1780
|
+
const value_accessors = [
|
|
1781
|
+
() => {
|
|
1782
|
+
return @value;
|
|
1783
|
+
},
|
|
1784
|
+
(v: string) => {
|
|
1785
|
+
if (v.includes('c')) {
|
|
1786
|
+
v = v.replace(/c/g, '');
|
|
1787
|
+
}
|
|
1788
|
+
@value = v;
|
|
1789
|
+
},
|
|
1790
|
+
];
|
|
1791
|
+
|
|
1792
|
+
effect(() => {
|
|
1793
|
+
@value;
|
|
1794
|
+
|
|
1795
|
+
untrack(() => {
|
|
1796
|
+
if (@value.includes('a')) {
|
|
1797
|
+
@value = @value.replace(/a/g, '');
|
|
1798
|
+
}
|
|
1799
|
+
});
|
|
1800
|
+
});
|
|
1801
|
+
<input type="text" {ref bindValue(...value_accessors)} />
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
render(App);
|
|
1805
|
+
flushSync();
|
|
1806
|
+
|
|
1807
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1808
|
+
|
|
1809
|
+
expect(input.value).toBe('');
|
|
1810
|
+
|
|
1811
|
+
input.value = 'abc';
|
|
1812
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1813
|
+
flushSync();
|
|
1814
|
+
|
|
1815
|
+
expect(input.value).toBe('b');
|
|
1816
|
+
},
|
|
1817
|
+
);
|
|
1818
|
+
|
|
1819
|
+
it(
|
|
1820
|
+
'should keep the input.value unchanged and synced with the tracked when the setter blocks updates to the tracked via bind accessors',
|
|
1821
|
+
() => {
|
|
1822
|
+
component App() {
|
|
1823
|
+
let value = track('');
|
|
1824
|
+
const value_accessors = [
|
|
1825
|
+
() => {
|
|
1826
|
+
return @value;
|
|
1827
|
+
},
|
|
1828
|
+
(v: string) => {
|
|
1829
|
+
// no update
|
|
1830
|
+
},
|
|
1831
|
+
];
|
|
1832
|
+
|
|
1833
|
+
<input type="text" {ref bindValue(...value_accessors)} />
|
|
1834
|
+
<div>{@value}</div>
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
render(App);
|
|
1838
|
+
flushSync();
|
|
1839
|
+
|
|
1840
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1841
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
1842
|
+
|
|
1843
|
+
expect(input.value).toBe('');
|
|
1844
|
+
|
|
1845
|
+
input.value = 'abc';
|
|
1846
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1847
|
+
flushSync();
|
|
1848
|
+
|
|
1849
|
+
expect(input.value).toBe('');
|
|
1850
|
+
expect(div.textContent).toBe('');
|
|
1851
|
+
},
|
|
1852
|
+
);
|
|
1853
|
+
|
|
1854
|
+
it(
|
|
1855
|
+
'should keep the input.value unchanged and synced with the tracked when the setter blocks updates to the tracked via track get / set',
|
|
1856
|
+
() => {
|
|
1857
|
+
component App() {
|
|
1858
|
+
let value = track(
|
|
1859
|
+
'',
|
|
1860
|
+
(v) => {
|
|
1861
|
+
return v;
|
|
1862
|
+
},
|
|
1863
|
+
() => {
|
|
1864
|
+
return '';
|
|
1865
|
+
},
|
|
1866
|
+
);
|
|
1867
|
+
|
|
1868
|
+
<input type="text" {ref bindValue(value)} />
|
|
1869
|
+
<div>{@value}</div>
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
render(App);
|
|
1873
|
+
flushSync();
|
|
1874
|
+
|
|
1875
|
+
const input = container.querySelector('input') as HTMLInputElement;
|
|
1876
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
1877
|
+
|
|
1878
|
+
expect(input.value).toBe('');
|
|
1879
|
+
|
|
1880
|
+
input.value = 'abc';
|
|
1881
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1882
|
+
flushSync();
|
|
1883
|
+
|
|
1884
|
+
expect(input.value).toBe('');
|
|
1885
|
+
expect(div.textContent).toBe('');
|
|
1886
|
+
},
|
|
1887
|
+
);
|
|
1888
|
+
});
|
|
1889
|
+
|
|
1890
|
+
describe('bindClientWidth and bindClientHeight', () => {
|
|
1891
|
+
it('should bind element clientWidth', () => {
|
|
1710
1892
|
const logs: number[] = [];
|
|
1711
1893
|
|
|
1712
1894
|
component App() {
|
|
1713
|
-
const
|
|
1895
|
+
const width = track(0);
|
|
1714
1896
|
|
|
1715
1897
|
effect(() => {
|
|
1716
|
-
logs.push(@
|
|
1898
|
+
logs.push(@width);
|
|
1717
1899
|
});
|
|
1718
1900
|
|
|
1719
|
-
<div {ref
|
|
1901
|
+
<div {ref bindClientWidth(width)} />
|
|
1720
1902
|
}
|
|
1721
1903
|
|
|
1722
1904
|
render(App);
|
|
@@ -1724,29 +1906,30 @@ describe('bindOffsetWidth and bindOffsetHeight', () => {
|
|
|
1724
1906
|
|
|
1725
1907
|
const div = container.querySelector('div') as HTMLDivElement;
|
|
1726
1908
|
|
|
1727
|
-
Object.defineProperty(div, '
|
|
1909
|
+
Object.defineProperty(div, 'clientWidth', {
|
|
1728
1910
|
configurable: true,
|
|
1729
|
-
get: () =>
|
|
1911
|
+
get: () => 200,
|
|
1730
1912
|
});
|
|
1731
1913
|
|
|
1732
1914
|
triggerResize(div, {
|
|
1733
|
-
contentRect: new DOMRectReadOnly(0, 0,
|
|
1915
|
+
contentRect: new DOMRectReadOnly(0, 0, 200, 100),
|
|
1734
1916
|
});
|
|
1735
1917
|
flushSync();
|
|
1736
1918
|
|
|
1737
|
-
expect(logs[logs.length - 1]).toBe(
|
|
1919
|
+
expect(logs[logs.length - 1]).toBe(200);
|
|
1738
1920
|
});
|
|
1739
1921
|
|
|
1740
|
-
it('should bind element
|
|
1922
|
+
it('should bind element clientWidth with a getter and setter', () => {
|
|
1741
1923
|
const logs: number[] = [];
|
|
1742
1924
|
|
|
1743
1925
|
component App() {
|
|
1744
|
-
const
|
|
1926
|
+
const width = #{ value: 0 };
|
|
1927
|
+
|
|
1745
1928
|
effect(() => {
|
|
1746
|
-
logs.push(
|
|
1929
|
+
logs.push(width.value);
|
|
1747
1930
|
});
|
|
1748
1931
|
|
|
1749
|
-
<div {ref
|
|
1932
|
+
<div {ref bindClientWidth(() => width.value, (v: number) => (width.value = v))} />
|
|
1750
1933
|
}
|
|
1751
1934
|
|
|
1752
1935
|
render(App);
|
|
@@ -1754,32 +1937,30 @@ describe('bindOffsetWidth and bindOffsetHeight', () => {
|
|
|
1754
1937
|
|
|
1755
1938
|
const div = container.querySelector('div') as HTMLDivElement;
|
|
1756
1939
|
|
|
1757
|
-
Object.defineProperty(div, '
|
|
1940
|
+
Object.defineProperty(div, 'clientWidth', {
|
|
1758
1941
|
configurable: true,
|
|
1759
|
-
get: () =>
|
|
1942
|
+
get: () => 200,
|
|
1760
1943
|
});
|
|
1761
1944
|
|
|
1762
1945
|
triggerResize(div, {
|
|
1763
|
-
contentRect: new DOMRectReadOnly(0, 0,
|
|
1946
|
+
contentRect: new DOMRectReadOnly(0, 0, 200, 100),
|
|
1764
1947
|
});
|
|
1765
1948
|
flushSync();
|
|
1766
1949
|
|
|
1767
|
-
expect(logs[logs.length - 1]).toBe(
|
|
1950
|
+
expect(logs[logs.length - 1]).toBe(200);
|
|
1768
1951
|
});
|
|
1769
|
-
});
|
|
1770
1952
|
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
const logs: DOMRectReadOnly[] = [];
|
|
1953
|
+
it('should bind element clientHeight', () => {
|
|
1954
|
+
const logs: number[] = [];
|
|
1774
1955
|
|
|
1775
1956
|
component App() {
|
|
1776
|
-
const
|
|
1957
|
+
const height = track(0);
|
|
1777
1958
|
|
|
1778
1959
|
effect(() => {
|
|
1779
|
-
|
|
1960
|
+
logs.push(@height);
|
|
1780
1961
|
});
|
|
1781
1962
|
|
|
1782
|
-
<div {ref
|
|
1963
|
+
<div {ref bindClientHeight(height)} />
|
|
1783
1964
|
}
|
|
1784
1965
|
|
|
1785
1966
|
render(App);
|
|
@@ -1787,33 +1968,29 @@ describe('bindContentRect', () => {
|
|
|
1787
1968
|
|
|
1788
1969
|
const div = container.querySelector('div') as HTMLDivElement;
|
|
1789
1970
|
|
|
1790
|
-
|
|
1971
|
+
Object.defineProperty(div, 'clientHeight', {
|
|
1972
|
+
configurable: true,
|
|
1973
|
+
get: () => 150,
|
|
1974
|
+
});
|
|
1975
|
+
|
|
1791
1976
|
triggerResize(div, {
|
|
1792
|
-
contentRect:
|
|
1977
|
+
contentRect: new DOMRectReadOnly(0, 0, 100, 150),
|
|
1793
1978
|
});
|
|
1794
1979
|
flushSync();
|
|
1795
1980
|
|
|
1796
|
-
expect(logs.length).
|
|
1797
|
-
const lastRect = logs[logs.length - 1];
|
|
1798
|
-
expect(lastRect.width).toBe(300);
|
|
1799
|
-
expect(lastRect.height).toBe(200);
|
|
1981
|
+
expect(logs[logs.length - 1]).toBe(150);
|
|
1800
1982
|
});
|
|
1801
1983
|
|
|
1802
|
-
it('should bind element
|
|
1803
|
-
const logs:
|
|
1984
|
+
it('should bind element clientHeight with a getter and setter', () => {
|
|
1985
|
+
const logs: number[] = [];
|
|
1804
1986
|
|
|
1805
1987
|
component App() {
|
|
1806
|
-
const
|
|
1988
|
+
const height = #{ value: 0 };
|
|
1807
1989
|
effect(() => {
|
|
1808
|
-
|
|
1990
|
+
logs.push(height.value);
|
|
1809
1991
|
});
|
|
1810
1992
|
|
|
1811
|
-
<div
|
|
1812
|
-
{ref bindContentRect<null | DOMRectReadOnly>(
|
|
1813
|
-
() => rect.value,
|
|
1814
|
-
(v: DOMRectReadOnly) => (rect.value = v),
|
|
1815
|
-
)}
|
|
1816
|
-
/>
|
|
1993
|
+
<div {ref bindClientHeight(() => height.value, (v: number) => (height.value = v))} />
|
|
1817
1994
|
}
|
|
1818
1995
|
|
|
1819
1996
|
render(App);
|
|
@@ -1821,31 +1998,32 @@ describe('bindContentRect', () => {
|
|
|
1821
1998
|
|
|
1822
1999
|
const div = container.querySelector('div') as HTMLDivElement;
|
|
1823
2000
|
|
|
1824
|
-
|
|
2001
|
+
Object.defineProperty(div, 'clientHeight', {
|
|
2002
|
+
configurable: true,
|
|
2003
|
+
get: () => 150,
|
|
2004
|
+
});
|
|
2005
|
+
|
|
1825
2006
|
triggerResize(div, {
|
|
1826
|
-
contentRect:
|
|
2007
|
+
contentRect: new DOMRectReadOnly(0, 0, 100, 150),
|
|
1827
2008
|
});
|
|
1828
2009
|
flushSync();
|
|
1829
2010
|
|
|
1830
|
-
expect(logs.length).
|
|
1831
|
-
const lastRect = logs[logs.length - 1];
|
|
1832
|
-
expect(lastRect.width).toBe(300);
|
|
1833
|
-
expect(lastRect.height).toBe(200);
|
|
2011
|
+
expect(logs[logs.length - 1]).toBe(150);
|
|
1834
2012
|
});
|
|
1835
2013
|
});
|
|
1836
2014
|
|
|
1837
|
-
describe('
|
|
1838
|
-
it('should bind element
|
|
1839
|
-
const logs:
|
|
2015
|
+
describe('bindOffsetWidth and bindOffsetHeight', () => {
|
|
2016
|
+
it('should bind element offsetWidth', () => {
|
|
2017
|
+
const logs: number[] = [];
|
|
1840
2018
|
|
|
1841
2019
|
component App() {
|
|
1842
|
-
const
|
|
2020
|
+
const width = track(0);
|
|
1843
2021
|
|
|
1844
2022
|
effect(() => {
|
|
1845
|
-
|
|
2023
|
+
logs.push(@width);
|
|
1846
2024
|
});
|
|
1847
2025
|
|
|
1848
|
-
<div {ref
|
|
2026
|
+
<div {ref bindOffsetWidth(width)} />
|
|
1849
2027
|
}
|
|
1850
2028
|
|
|
1851
2029
|
render(App);
|
|
@@ -1853,16 +2031,207 @@ describe('bindContentBoxSize', () => {
|
|
|
1853
2031
|
|
|
1854
2032
|
const div = container.querySelector('div') as HTMLDivElement;
|
|
1855
2033
|
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
2034
|
+
Object.defineProperty(div, 'offsetWidth', {
|
|
2035
|
+
configurable: true,
|
|
2036
|
+
get: () => 250,
|
|
2037
|
+
});
|
|
2038
|
+
|
|
1859
2039
|
triggerResize(div, {
|
|
1860
|
-
|
|
2040
|
+
contentRect: new DOMRectReadOnly(0, 0, 250, 100),
|
|
1861
2041
|
});
|
|
1862
2042
|
flushSync();
|
|
1863
2043
|
|
|
1864
|
-
expect(logs.length).
|
|
1865
|
-
|
|
2044
|
+
expect(logs[logs.length - 1]).toBe(250);
|
|
2045
|
+
});
|
|
2046
|
+
|
|
2047
|
+
it('should bind element offsetWidth with a getter and setter', () => {
|
|
2048
|
+
const logs: number[] = [];
|
|
2049
|
+
|
|
2050
|
+
component App() {
|
|
2051
|
+
const width = #{ value: 0 };
|
|
2052
|
+
|
|
2053
|
+
effect(() => {
|
|
2054
|
+
logs.push(width.value);
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
<div {ref bindOffsetWidth(() => width.value, (v: number) => (width.value = v))} />
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
render(App);
|
|
2061
|
+
flushSync();
|
|
2062
|
+
|
|
2063
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
2064
|
+
|
|
2065
|
+
Object.defineProperty(div, 'offsetWidth', {
|
|
2066
|
+
configurable: true,
|
|
2067
|
+
get: () => 250,
|
|
2068
|
+
});
|
|
2069
|
+
|
|
2070
|
+
triggerResize(div, {
|
|
2071
|
+
contentRect: new DOMRectReadOnly(0, 0, 250, 100),
|
|
2072
|
+
});
|
|
2073
|
+
flushSync();
|
|
2074
|
+
|
|
2075
|
+
expect(logs[logs.length - 1]).toBe(250);
|
|
2076
|
+
});
|
|
2077
|
+
|
|
2078
|
+
it('should bind element offsetHeight', () => {
|
|
2079
|
+
const logs: number[] = [];
|
|
2080
|
+
|
|
2081
|
+
component App() {
|
|
2082
|
+
const height = track(0);
|
|
2083
|
+
|
|
2084
|
+
effect(() => {
|
|
2085
|
+
logs.push(@height);
|
|
2086
|
+
});
|
|
2087
|
+
|
|
2088
|
+
<div {ref bindOffsetHeight(height)} />
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
render(App);
|
|
2092
|
+
flushSync();
|
|
2093
|
+
|
|
2094
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
2095
|
+
|
|
2096
|
+
Object.defineProperty(div, 'offsetHeight', {
|
|
2097
|
+
configurable: true,
|
|
2098
|
+
get: () => 175,
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2101
|
+
triggerResize(div, {
|
|
2102
|
+
contentRect: new DOMRectReadOnly(0, 0, 100, 175),
|
|
2103
|
+
});
|
|
2104
|
+
flushSync();
|
|
2105
|
+
|
|
2106
|
+
expect(logs[logs.length - 1]).toBe(175);
|
|
2107
|
+
});
|
|
2108
|
+
|
|
2109
|
+
it('should bind element offsetHeight with a getter and setter', () => {
|
|
2110
|
+
const logs: number[] = [];
|
|
2111
|
+
|
|
2112
|
+
component App() {
|
|
2113
|
+
const height = #{ value: 0 };
|
|
2114
|
+
effect(() => {
|
|
2115
|
+
logs.push(height.value);
|
|
2116
|
+
});
|
|
2117
|
+
|
|
2118
|
+
<div {ref bindOffsetHeight(() => height.value, (v: number) => (height.value = v))} />
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
render(App);
|
|
2122
|
+
flushSync();
|
|
2123
|
+
|
|
2124
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
2125
|
+
|
|
2126
|
+
Object.defineProperty(div, 'offsetHeight', {
|
|
2127
|
+
configurable: true,
|
|
2128
|
+
get: () => 175,
|
|
2129
|
+
});
|
|
2130
|
+
|
|
2131
|
+
triggerResize(div, {
|
|
2132
|
+
contentRect: new DOMRectReadOnly(0, 0, 100, 175),
|
|
2133
|
+
});
|
|
2134
|
+
flushSync();
|
|
2135
|
+
|
|
2136
|
+
expect(logs[logs.length - 1]).toBe(175);
|
|
2137
|
+
});
|
|
2138
|
+
});
|
|
2139
|
+
|
|
2140
|
+
describe('bindContentRect', () => {
|
|
2141
|
+
it('should bind element contentRect', () => {
|
|
2142
|
+
const logs: DOMRectReadOnly[] = [];
|
|
2143
|
+
|
|
2144
|
+
component App() {
|
|
2145
|
+
const rect = track(null);
|
|
2146
|
+
|
|
2147
|
+
effect(() => {
|
|
2148
|
+
if (@rect) logs.push(@rect);
|
|
2149
|
+
});
|
|
2150
|
+
|
|
2151
|
+
<div {ref bindContentRect(rect)} />
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
render(App);
|
|
2155
|
+
flushSync();
|
|
2156
|
+
|
|
2157
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
2158
|
+
|
|
2159
|
+
const mockRect = new DOMRectReadOnly(10, 20, 300, 200);
|
|
2160
|
+
triggerResize(div, {
|
|
2161
|
+
contentRect: mockRect,
|
|
2162
|
+
});
|
|
2163
|
+
flushSync();
|
|
2164
|
+
|
|
2165
|
+
expect(logs.length).toBeGreaterThan(0);
|
|
2166
|
+
const lastRect = logs[logs.length - 1];
|
|
2167
|
+
expect(lastRect.width).toBe(300);
|
|
2168
|
+
expect(lastRect.height).toBe(200);
|
|
2169
|
+
});
|
|
2170
|
+
|
|
2171
|
+
it('should bind element contentRect with a getter and setter', () => {
|
|
2172
|
+
const logs: DOMRectReadOnly[] = [];
|
|
2173
|
+
|
|
2174
|
+
component App() {
|
|
2175
|
+
const rect: TrackedObject<{ value: DOMRectReadOnly | null }> = #{ value: null };
|
|
2176
|
+
effect(() => {
|
|
2177
|
+
if (rect.value) logs.push(rect.value);
|
|
2178
|
+
});
|
|
2179
|
+
|
|
2180
|
+
<div
|
|
2181
|
+
{ref bindContentRect<null | DOMRectReadOnly>(
|
|
2182
|
+
() => rect.value,
|
|
2183
|
+
(v: DOMRectReadOnly) => (rect.value = v),
|
|
2184
|
+
)}
|
|
2185
|
+
/>
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
render(App);
|
|
2189
|
+
flushSync();
|
|
2190
|
+
|
|
2191
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
2192
|
+
|
|
2193
|
+
const mockRect = new DOMRectReadOnly(10, 20, 300, 200);
|
|
2194
|
+
triggerResize(div, {
|
|
2195
|
+
contentRect: mockRect,
|
|
2196
|
+
});
|
|
2197
|
+
flushSync();
|
|
2198
|
+
|
|
2199
|
+
expect(logs.length).toBeGreaterThan(0);
|
|
2200
|
+
const lastRect = logs[logs.length - 1];
|
|
2201
|
+
expect(lastRect.width).toBe(300);
|
|
2202
|
+
expect(lastRect.height).toBe(200);
|
|
2203
|
+
});
|
|
2204
|
+
});
|
|
2205
|
+
|
|
2206
|
+
describe('bindContentBoxSize', () => {
|
|
2207
|
+
it('should bind element contentBoxSize', () => {
|
|
2208
|
+
const logs: any[] = [];
|
|
2209
|
+
|
|
2210
|
+
component App() {
|
|
2211
|
+
const boxSize = track(null);
|
|
2212
|
+
|
|
2213
|
+
effect(() => {
|
|
2214
|
+
if (@boxSize) logs.push(@boxSize);
|
|
2215
|
+
});
|
|
2216
|
+
|
|
2217
|
+
<div {ref bindContentBoxSize(boxSize)} />
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
render(App);
|
|
2221
|
+
flushSync();
|
|
2222
|
+
|
|
2223
|
+
const div = container.querySelector('div') as HTMLDivElement;
|
|
2224
|
+
|
|
2225
|
+
const mockBoxSize = [
|
|
2226
|
+
{ blockSize: 200, inlineSize: 300 },
|
|
2227
|
+
];
|
|
2228
|
+
triggerResize(div, {
|
|
2229
|
+
contentBoxSize: mockBoxSize as any,
|
|
2230
|
+
});
|
|
2231
|
+
flushSync();
|
|
2232
|
+
|
|
2233
|
+
expect(logs.length).toBeGreaterThan(0);
|
|
2234
|
+
expect(logs[logs.length - 1]).toBe(mockBoxSize);
|
|
1866
2235
|
});
|
|
1867
2236
|
|
|
1868
2237
|
it('should bind element contentBoxSize with a getter and setter', () => {
|
|
@@ -2534,305 +2903,6 @@ describe('bindNode', () => {
|
|
|
2534
2903
|
|
|
2535
2904
|
expect(input.value).toBe('Set by ref');
|
|
2536
2905
|
});
|
|
2537
|
-
|
|
2538
|
-
it('should accurately reflect values mutated through a tracked setter', () => {
|
|
2539
|
-
component App() {
|
|
2540
|
-
let value = track(
|
|
2541
|
-
'',
|
|
2542
|
-
(val) => {
|
|
2543
|
-
return val;
|
|
2544
|
-
},
|
|
2545
|
-
(next) => {
|
|
2546
|
-
if (next.includes('c')) {
|
|
2547
|
-
next = next.replace(/c/g, '');
|
|
2548
|
-
}
|
|
2549
|
-
return next;
|
|
2550
|
-
},
|
|
2551
|
-
);
|
|
2552
|
-
|
|
2553
|
-
<input type="text" {ref bindValue(value)} />
|
|
2554
|
-
<div>{@value}</div>
|
|
2555
|
-
}
|
|
2556
|
-
|
|
2557
|
-
render(App);
|
|
2558
|
-
flushSync();
|
|
2559
|
-
|
|
2560
|
-
const input = container.querySelector('input') as HTMLInputElement;
|
|
2561
|
-
const div = container.querySelector('div') as HTMLDivElement;
|
|
2562
|
-
|
|
2563
|
-
expect(input.value).toBe('');
|
|
2564
|
-
expect(div.textContent).toBe('');
|
|
2565
|
-
|
|
2566
|
-
input.value = 'abc';
|
|
2567
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2568
|
-
flushSync();
|
|
2569
|
-
|
|
2570
|
-
expect(input.value).toBe('ab');
|
|
2571
|
-
expect(div.textContent).toBe('ab');
|
|
2572
|
-
});
|
|
2573
|
-
|
|
2574
|
-
it('should accurately reflect values when a getter modifies value', () => {
|
|
2575
|
-
component App() {
|
|
2576
|
-
let value = track(
|
|
2577
|
-
'',
|
|
2578
|
-
(val) => {
|
|
2579
|
-
if (val.includes('c')) {
|
|
2580
|
-
val = val.replace(/c/g, '');
|
|
2581
|
-
}
|
|
2582
|
-
return val;
|
|
2583
|
-
},
|
|
2584
|
-
(next) => {
|
|
2585
|
-
return next;
|
|
2586
|
-
},
|
|
2587
|
-
);
|
|
2588
|
-
|
|
2589
|
-
<input type="text" {ref bindValue(value)} />
|
|
2590
|
-
<div>{@value}</div>
|
|
2591
|
-
}
|
|
2592
|
-
|
|
2593
|
-
render(App);
|
|
2594
|
-
flushSync();
|
|
2595
|
-
|
|
2596
|
-
const input = container.querySelector('input') as HTMLInputElement;
|
|
2597
|
-
const div = container.querySelector('div') as HTMLDivElement;
|
|
2598
|
-
|
|
2599
|
-
expect(input.value).toBe('');
|
|
2600
|
-
expect(div.textContent).toBe('');
|
|
2601
|
-
|
|
2602
|
-
input.value = 'abc';
|
|
2603
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2604
|
-
flushSync();
|
|
2605
|
-
|
|
2606
|
-
expect(input.value).toBe('ab');
|
|
2607
|
-
expect(div.textContent).toBe('ab');
|
|
2608
|
-
});
|
|
2609
|
-
|
|
2610
|
-
it('should always prefer what getter returns even if setter mutates next', () => {
|
|
2611
|
-
component App() {
|
|
2612
|
-
let value = track(
|
|
2613
|
-
'',
|
|
2614
|
-
(val) => {
|
|
2615
|
-
return val.replace(/[c,b]+/g, '');
|
|
2616
|
-
},
|
|
2617
|
-
(next) => {
|
|
2618
|
-
if (next.includes('c')) {
|
|
2619
|
-
next = next.replace(/c/g, '');
|
|
2620
|
-
}
|
|
2621
|
-
return next;
|
|
2622
|
-
},
|
|
2623
|
-
);
|
|
2624
|
-
|
|
2625
|
-
<input type="text" {ref bindValue(value)} />
|
|
2626
|
-
<div>{@value}</div>
|
|
2627
|
-
}
|
|
2628
|
-
|
|
2629
|
-
render(App);
|
|
2630
|
-
flushSync();
|
|
2631
|
-
|
|
2632
|
-
const input = container.querySelector('input') as HTMLInputElement;
|
|
2633
|
-
const div = container.querySelector('div') as HTMLDivElement;
|
|
2634
|
-
|
|
2635
|
-
expect(input.value).toBe('');
|
|
2636
|
-
expect(div.textContent).toBe('');
|
|
2637
|
-
|
|
2638
|
-
input.value = 'abc';
|
|
2639
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2640
|
-
flushSync();
|
|
2641
|
-
|
|
2642
|
-
expect(input.value).toBe('a');
|
|
2643
|
-
expect(div.textContent).toBe('a');
|
|
2644
|
-
});
|
|
2645
|
-
|
|
2646
|
-
it(
|
|
2647
|
-
'should accurately reflect values mutated through an effect even after a setter mutation',
|
|
2648
|
-
() => {
|
|
2649
|
-
component App() {
|
|
2650
|
-
let value = track(
|
|
2651
|
-
'',
|
|
2652
|
-
(val) => {
|
|
2653
|
-
return val;
|
|
2654
|
-
},
|
|
2655
|
-
(next) => {
|
|
2656
|
-
if (next.includes('c')) {
|
|
2657
|
-
next = next.replace(/c/g, '');
|
|
2658
|
-
}
|
|
2659
|
-
return next;
|
|
2660
|
-
},
|
|
2661
|
-
);
|
|
2662
|
-
|
|
2663
|
-
effect(() => {
|
|
2664
|
-
@value;
|
|
2665
|
-
|
|
2666
|
-
untrack(() => {
|
|
2667
|
-
if (@value.includes('a')) {
|
|
2668
|
-
@value = @value.replace(/a/g, '');
|
|
2669
|
-
}
|
|
2670
|
-
});
|
|
2671
|
-
});
|
|
2672
|
-
<input type="text" {ref bindValue(value)} />
|
|
2673
|
-
<div>{@value}</div>
|
|
2674
|
-
}
|
|
2675
|
-
|
|
2676
|
-
render(App);
|
|
2677
|
-
flushSync();
|
|
2678
|
-
|
|
2679
|
-
const input = container.querySelector('input') as HTMLInputElement;
|
|
2680
|
-
const div = container.querySelector('div') as HTMLDivElement;
|
|
2681
|
-
|
|
2682
|
-
expect(input.value).toBe('');
|
|
2683
|
-
expect(div.textContent).toBe('');
|
|
2684
|
-
|
|
2685
|
-
input.value = 'abc';
|
|
2686
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2687
|
-
flushSync();
|
|
2688
|
-
|
|
2689
|
-
expect(input.value).toBe('b');
|
|
2690
|
-
expect(div.textContent).toBe('b');
|
|
2691
|
-
},
|
|
2692
|
-
);
|
|
2693
|
-
|
|
2694
|
-
it('should accurately reflect values mutated through a tracked setter via bind accessors', () => {
|
|
2695
|
-
component App() {
|
|
2696
|
-
let value = track('');
|
|
2697
|
-
const value_accessors = [
|
|
2698
|
-
() => {
|
|
2699
|
-
return @value;
|
|
2700
|
-
},
|
|
2701
|
-
(v: string) => {
|
|
2702
|
-
if (v.includes('c')) {
|
|
2703
|
-
v = v.replace(/c/g, '');
|
|
2704
|
-
}
|
|
2705
|
-
@value = v;
|
|
2706
|
-
},
|
|
2707
|
-
];
|
|
2708
|
-
|
|
2709
|
-
<input type="text" {ref bindValue(...value_accessors)} />
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
render(App);
|
|
2713
|
-
flushSync();
|
|
2714
|
-
|
|
2715
|
-
const input = container.querySelector('input') as HTMLInputElement;
|
|
2716
|
-
|
|
2717
|
-
expect(input.value).toBe('');
|
|
2718
|
-
|
|
2719
|
-
input.value = 'abc';
|
|
2720
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2721
|
-
flushSync();
|
|
2722
|
-
|
|
2723
|
-
expect(input.value).toBe('ab');
|
|
2724
|
-
});
|
|
2725
|
-
|
|
2726
|
-
it('should prefer what getter returns via bind accessors', () => {
|
|
2727
|
-
component App() {
|
|
2728
|
-
let value = track('');
|
|
2729
|
-
const value_accessors = [
|
|
2730
|
-
() => {
|
|
2731
|
-
if (@value.includes('c')) {
|
|
2732
|
-
return @value.replace(/c/g, '');
|
|
2733
|
-
}
|
|
2734
|
-
return @value;
|
|
2735
|
-
},
|
|
2736
|
-
(v: string) => {
|
|
2737
|
-
@value = v;
|
|
2738
|
-
},
|
|
2739
|
-
];
|
|
2740
|
-
|
|
2741
|
-
<input type="text" {ref bindValue(...value_accessors)} />
|
|
2742
|
-
}
|
|
2743
|
-
|
|
2744
|
-
render(App);
|
|
2745
|
-
flushSync();
|
|
2746
|
-
|
|
2747
|
-
const input = container.querySelector('input') as HTMLInputElement;
|
|
2748
|
-
|
|
2749
|
-
expect(input.value).toBe('');
|
|
2750
|
-
|
|
2751
|
-
input.value = 'abc';
|
|
2752
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2753
|
-
flushSync();
|
|
2754
|
-
|
|
2755
|
-
expect(input.value).toBe('ab');
|
|
2756
|
-
});
|
|
2757
|
-
|
|
2758
|
-
it(
|
|
2759
|
-
'should always prefer what getter returns even if setter mutates next via bind accessors',
|
|
2760
|
-
() => {
|
|
2761
|
-
component App() {
|
|
2762
|
-
let value = track('');
|
|
2763
|
-
const value_accessors = [
|
|
2764
|
-
() => {
|
|
2765
|
-
return @value.replace(/[c,b]+/g, '');
|
|
2766
|
-
},
|
|
2767
|
-
(v: string) => {
|
|
2768
|
-
if (v.includes('c')) {
|
|
2769
|
-
v = v.replace(/c/g, '');
|
|
2770
|
-
}
|
|
2771
|
-
@value = v;
|
|
2772
|
-
},
|
|
2773
|
-
];
|
|
2774
|
-
|
|
2775
|
-
<input type="text" {ref bindValue(...value_accessors)} />
|
|
2776
|
-
}
|
|
2777
|
-
|
|
2778
|
-
render(App);
|
|
2779
|
-
flushSync();
|
|
2780
|
-
|
|
2781
|
-
const input = container.querySelector('input') as HTMLInputElement;
|
|
2782
|
-
|
|
2783
|
-
expect(input.value).toBe('');
|
|
2784
|
-
|
|
2785
|
-
input.value = 'abc';
|
|
2786
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2787
|
-
flushSync();
|
|
2788
|
-
|
|
2789
|
-
expect(input.value).toBe('a');
|
|
2790
|
-
},
|
|
2791
|
-
);
|
|
2792
|
-
|
|
2793
|
-
it(
|
|
2794
|
-
'should accurately reflect values mutated through an effect even after a setter mutation via bind accessors',
|
|
2795
|
-
() => {
|
|
2796
|
-
component App() {
|
|
2797
|
-
let value = track('');
|
|
2798
|
-
const value_accessors = [
|
|
2799
|
-
() => {
|
|
2800
|
-
return @value;
|
|
2801
|
-
},
|
|
2802
|
-
(v: string) => {
|
|
2803
|
-
if (v.includes('c')) {
|
|
2804
|
-
v = v.replace(/c/g, '');
|
|
2805
|
-
}
|
|
2806
|
-
@value = v;
|
|
2807
|
-
},
|
|
2808
|
-
];
|
|
2809
|
-
|
|
2810
|
-
effect(() => {
|
|
2811
|
-
@value;
|
|
2812
|
-
|
|
2813
|
-
untrack(() => {
|
|
2814
|
-
if (@value.includes('a')) {
|
|
2815
|
-
@value = @value.replace(/a/g, '');
|
|
2816
|
-
}
|
|
2817
|
-
});
|
|
2818
|
-
});
|
|
2819
|
-
<input type="text" {ref bindValue(...value_accessors)} />
|
|
2820
|
-
}
|
|
2821
|
-
|
|
2822
|
-
render(App);
|
|
2823
|
-
flushSync();
|
|
2824
|
-
|
|
2825
|
-
const input = container.querySelector('input') as HTMLInputElement;
|
|
2826
|
-
|
|
2827
|
-
expect(input.value).toBe('');
|
|
2828
|
-
|
|
2829
|
-
input.value = 'abc';
|
|
2830
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
2831
|
-
flushSync();
|
|
2832
|
-
|
|
2833
|
-
expect(input.value).toBe('b');
|
|
2834
|
-
},
|
|
2835
|
-
);
|
|
2836
2906
|
});
|
|
2837
2907
|
|
|
2838
2908
|
describe('bindFiles', () => {
|