@capacms/sdk 1.0.0-next.8 → 1.0.0-next.9
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/CHANGELOG.md +31 -0
- package/README.md +147 -6
- package/dist/esm/nextjs/overlay.d.ts +30 -0
- package/dist/esm/nextjs/overlay.js +75 -0
- package/dist/esm/overlay/index.d.ts +32 -0
- package/dist/esm/overlay/index.js +510 -0
- package/dist/esm/overlay/protocol.d.ts +134 -0
- package/dist/esm/overlay/protocol.js +173 -0
- package/dist/esm/package.json +4 -0
- package/dist/nextjs/overlay.d.ts +26 -1
- package/dist/nextjs/overlay.js +49 -6
- package/dist/overlay/index.d.ts +14 -2
- package/dist/overlay/index.js +168 -45
- package/package.json +12 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- 1.0.0-next.9. Live preview on sites in production.
|
|
6
|
+
`@capacms/sdk/nextjs/overlay` and `@capacms/sdk/overlay` reach a bundler as
|
|
7
|
+
ES modules (the `import` condition, built to `dist/esm`) and stay CommonJS
|
|
8
|
+
for `require`. The CommonJS overlay's `require("next/navigation")` made
|
|
9
|
+
webpack keep every `next/navigation` export in the module that re-exports
|
|
10
|
+
them, which sits in chunks a visitor loads, so loading the overlay, even
|
|
11
|
+
lazily, changed a site's visitor chunks (17 on one site). An ES
|
|
12
|
+
`import { useRouter }` leaves them as they were.
|
|
13
|
+
- `<CapaOverlay />`: a save's `router.refresh()` runs in a React transition,
|
|
14
|
+
and while it is pending the overlay makes a no-op state update every 300 ms.
|
|
15
|
+
Under React 19.2 and Next 15.5 a draft refresh could stay suspended after
|
|
16
|
+
its whole response had arrived, inside a Suspense boundary already on
|
|
17
|
+
screen (a root `loading.tsx` makes one), and show nothing until some other
|
|
18
|
+
state update. A refresh that has not landed within `refreshTimeoutMs`
|
|
19
|
+
(10 seconds) reloads the page instead, at the same scroll position.
|
|
20
|
+
`refresh="reload"` reloads on every save.
|
|
21
|
+
- `startOverlay`: `onRefresh` may return a promise. The overlay waits for it
|
|
22
|
+
up to `refreshTimeoutMs` and reloads if it rejects or is still pending; a
|
|
23
|
+
function that returns nothing counts as done at once, as before. A reload
|
|
24
|
+
after a failed refresh now keeps the scroll position too. The position is
|
|
25
|
+
held while a refresh is pending, and an editor who scrolls meanwhile is not
|
|
26
|
+
pulled back. `REFRESH_TIMEOUT_MS` is exported.
|
|
27
|
+
- Inside the editor's frame, a ⌘-click (Ctrl-click on Windows and Linux) on a
|
|
28
|
+
tagged element that is a link, or sits inside one, follows the link in the
|
|
29
|
+
frame instead of selecting the field, and the hover label says so. A plain
|
|
30
|
+
click still selects, and an untagged link navigates as before. No message
|
|
31
|
+
between the overlay and the editor changed.
|
|
32
|
+
- Docs: load the overlay lazily from a small client component, since a direct
|
|
33
|
+
import from the root layout puts its code in the layout's chunk, which every
|
|
34
|
+
visitor downloads; and skip a page transition's `FrozenRoute` in draft mode,
|
|
35
|
+
or a save fetches the draft and shows nothing.
|
|
5
36
|
- 1.0.0-next.8. Preview on a live site, in draft mode on its production
|
|
6
37
|
domain. `preview()` takes the legacy key a site already holds (`pk_`, `sk_`
|
|
7
38
|
or unprefixed), as the API does: Capa checks the token with any key that
|
package/README.md
CHANGED
|
@@ -1275,6 +1275,13 @@ editor sees the path without a link to open it.
|
|
|
1275
1275
|
|
|
1276
1276
|
### Quick start (Next.js)
|
|
1277
1277
|
|
|
1278
|
+
Preview needs `@capacms/sdk` 1.0.0-next.8 or later. The `latest` tag is
|
|
1279
|
+
older and has no `capaHeaders`, so install the `next` tag:
|
|
1280
|
+
|
|
1281
|
+
```sh
|
|
1282
|
+
pnpm add @capacms/sdk@next
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1278
1285
|
Set `CAPA_API_URL`, `CAPA_KEY` (`cap_live_`, or the legacy key your site
|
|
1279
1286
|
holds) and `CAPA_DRAFT_KEY` (`cap_test_`). Draft reads through the SDK take a
|
|
1280
1287
|
`cap_` key only (see Keys). Then:
|
|
@@ -1422,11 +1429,45 @@ import { CapaOverlay } from "@capacms/sdk/nextjs/overlay";
|
|
|
1422
1429
|
`@capacms/sdk/overlay` in your own effect.
|
|
1423
1430
|
|
|
1424
1431
|
Render it from your root layout only in edit mode
|
|
1425
|
-
(`await editMode({ draftMode, headers })`), so
|
|
1432
|
+
(`await editMode({ draftMode, headers })`), so it never runs for a visitor.
|
|
1433
|
+
Imported this way, its code still sits in the layout's chunk, which every
|
|
1434
|
+
visitor downloads. To keep it out, load it lazily from a small client
|
|
1435
|
+
component, as step 5 of "Add preview to a live site without changing it"
|
|
1436
|
+
shows. Both overlay entry points reach a bundler as ES modules, so loading
|
|
1437
|
+
the overlay leaves the rest of a visitor's chunks as they were.
|
|
1438
|
+
|
|
1426
1439
|
`startOverlay` returns a disposer and is safe to call twice. Outside a frame it
|
|
1427
1440
|
does nothing at all, and inside one it only listens to a parent window at one of
|
|
1428
|
-
`adminOrigins`.
|
|
1429
|
-
|
|
1441
|
+
`adminOrigins`.
|
|
1442
|
+
|
|
1443
|
+
**Clicks inside the editor's frame.** A click on a tagged element selects its
|
|
1444
|
+
field in the editor. A ⌘-click (Ctrl-click on Windows and Linux) on a tagged
|
|
1445
|
+
element that is a link, or sits inside one, follows the link inside the frame
|
|
1446
|
+
instead, so an editor can move between pages. The hover label says so over a
|
|
1447
|
+
link. A link with no tag on or around it navigates as usual.
|
|
1448
|
+
|
|
1449
|
+
**After a save.** `<CapaOverlay />` re-renders the draft in place with
|
|
1450
|
+
`router.refresh()` and keeps the scroll position.
|
|
1451
|
+
|
|
1452
|
+
- The refresh runs in a React transition. While it is pending, the overlay
|
|
1453
|
+
makes a no-op state update every 300 ms. Under React 19.2 and Next 15.5, a
|
|
1454
|
+
draft refresh can otherwise stay suspended after its whole response has
|
|
1455
|
+
arrived, when the page sits inside a Suspense boundary that is already on
|
|
1456
|
+
screen (a root `loading.tsx` makes one), and show nothing until some other
|
|
1457
|
+
state update.
|
|
1458
|
+
- A refresh that has not landed after `refreshTimeoutMs` (10 seconds) reloads
|
|
1459
|
+
the page instead, which comes back to the same scroll position.
|
|
1460
|
+
- `refresh="reload"` reloads the page on every save, for a site that prefers
|
|
1461
|
+
it:
|
|
1462
|
+
|
|
1463
|
+
```tsx
|
|
1464
|
+
<CapaOverlay adminOrigins={["https://app.capacms.com"]} refresh="reload" />
|
|
1465
|
+
```
|
|
1466
|
+
|
|
1467
|
+
With `startOverlay`, `onRefresh` may return a promise that settles once the new
|
|
1468
|
+
draft is on screen. The overlay waits for it up to `refreshTimeoutMs`, and
|
|
1469
|
+
reloads if it rejects or is still pending. Without `onRefresh` every save
|
|
1470
|
+
reloads. The scroll position is kept every way.
|
|
1430
1471
|
|
|
1431
1472
|
### 3. Accept the preview link on any page
|
|
1432
1473
|
|
|
@@ -1552,11 +1593,31 @@ the same pages, headers and cache as before.
|
|
|
1552
1593
|
4. **Add `capaHeaders()`** to `next.config`'s `headers()`, as in the Quick
|
|
1553
1594
|
start: drafts are marked noindex and only the Capa admin can frame them.
|
|
1554
1595
|
|
|
1555
|
-
5. **Start the overlay and tag fields in draft mode.**
|
|
1596
|
+
5. **Start the overlay and tag fields in draft mode.** Load the overlay
|
|
1597
|
+
lazily from a small client component, so its code is not in a chunk a
|
|
1598
|
+
visitor downloads, and render that component from the root layout in
|
|
1599
|
+
draft mode only:
|
|
1556
1600
|
|
|
1557
1601
|
```tsx
|
|
1602
|
+
// components/capa-preview.tsx
|
|
1603
|
+
"use client";
|
|
1604
|
+
import { lazy, Suspense } from "react";
|
|
1605
|
+
|
|
1606
|
+
const CapaOverlay = lazy(() =>
|
|
1607
|
+
import("@capacms/sdk/nextjs/overlay").then((m) => ({ default: m.CapaOverlay })),
|
|
1608
|
+
);
|
|
1609
|
+
|
|
1610
|
+
export default function CapaPreview({ adminOrigins }: { adminOrigins: string[] }) {
|
|
1611
|
+
return (
|
|
1612
|
+
<Suspense fallback={null}>
|
|
1613
|
+
<CapaOverlay adminOrigins={adminOrigins} />
|
|
1614
|
+
</Suspense>
|
|
1615
|
+
);
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
// app/layout.tsx
|
|
1558
1619
|
const draft = await isDraft();
|
|
1559
|
-
{draft ? <
|
|
1620
|
+
{draft ? <CapaPreview adminOrigins={["https://app.capacms.com"]} /> : null}
|
|
1560
1621
|
```
|
|
1561
1622
|
|
|
1562
1623
|
Tag an editable field with `{...capaAttrs({ id: entry.id }, "title", draft)}`.
|
|
@@ -1576,9 +1637,85 @@ Published view then shows the static page without the overlay.
|
|
|
1576
1637
|
In Capa, set the project's preview URL to the site's production origin, and
|
|
1577
1638
|
give each model with a page a route pattern, or Preview has no link to open.
|
|
1578
1639
|
|
|
1640
|
+
### A save that shows nothing: a page transition that freezes the route
|
|
1641
|
+
|
|
1642
|
+
A site that animates page changes with framer-motion often wraps each page in
|
|
1643
|
+
a `FrozenRoute`, which pins Next's `LayoutRouterContext` so the page that is
|
|
1644
|
+
leaving keeps its content while it animates out:
|
|
1645
|
+
|
|
1646
|
+
```tsx
|
|
1647
|
+
"use client";
|
|
1648
|
+
|
|
1649
|
+
import { useContext, useRef } from "react";
|
|
1650
|
+
import { LayoutRouterContext } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
|
1651
|
+
|
|
1652
|
+
const FrozenRoute = ({ children }: { children: React.ReactNode }) => {
|
|
1653
|
+
const context = useContext(LayoutRouterContext);
|
|
1654
|
+
const frozen = useRef(context).current;
|
|
1655
|
+
|
|
1656
|
+
return (
|
|
1657
|
+
<LayoutRouterContext.Provider value={frozen}>
|
|
1658
|
+
{children}
|
|
1659
|
+
</LayoutRouterContext.Provider>
|
|
1660
|
+
);
|
|
1661
|
+
};
|
|
1662
|
+
|
|
1663
|
+
export default FrozenRoute;
|
|
1664
|
+
```
|
|
1665
|
+
|
|
1666
|
+
The pinned context keeps the page as the frame first drew it. After a save,
|
|
1667
|
+
`router.refresh()` fetches the draft and nothing on screen changes, and no
|
|
1668
|
+
overlay setting can reach inside the freeze. Skip it in draft mode only. Give
|
|
1669
|
+
the page-transition wrapper a `live` prop:
|
|
1670
|
+
|
|
1671
|
+
```tsx
|
|
1672
|
+
"use client";
|
|
1673
|
+
|
|
1674
|
+
import { usePathname } from "next/navigation";
|
|
1675
|
+
import { AnimatePresence, motion } from "framer-motion";
|
|
1676
|
+
import FrozenRoute from "./frozen-route";
|
|
1677
|
+
|
|
1678
|
+
const PageAnimatePresence = ({
|
|
1679
|
+
children,
|
|
1680
|
+
live,
|
|
1681
|
+
}: {
|
|
1682
|
+
children: React.ReactNode;
|
|
1683
|
+
/** Capa preview (draft mode only): no freeze, so an editor's save shows in place. */
|
|
1684
|
+
live?: boolean;
|
|
1685
|
+
}) => {
|
|
1686
|
+
const pathname = usePathname();
|
|
1687
|
+
|
|
1688
|
+
return (
|
|
1689
|
+
<AnimatePresence mode="wait">
|
|
1690
|
+
<motion.div className="flex flex-col flex-grow" key={pathname}>
|
|
1691
|
+
{live ? children : <FrozenRoute>{children}</FrozenRoute>}
|
|
1692
|
+
</motion.div>
|
|
1693
|
+
</AnimatePresence>
|
|
1694
|
+
);
|
|
1695
|
+
};
|
|
1696
|
+
|
|
1697
|
+
export default PageAnimatePresence;
|
|
1698
|
+
```
|
|
1699
|
+
|
|
1700
|
+
and pass it from the root layout as a conditional spread, so a visitor's
|
|
1701
|
+
props, and the RSC payload that carries them, are exactly what they were:
|
|
1702
|
+
|
|
1703
|
+
```tsx
|
|
1704
|
+
// app/layout.tsx
|
|
1705
|
+
const draft = await isDraft();
|
|
1706
|
+
|
|
1707
|
+
<PageAnimatePresence {...(draft ? { live: true } : {})}>
|
|
1708
|
+
{children}
|
|
1709
|
+
</PageAnimatePresence>
|
|
1710
|
+
```
|
|
1711
|
+
|
|
1712
|
+
Writing `live={draft}` instead would send `live: false` to every visitor.
|
|
1713
|
+
To find the freeze, search the site for `LayoutRouterContext`.
|
|
1714
|
+
|
|
1579
1715
|
### The protocol
|
|
1580
1716
|
|
|
1581
|
-
Every message is `{ source, v: 1, type, ...fields }`.
|
|
1717
|
+
Every message is `{ source, v: 1, type, ...fields }`. `source` is
|
|
1718
|
+
`capa-admin` on the admin's messages and `capa` on the site's. The admin sends
|
|
1582
1719
|
`hello`, `highlight { entryId, field }` (`entryId: ""` clears), `outline { on }`
|
|
1583
1720
|
and `refresh`. The site answers `ready { path, entries }` after every hello and
|
|
1584
1721
|
every navigation, `select { entryId, field }` on a click, and `hover`.
|
|
@@ -1593,6 +1730,10 @@ and at the very bottom the bottommost. The editor's "Follow the page" scrolls
|
|
|
1593
1730
|
the form to that field. An overlay older than 1.0.0-next.2 never sends it, and
|
|
1594
1731
|
the editor then does not follow.
|
|
1595
1732
|
|
|
1733
|
+
Following a link with ⌘-click sends no message of its own: the page the link
|
|
1734
|
+
leads to answers with `ready`, as after any navigation, so an editor of any
|
|
1735
|
+
version follows along.
|
|
1736
|
+
|
|
1596
1737
|
## Not yet
|
|
1597
1738
|
|
|
1598
1739
|
`--select-from-depth`, `capa convert-url`, GraphQL mutations, and `/api/`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface CapaOverlayProps {
|
|
2
|
+
/** The Capa admin origins allowed to drive the overlay. */
|
|
3
|
+
adminOrigins: string[];
|
|
4
|
+
/**
|
|
5
|
+
* How a save shows. `"in-place"` (the default) re-renders the draft with
|
|
6
|
+
* `router.refresh()`, and reloads the page only if that has not landed
|
|
7
|
+
* within `refreshTimeoutMs`. `"reload"` reloads the page on every save.
|
|
8
|
+
* The scroll position is kept either way.
|
|
9
|
+
*/
|
|
10
|
+
refresh?: "in-place" | "reload";
|
|
11
|
+
/** How long an in-place refresh may take before the page reloads instead. 10 seconds. */
|
|
12
|
+
refreshTimeoutMs?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The refresh runs in a transition, so `isPending` says when the new draft
|
|
16
|
+
* has been committed to the screen, and the overlay settles the refresh
|
|
17
|
+
* then: it puts the scroll position back, and a refresh that has not
|
|
18
|
+
* committed within `refreshTimeoutMs` reloads.
|
|
19
|
+
*
|
|
20
|
+
* While the transition is pending the overlay makes a no-op state update
|
|
21
|
+
* every `REFRESH_NUDGE_MS`. React 19.2 under Next 15.5 can leave a draft
|
|
22
|
+
* refresh suspended after every part of its streamed response has arrived:
|
|
23
|
+
* the page suspends inside an already visible Suspense boundary (a root
|
|
24
|
+
* `loading.tsx` makes one around every page), and the signal that its data
|
|
25
|
+
* is ready is lost, so nothing commits until some other state update. Any
|
|
26
|
+
* state update makes React retry the suspended render, which then completes.
|
|
27
|
+
* A refresh that commits on its own stops the nudges at once. Draft mode
|
|
28
|
+
* only: a visitor never runs this component.
|
|
29
|
+
*/
|
|
30
|
+
export declare function CapaOverlay({ adminOrigins, refresh, refreshTimeoutMs }: CapaOverlayProps): null;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* `<CapaOverlay />`: Capa's live preview overlay as one Next.js client
|
|
4
|
+
* component (M6).
|
|
5
|
+
*
|
|
6
|
+
* // app/layout.tsx (a server component)
|
|
7
|
+
* import { CapaOverlay } from "@capacms/sdk/nextjs/overlay";
|
|
8
|
+
* {edit ? <CapaOverlay adminOrigins={["https://app.capacms.com"]} /> : null}
|
|
9
|
+
*
|
|
10
|
+
* Render it only in edit mode (`editMode()` from `@capacms/sdk/nextjs`), so a
|
|
11
|
+
* visitor never downloads it. Inside the Capa editor it outlines the focused
|
|
12
|
+
* field, reports clicks back, and on a save re-renders the page with
|
|
13
|
+
* `router.refresh()`, keeping the scroll position. Outside a Capa frame it does
|
|
14
|
+
* nothing at all.
|
|
15
|
+
*
|
|
16
|
+
* Its own entry point, apart from `@capacms/sdk/nextjs`, because it imports
|
|
17
|
+
* `react` and `next/navigation` and is a client module: the server helpers must
|
|
18
|
+
* stay free of both. A bundler that imports it gets an ES module, so it sees
|
|
19
|
+
* that only `useRouter` is used from `next/navigation` and leaves the chunks a
|
|
20
|
+
* visitor loads as they were.
|
|
21
|
+
*/
|
|
22
|
+
import { useEffect, useRef, useState, useTransition } from "react";
|
|
23
|
+
import { useRouter } from "next/navigation";
|
|
24
|
+
import { startOverlay } from "../overlay/index.js";
|
|
25
|
+
/**
|
|
26
|
+
* While a refresh is pending, the overlay updates its own unused state this
|
|
27
|
+
* often. See `CapaOverlay` for why.
|
|
28
|
+
*/
|
|
29
|
+
const REFRESH_NUDGE_MS = 300;
|
|
30
|
+
/**
|
|
31
|
+
* The refresh runs in a transition, so `isPending` says when the new draft
|
|
32
|
+
* has been committed to the screen, and the overlay settles the refresh
|
|
33
|
+
* then: it puts the scroll position back, and a refresh that has not
|
|
34
|
+
* committed within `refreshTimeoutMs` reloads.
|
|
35
|
+
*
|
|
36
|
+
* While the transition is pending the overlay makes a no-op state update
|
|
37
|
+
* every `REFRESH_NUDGE_MS`. React 19.2 under Next 15.5 can leave a draft
|
|
38
|
+
* refresh suspended after every part of its streamed response has arrived:
|
|
39
|
+
* the page suspends inside an already visible Suspense boundary (a root
|
|
40
|
+
* `loading.tsx` makes one around every page), and the signal that its data
|
|
41
|
+
* is ready is lost, so nothing commits until some other state update. Any
|
|
42
|
+
* state update makes React retry the suspended render, which then completes.
|
|
43
|
+
* A refresh that commits on its own stops the nudges at once. Draft mode
|
|
44
|
+
* only: a visitor never runs this component.
|
|
45
|
+
*/
|
|
46
|
+
export function CapaOverlay({ adminOrigins, refresh = "in-place", refreshTimeoutMs }) {
|
|
47
|
+
const router = useRouter();
|
|
48
|
+
const [refreshing, startRefresh] = useTransition();
|
|
49
|
+
const [, nudge] = useState(0);
|
|
50
|
+
/** One resolver per refresh waiting for its transition to commit. */
|
|
51
|
+
const waiting = useRef([]);
|
|
52
|
+
// A string, so a new array with the same origins does not restart it.
|
|
53
|
+
const origins = adminOrigins.join(",");
|
|
54
|
+
useEffect(() => startOverlay({
|
|
55
|
+
adminOrigins: origins.split(",").filter(Boolean),
|
|
56
|
+
onRefresh: refresh === "reload"
|
|
57
|
+
? undefined
|
|
58
|
+
: () => new Promise((resolve) => {
|
|
59
|
+
waiting.current.push(resolve);
|
|
60
|
+
startRefresh(() => router.refresh());
|
|
61
|
+
}),
|
|
62
|
+
refreshTimeoutMs,
|
|
63
|
+
}), [origins, router, refresh, refreshTimeoutMs]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!refreshing) {
|
|
66
|
+
// Committed: every refresh started before now is on screen.
|
|
67
|
+
for (const settle of waiting.current.splice(0))
|
|
68
|
+
settle();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const timer = window.setInterval(() => nudge((n) => n + 1), REFRESH_NUDGE_MS);
|
|
72
|
+
return () => window.clearInterval(timer);
|
|
73
|
+
}, [refreshing]);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export { acceptMessage, hoverMessage, normaliseOrigins, pickCentred, readyMessage, scrollEdge, selectMessage, visibleMessage, ADMIN_SOURCE, PROTOCOL_VERSION, SITE_SOURCE, } from "./protocol.js";
|
|
2
|
+
export type { AdminMessage, MessageLike, SiteMessage, TaggedBox } from "./protocol.js";
|
|
3
|
+
export interface OverlayOptions {
|
|
4
|
+
/**
|
|
5
|
+
* The Capa admin origins allowed to drive this page, for example
|
|
6
|
+
* `["https://app.capacms.com"]`. A message from anywhere else is ignored.
|
|
7
|
+
*/
|
|
8
|
+
adminOrigins: string[];
|
|
9
|
+
/**
|
|
10
|
+
* How to re-render the draft after the editor saves. `router.refresh()` in a
|
|
11
|
+
* Next app. Without it the page reloads. Scroll position is kept either way.
|
|
12
|
+
*
|
|
13
|
+
* Return a promise that settles once the new draft is on screen, and the
|
|
14
|
+
* overlay waits for it: a promise that rejects, or is still pending after
|
|
15
|
+
* `refreshTimeoutMs`, falls back to a reload, which keeps the scroll
|
|
16
|
+
* position too. A function that returns nothing counts as done at once.
|
|
17
|
+
*/
|
|
18
|
+
onRefresh?: () => void | Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* How long `onRefresh`'s promise may stay pending before the page reloads
|
|
21
|
+
* instead. 10 seconds.
|
|
22
|
+
*/
|
|
23
|
+
refreshTimeoutMs?: number;
|
|
24
|
+
}
|
|
25
|
+
/** How long an in-place refresh may take before the page reloads instead. */
|
|
26
|
+
export declare const REFRESH_TIMEOUT_MS = 10000;
|
|
27
|
+
/**
|
|
28
|
+
* Start the overlay. Returns a disposer that removes every listener and the
|
|
29
|
+
* drawing layer. Calling it again while it runs updates the options and returns
|
|
30
|
+
* the same disposer, so a React effect that runs twice does not listen twice.
|
|
31
|
+
*/
|
|
32
|
+
export declare function startOverlay(options: OverlayOptions): () => void;
|