@ionic/react 9.0.1-dev.11788212611.154b1596 → 9.0.1-dev.11788375537.1f38f077
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/css/core.css +1 -1
- package/css/core.css.map +1 -1
- package/css/ionic.bundle.css +1 -1
- package/css/ionic.bundle.css.map +1 -1
- package/dist/index.js +53 -177
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1395,72 +1395,6 @@ const detachEvent = (node, eventName) => {
|
|
|
1395
1395
|
* React event-delegation root.
|
|
1396
1396
|
*/
|
|
1397
1397
|
const NestedOverlayContext = React.createContext(false);
|
|
1398
|
-
/**
|
|
1399
|
-
* React skips `componentWillUnmount` when it destroys a subtree it had already
|
|
1400
|
-
* hidden, so a hidden overlay watches its own marker leave the document. One
|
|
1401
|
-
* observer serves every watcher, since each one allocates its own records for
|
|
1402
|
-
* a whole root.
|
|
1403
|
-
*
|
|
1404
|
-
* This all assumes React hides with `display: none` rather than detaching, so
|
|
1405
|
-
* the marker survives a hide. True today, but an implementation detail.
|
|
1406
|
-
*/
|
|
1407
|
-
const destroyWatches = new Set();
|
|
1408
|
-
let destroyObserver;
|
|
1409
|
-
const stopDestroyObserverIfIdle = () => {
|
|
1410
|
-
if (destroyWatches.size === 0) {
|
|
1411
|
-
destroyObserver?.disconnect();
|
|
1412
|
-
destroyObserver = undefined;
|
|
1413
|
-
}
|
|
1414
|
-
};
|
|
1415
|
-
const watchForDestroy = (marker, onDestroy) => {
|
|
1416
|
-
if (typeof MutationObserver === 'undefined') {
|
|
1417
|
-
return undefined;
|
|
1418
|
-
}
|
|
1419
|
-
const watch = { marker, onDestroy };
|
|
1420
|
-
destroyWatches.add(watch);
|
|
1421
|
-
if (destroyObserver === undefined) {
|
|
1422
|
-
destroyObserver = new MutationObserver(() => {
|
|
1423
|
-
try {
|
|
1424
|
-
for (const candidate of Array.from(destroyWatches)) {
|
|
1425
|
-
if (candidate.marker.isConnected) {
|
|
1426
|
-
continue;
|
|
1427
|
-
}
|
|
1428
|
-
destroyWatches.delete(candidate);
|
|
1429
|
-
// `detachProps` assigns arbitrary props onto a custom element, so a
|
|
1430
|
-
// throwing setter would otherwise strand every remaining overlay.
|
|
1431
|
-
try {
|
|
1432
|
-
candidate.onDestroy();
|
|
1433
|
-
}
|
|
1434
|
-
catch (error) {
|
|
1435
|
-
console.error(error);
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
finally {
|
|
1440
|
-
stopDestroyObserverIfIdle();
|
|
1441
|
-
}
|
|
1442
|
-
});
|
|
1443
|
-
}
|
|
1444
|
-
/**
|
|
1445
|
-
* React usually removes the marker's own parent, and a `childList` observer
|
|
1446
|
-
* never fires for its own removal, so watch from the root down. Removing a
|
|
1447
|
-
* shadow host disconnects the marker without mutating anything inside its
|
|
1448
|
-
* root, so walk up the host chain too.
|
|
1449
|
-
*/
|
|
1450
|
-
for (let root = marker.getRootNode(); root !== null;) {
|
|
1451
|
-
destroyObserver.observe(root, { childList: true, subtree: true });
|
|
1452
|
-
const { host } = root;
|
|
1453
|
-
root = host === undefined ? null : host.getRootNode();
|
|
1454
|
-
}
|
|
1455
|
-
return watch;
|
|
1456
|
-
};
|
|
1457
|
-
const unwatchForDestroy = (watch) => {
|
|
1458
|
-
if (watch === undefined) {
|
|
1459
|
-
return;
|
|
1460
|
-
}
|
|
1461
|
-
destroyWatches.delete(watch);
|
|
1462
|
-
stopDestroyObserverIfIdle();
|
|
1463
|
-
};
|
|
1464
1398
|
const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateHost) => {
|
|
1465
1399
|
if (defineCustomElement) {
|
|
1466
1400
|
defineCustomElement();
|
|
@@ -1472,18 +1406,7 @@ const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateH
|
|
|
1472
1406
|
markerRef;
|
|
1473
1407
|
stableMergedRefs;
|
|
1474
1408
|
portalTarget;
|
|
1475
|
-
|
|
1476
|
-
mountCount = 0;
|
|
1477
|
-
hiddenDestroyWatch;
|
|
1478
|
-
// Where a relocated portaled host sat before `componentWillUnmount` moved
|
|
1479
|
-
// it back into `portalTarget`, so a reveal can put it back.
|
|
1480
|
-
relocatedPortalHost;
|
|
1481
|
-
// React nulls the refs for as long as it keeps this subtree hidden, and a
|
|
1482
|
-
// dismiss can land in that window, so `handleDidDismiss` falls back to these.
|
|
1483
|
-
nodesAtUnmount = null;
|
|
1484
|
-
// Core clears `cachedOriginalParent` when the parent is removed, so the
|
|
1485
|
-
// redirect must not re-run on a reveal and put the reference back.
|
|
1486
|
-
hasRedirectedOriginalParent = false;
|
|
1409
|
+
isUnmounted = false;
|
|
1487
1410
|
constructor(props) {
|
|
1488
1411
|
super(props);
|
|
1489
1412
|
// Create a local ref to to attach props to the wrapped element.
|
|
@@ -1494,6 +1417,8 @@ const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateH
|
|
|
1494
1417
|
this.state = { isOpen: false };
|
|
1495
1418
|
// Create a local ref to the inner child element.
|
|
1496
1419
|
this.wrapperRef = React.createRef();
|
|
1420
|
+
// Marker stays at the JSX location so we can recover the immediate
|
|
1421
|
+
// JSX parent after the overlay has been portaled to ion-app.
|
|
1497
1422
|
this.markerRef = React.createRef();
|
|
1498
1423
|
/**
|
|
1499
1424
|
* Resolve the portal target to the same container CoreDelegate
|
|
@@ -1505,11 +1430,10 @@ const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateH
|
|
|
1505
1430
|
this.portalTarget = typeof document !== 'undefined' ? document.querySelector('ion-app') || document.body : null;
|
|
1506
1431
|
}
|
|
1507
1432
|
componentDidMount() {
|
|
1508
|
-
|
|
1509
|
-
this
|
|
1510
|
-
//
|
|
1511
|
-
this.
|
|
1512
|
-
this.restoreRelocatedPortalHost();
|
|
1433
|
+
// Reset for React 18 StrictMode: the dev-mode unmount/remount cycle
|
|
1434
|
+
// re-uses this instance and leaves the flag set from the prior
|
|
1435
|
+
// componentWillUnmount.
|
|
1436
|
+
this.isUnmounted = false;
|
|
1513
1437
|
this.componentDidUpdate(this.props);
|
|
1514
1438
|
this.ref.current?.addEventListener('ionMount', this.handleIonMount);
|
|
1515
1439
|
this.ref.current?.addEventListener('willPresent', this.handleWillPresent);
|
|
@@ -1520,23 +1444,14 @@ const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateH
|
|
|
1520
1444
|
* child-route passthrough, parent-removal auto-dismiss) walk up
|
|
1521
1445
|
* from `cachedOriginalParent` to find the enclosing `.ion-page`,
|
|
1522
1446
|
* so we redirect it at the marker's JSX parent.
|
|
1523
|
-
*
|
|
1524
|
-
* Nested overlays never portal, so they already cached their
|
|
1525
|
-
* `<template>` at the JSX position and resolve the right `.ion-page`.
|
|
1526
1447
|
*/
|
|
1527
1448
|
const overlay = this.ref.current;
|
|
1528
|
-
|
|
1529
|
-
if (overlay && !this.props.isNested && !this.hasRedirectedOriginalParent) {
|
|
1449
|
+
if (overlay) {
|
|
1530
1450
|
componentOnReady(overlay, () => {
|
|
1531
|
-
|
|
1532
|
-
// Leave the latch open so the reveal can try again.
|
|
1533
|
-
const markerParent = this.markerRef.current?.parentElement ?? null;
|
|
1534
|
-
if (this.mountCount !== generation || markerParent === null) {
|
|
1451
|
+
if (this.isUnmounted)
|
|
1535
1452
|
return;
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
this.hasRedirectedOriginalParent = true;
|
|
1539
|
-
if (markerParent !== this.portalTarget) {
|
|
1453
|
+
const markerParent = this.markerRef.current?.parentElement ?? null;
|
|
1454
|
+
if (markerParent && markerParent !== this.portalTarget) {
|
|
1540
1455
|
overlay.cachedOriginalParent = markerParent;
|
|
1541
1456
|
}
|
|
1542
1457
|
});
|
|
@@ -1554,80 +1469,43 @@ const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateH
|
|
|
1554
1469
|
attachProps(node, cProps, prevProps);
|
|
1555
1470
|
}
|
|
1556
1471
|
componentWillUnmount() {
|
|
1472
|
+
this.isUnmounted = true;
|
|
1557
1473
|
const node = this.ref.current;
|
|
1558
1474
|
if (!node) {
|
|
1559
1475
|
return;
|
|
1560
1476
|
}
|
|
1561
|
-
this.nodesAtUnmount = { host: node, wrapper: this.wrapperRef.current };
|
|
1562
|
-
/**
|
|
1563
|
-
* CoreDelegate (or user code in onWillPresent) can move a portaled
|
|
1564
|
-
* overlay out of `portalTarget`. React's portal `removeChild` runs as
|
|
1565
|
-
* soon as this returns and needs the host where it left it, so this has
|
|
1566
|
-
* to stay synchronous, before we know a hide from a destroy.
|
|
1567
|
-
*/
|
|
1568
|
-
if (node.isConnected && !this.props.isNested && this.portalTarget && node.parentNode !== this.portalTarget) {
|
|
1569
|
-
this.relocatedPortalHost = { node, parent: node.parentNode, nextSibling: node.nextSibling };
|
|
1570
|
-
this.portalTarget.appendChild(node);
|
|
1571
|
-
}
|
|
1572
1477
|
/**
|
|
1573
|
-
*
|
|
1574
|
-
*
|
|
1575
|
-
*
|
|
1576
|
-
*
|
|
1478
|
+
* CoreDelegate (or user code in onWillPresent) can move the overlay out
|
|
1479
|
+
* of where React rendered it. React's unmount only removes the node from
|
|
1480
|
+
* its original React location, so we recover a relocated host here,
|
|
1481
|
+
* regardless of open state.
|
|
1482
|
+
*
|
|
1483
|
+
* We can't gate this on `isOpen`: the overlay can be moved before it
|
|
1484
|
+
* finishes presenting (e.g. the React 18 StrictMode mount/unmount cycle,
|
|
1485
|
+
* where the present events that flip `isOpen` haven't fired yet), which
|
|
1486
|
+
* would orphan the relocated host in the DOM. It also has to run
|
|
1487
|
+
* synchronously here, since React's portal `removeChild` runs after
|
|
1488
|
+
* `componentWillUnmount` returns and needs the host where it expects it.
|
|
1577
1489
|
*/
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1490
|
+
if (node.isConnected) {
|
|
1491
|
+
if (this.props.isNested) {
|
|
1492
|
+
/**
|
|
1493
|
+
* Nested overlays render inline inside a `<template>`. If the host
|
|
1494
|
+
* has been moved out of that template, React's unmount won't reach
|
|
1495
|
+
* it, so remove it directly. A host still in its template is left
|
|
1496
|
+
* for React to remove.
|
|
1497
|
+
*/
|
|
1498
|
+
if (!(node.parentElement instanceof HTMLTemplateElement)) {
|
|
1499
|
+
node.remove();
|
|
1500
|
+
}
|
|
1588
1501
|
}
|
|
1589
|
-
this.
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
const relocated = this.relocatedPortalHost;
|
|
1596
|
-
this.relocatedPortalHost = undefined;
|
|
1597
|
-
if (!relocated || !relocated.parent.isConnected || relocated.node.parentNode !== this.portalTarget) {
|
|
1598
|
-
return;
|
|
1599
|
-
}
|
|
1600
|
-
const { node, parent, nextSibling } = relocated;
|
|
1601
|
-
// The recorded sibling can have moved or been removed while hidden, in
|
|
1602
|
-
// which case appending is the closest we can get.
|
|
1603
|
-
parent.insertBefore(node, nextSibling?.parentNode === parent ? nextSibling : null);
|
|
1604
|
-
}
|
|
1605
|
-
// `cleanupAfterUnmount` decides what to undo. Gating on the state at hide
|
|
1606
|
-
// time would miss an overlay that only starts presenting afterwards.
|
|
1607
|
-
watchForDestroyWhileHidden(marker, node, mountCount) {
|
|
1608
|
-
this.hiddenDestroyWatch = watchForDestroy(marker, () => {
|
|
1609
|
-
this.hiddenDestroyWatch = undefined;
|
|
1610
|
-
// A reveal already happened, so `componentDidMount` owns the teardown.
|
|
1611
|
-
if (this.mountCount !== mountCount) {
|
|
1612
|
-
return;
|
|
1502
|
+
else if (this.portalTarget && node.parentNode !== this.portalTarget) {
|
|
1503
|
+
/**
|
|
1504
|
+
* Portaled overlays: move the host back into `portalTarget` so
|
|
1505
|
+
* React's portal `removeChild` can find it.
|
|
1506
|
+
*/
|
|
1507
|
+
this.portalTarget.appendChild(node);
|
|
1613
1508
|
}
|
|
1614
|
-
this.cleanupAfterUnmount(node);
|
|
1615
|
-
});
|
|
1616
|
-
}
|
|
1617
|
-
stopWatchingForDestroy() {
|
|
1618
|
-
unwatchForDestroy(this.hiddenDestroyWatch);
|
|
1619
|
-
this.hiddenDestroyWatch = undefined;
|
|
1620
|
-
}
|
|
1621
|
-
cleanupAfterUnmount(node) {
|
|
1622
|
-
this.nodesAtUnmount = null;
|
|
1623
|
-
this.relocatedPortalHost = undefined;
|
|
1624
|
-
/**
|
|
1625
|
-
* Nested overlays render inline inside a `<template>`. React's unmount
|
|
1626
|
-
* won't reach a host that has been moved out of one, so remove it here.
|
|
1627
|
-
* A host still in its template is left for React.
|
|
1628
|
-
*/
|
|
1629
|
-
if (this.props.isNested && node.isConnected && !(node.parentElement instanceof HTMLTemplateElement)) {
|
|
1630
|
-
node.remove();
|
|
1631
1509
|
}
|
|
1632
1510
|
/**
|
|
1633
1511
|
* If the overlay is being unmounted, but is still
|
|
@@ -1695,14 +1573,14 @@ const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateH
|
|
|
1695
1573
|
className: getWrapperClasses(),
|
|
1696
1574
|
}, children)
|
|
1697
1575
|
: null));
|
|
1698
|
-
//
|
|
1699
|
-
//
|
|
1700
|
-
//
|
|
1701
|
-
//
|
|
1576
|
+
// Top-level overlays portal into `portalTarget` with a marker
|
|
1577
|
+
// `<template>` at the JSX location to recover the immediate JSX
|
|
1578
|
+
// parent after CoreDelegate teleports. Nested overlays and SSR
|
|
1579
|
+
// fall back to a `<template>` wrapper.
|
|
1702
1580
|
if (!isNested && this.portalTarget) {
|
|
1703
1581
|
return createElement(React.Fragment, null, createElement('template', { ref: this.markerRef }), createPortal(overlayElement, this.portalTarget));
|
|
1704
1582
|
}
|
|
1705
|
-
return createElement('template', {
|
|
1583
|
+
return createElement('template', {}, overlayElement);
|
|
1706
1584
|
}
|
|
1707
1585
|
static get displayName() {
|
|
1708
1586
|
return displayName;
|
|
@@ -1728,20 +1606,18 @@ const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateH
|
|
|
1728
1606
|
this.props.onWillPresent && this.props.onWillPresent(evt);
|
|
1729
1607
|
};
|
|
1730
1608
|
handleDidDismiss = (evt) => {
|
|
1731
|
-
const wrapper = this.wrapperRef.current
|
|
1732
|
-
const el = this.ref.current
|
|
1609
|
+
const wrapper = this.wrapperRef.current;
|
|
1610
|
+
const el = this.ref.current;
|
|
1733
1611
|
/**
|
|
1734
|
-
*
|
|
1735
|
-
*
|
|
1736
|
-
*
|
|
1737
|
-
*
|
|
1612
|
+
* This component might be unmounted already, if the containing
|
|
1613
|
+
* element was removed while the overlay was still open. (For
|
|
1614
|
+
* example, if an item contains an inline overlay with a button
|
|
1615
|
+
* that removes the item.)
|
|
1738
1616
|
*/
|
|
1739
|
-
if (wrapper && el
|
|
1617
|
+
if (wrapper && el) {
|
|
1740
1618
|
el.append(wrapper);
|
|
1619
|
+
this.setState({ isOpen: false });
|
|
1741
1620
|
}
|
|
1742
|
-
// Flip either way, or a dismiss landing while hidden leaves the contents
|
|
1743
|
-
// mounted against a closed overlay on reveal. A no-op after a real unmount.
|
|
1744
|
-
this.setState({ isOpen: false });
|
|
1745
1621
|
this.props.onDidDismiss && this.props.onDidDismiss(evt);
|
|
1746
1622
|
};
|
|
1747
1623
|
};
|