@proappstore/sdk 1.16.56 → 1.16.58
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/README.md +41 -17
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/navbar-css.d.ts +13 -0
- package/dist/navbar-css.d.ts.map +1 -0
- package/dist/navbar-css.js +21 -0
- package/dist/navbar-css.js.map +1 -0
- package/dist/navbar.d.ts +46 -0
- package/dist/navbar.d.ts.map +1 -0
- package/dist/navbar.js +90 -0
- package/dist/navbar.js.map +1 -0
- package/dist/page.d.ts +27 -0
- package/dist/page.d.ts.map +1 -0
- package/dist/page.js +27 -0
- package/dist/page.js.map +1 -0
- package/dist/shell-css.d.ts +8 -0
- package/dist/shell-css.d.ts.map +1 -0
- package/dist/shell-css.js +28 -0
- package/dist/shell-css.js.map +1 -0
- package/dist/shell-resilience.d.ts +89 -0
- package/dist/shell-resilience.d.ts.map +1 -0
- package/dist/shell-resilience.js +178 -0
- package/dist/shell-resilience.js.map +1 -0
- package/dist/shell.css +28 -0
- package/dist/shell.d.ts +45 -3
- package/dist/shell.d.ts.map +1 -1
- package/dist/shell.js +53 -6
- package/dist/shell.js.map +1 -1
- package/dist/ui.d.ts +6 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +5 -0
- package/dist/ui.js.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -571,17 +571,23 @@ Pass `{ allowFree: true }` to skip the subscription check (lets free users throu
|
|
|
571
571
|
|
|
572
572
|
## ProShell Component
|
|
573
573
|
|
|
574
|
-
|
|
574
|
+
The app frame. It handles the auth gates, subscription checks, provider context, the topbar (app name, text size control, user menu), the footer, and the **main navigation**.
|
|
575
575
|
|
|
576
576
|
```tsx
|
|
577
|
-
import { initPro } from '@proappstore/sdk'
|
|
578
|
-
import { ProShell } from '@proappstore/sdk/shell'
|
|
577
|
+
import { initPro, ProShell } from '@proappstore/sdk'
|
|
579
578
|
|
|
580
579
|
const app = initPro({ appId: 'meetup' })
|
|
581
580
|
|
|
582
581
|
export default function App() {
|
|
583
582
|
return (
|
|
584
|
-
<ProShell
|
|
583
|
+
<ProShell
|
|
584
|
+
app={app}
|
|
585
|
+
appName="Meetup"
|
|
586
|
+
nav={[
|
|
587
|
+
{ label: 'Events', href: '/' },
|
|
588
|
+
{ label: 'Groups', href: '/groups' },
|
|
589
|
+
]}
|
|
590
|
+
>
|
|
585
591
|
<MeetupApp />
|
|
586
592
|
</ProShell>
|
|
587
593
|
)
|
|
@@ -595,32 +601,50 @@ Props:
|
|
|
595
601
|
| `app` | `ProAppStore` | SDK instance from `initPro()` |
|
|
596
602
|
| `children` | `ReactNode` | App content (rendered only when gates pass) |
|
|
597
603
|
| `appName` | `string?` | Name shown in the topbar |
|
|
604
|
+
| `nav` | `{ label: string; href: string; icon?: ReactNode; title?: string }[]` | **The app's screens**, rendered as the main navigation in the topbar |
|
|
605
|
+
| `onNavigate` | `(href: string) => void` | Client-side navigation for nav clicks (e.g. a router's `navigate`); without it items are links |
|
|
606
|
+
| `renderNav` | `(ctx) => ReactNode` | Replace the built-in NavBar (`ctx`: `items`, `currentPath`, `onNavigate`) |
|
|
598
607
|
| `allowFree` | `boolean?` | Skip subscription gate (default: `true` until platform billing is live) |
|
|
599
608
|
| `showThemeToggle` | `boolean?` | Show theme toggle in the profile menu |
|
|
600
609
|
| `menuItems` | `{ label: string; onClick: () => void }[]` | Extra profile dropdown items |
|
|
601
|
-
| `hideTopbar` | `boolean?` | Omit the default topbar |
|
|
610
|
+
| `hideTopbar` | `boolean?` | Omit the default topbar (and the navigation) |
|
|
602
611
|
| `hideFooter` | `boolean?` | Omit the default footer |
|
|
603
|
-
| `renderTopbar` | `(ctx) => ReactNode` | Replace the default topbar |
|
|
612
|
+
| `renderTopbar` | `(ctx) => ReactNode` | Replace the default topbar; place `ctx.nav` in it |
|
|
604
613
|
| `renderFooter` | `(ctx) => ReactNode` | Replace the default footer |
|
|
614
|
+
| `renderError` | `({ error, reset }) => ReactNode` | Replace the error-boundary fallback (errors are recorded via `app.logs`) |
|
|
615
|
+
| `renderLoading` | `() => ReactNode` | Replace the spinner shown while a lazy screen loads |
|
|
605
616
|
|
|
606
617
|
ProShell handles:
|
|
607
|
-
- Auth initialization and sign-in gate
|
|
608
|
-
-
|
|
609
|
-
-
|
|
610
|
-
|
|
611
|
-
|
|
618
|
+
- Auth initialization and the sign-in gate
|
|
619
|
+
- The subscription check and upgrade wall (unless `allowFree=true`)
|
|
620
|
+
- The topbar with app name, text size toggle and user menu (sign out, manage billing, delete account)
|
|
621
|
+
- The main navigation from `nav`:
|
|
622
|
+
- a `<nav aria-label="Main">` landmark;
|
|
623
|
+
- `aria-current="page"` on the current route, following `location.pathname` and back/forward;
|
|
624
|
+
- a menu button below 640 px (`aria-expanded`, Escape to close);
|
|
625
|
+
- 44 px targets and visible focus.
|
|
626
|
+
|
|
627
|
+
Its styles are injected when the navbar renders, so no setup is needed. They are also available as `@proappstore/sdk/shell.css`.
|
|
628
|
+
- Resilience and feedback:
|
|
629
|
+
- an error boundary (with a Try again fallback, errors recorded via `app.logs`) and a Suspense spinner around the content;
|
|
630
|
+
- `useToast()` for messages in one polite live region;
|
|
631
|
+
- an offline banner, plus `useOnline()`;
|
|
632
|
+
- tab titles from a nav item's `title` or `useDocumentTitle`;
|
|
633
|
+
- `PageHeader` for each screen's one `h1`;
|
|
634
|
+
- a skip link to `<main id="main">`;
|
|
635
|
+
- with `onNavigate`, scroll to top or restore on back/forward, and focus moved to the new screen's heading.
|
|
636
|
+
|
|
637
|
+
Do not build navigation into a page, and do not stack a second navbar under the shell. A custom topbar keeps the gates and places the rendered `nav`:
|
|
612
638
|
|
|
613
639
|
```tsx
|
|
614
640
|
<ProShell
|
|
615
641
|
app={app}
|
|
616
642
|
appName="Chess Academy"
|
|
617
|
-
|
|
643
|
+
nav={[{ label: 'Students', href: '/students' }, { label: 'Tournaments', href: '/tournaments' }]}
|
|
644
|
+
renderTopbar={({ appName, nav, profileMenu, textSizeToggle }) => (
|
|
618
645
|
<header className="top-nav">
|
|
619
646
|
<a href="/">{appName}</a>
|
|
620
|
-
|
|
621
|
-
<a href="/students">Students</a>
|
|
622
|
-
<a href="/tournaments">Tournaments</a>
|
|
623
|
-
</nav>
|
|
647
|
+
{nav}
|
|
624
648
|
{textSizeToggle}
|
|
625
649
|
{profileMenu}
|
|
626
650
|
</header>
|
|
@@ -630,7 +654,7 @@ Apps with their own primary navigation should not stack a second navbar under th
|
|
|
630
654
|
</ProShell>
|
|
631
655
|
```
|
|
632
656
|
|
|
633
|
-
For a fully custom layout, use `<ProShell app={app} hideTopbar hideFooter>` and compose `ProfileMenu`, `SignInButton`, `GateScreen`, and hooks from `@proappstore/sdk/ui` and `@proappstore/sdk/hooks`.
|
|
657
|
+
For a fully custom layout, use `<ProShell app={app} hideTopbar hideFooter>` and compose `NavBar`, `ProfileMenu`, `SignInButton`, `GateScreen`, and hooks from `@proappstore/sdk/ui` and `@proappstore/sdk/hooks`.
|
|
634
658
|
|
|
635
659
|
## UI Components
|
|
636
660
|
|
package/dist/index.d.ts
CHANGED
|
@@ -47,7 +47,13 @@ export { useProAuth, useProSubscription, useProGate, useProNotifications } from
|
|
|
47
47
|
export { ProProvider, useApp } from './provider.js';
|
|
48
48
|
export type { ProProviderProps } from './provider.js';
|
|
49
49
|
export { ProShell } from './shell.js';
|
|
50
|
-
export type { ProShellProps, ProShellRenderContext, MenuItem } from './shell.js';
|
|
50
|
+
export type { ProShellProps, ProShellRenderContext, ProShellNavContext, MenuItem, ShellErrorContext } from './shell.js';
|
|
51
|
+
export { useToast, useOnline } from './shell-resilience.js';
|
|
52
|
+
export type { ToastApi, ToastOptions, ShellToastVariant } from './shell-resilience.js';
|
|
53
|
+
export { PageHeader, useDocumentTitle } from './page.js';
|
|
54
|
+
export type { PageHeaderProps } from './page.js';
|
|
55
|
+
export { NavBar } from './navbar.js';
|
|
56
|
+
export type { NavBarProps, NavItem } from './navbar.js';
|
|
51
57
|
export { Avatar, ThemeToggle, TextSizeToggle, SignInButton, ProfileMenu, ProBadge, SubscriptionStatus, UpgradeCard, BillingButton, GateScreen, ProProfilePage, } from './ui.js';
|
|
52
58
|
/**
|
|
53
59
|
* Pro SDK instance — all features hit the PAS backend.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,9 @@ export { useAuth, useSubscription, useGate, useNotifications, useTheme } from '.
|
|
|
36
36
|
export { useProAuth, useProSubscription, useProGate, useProNotifications } from './hooks.js';
|
|
37
37
|
export { ProProvider, useApp } from './provider.js';
|
|
38
38
|
export { ProShell } from './shell.js';
|
|
39
|
+
export { useToast, useOnline } from './shell-resilience.js';
|
|
40
|
+
export { PageHeader, useDocumentTitle } from './page.js';
|
|
41
|
+
export { NavBar } from './navbar.js';
|
|
39
42
|
export { Avatar, ThemeToggle, TextSizeToggle, SignInButton, ProfileMenu, ProBadge, SubscriptionStatus, UpgradeCard, BillingButton, GateScreen, ProProfilePage, } from './ui.js';
|
|
40
43
|
/**
|
|
41
44
|
* Pro SDK instance — all features hit the PAS backend.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavBar styles (#235) — the single source for both delivery paths:
|
|
3
|
+
* NavBar injects this into <head> at render (so an app needs no configuration),
|
|
4
|
+
* and the build writes it to dist/shell.css (`@proappstore/sdk/shell.css`) for
|
|
5
|
+
* apps that prefer to import it.
|
|
6
|
+
*
|
|
7
|
+
* Built on the canonical tokens only (PAS-UI-001), so it follows the app's
|
|
8
|
+
* light/dark theme. The Tailwind classes on NavBar's elements mirror these
|
|
9
|
+
* rules; Tailwind v4 emits utilities inside a cascade layer, so these unlayered
|
|
10
|
+
* rules win wherever the two meet and they cannot disagree.
|
|
11
|
+
*/
|
|
12
|
+
export declare const NAVBAR_CSS = ".pas-nav{position:relative;display:flex;align-items:center;flex:1 1 auto;min-width:0;margin:0 .5rem}\n.pas-nav__toggle{display:none;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0;border:1px solid var(--line);border-radius:10px;background:transparent;color:var(--ink);font:inherit;cursor:pointer}\n.pas-nav__list{display:flex;align-items:center;gap:.25rem;margin:0;padding:0;list-style:none;overflow-x:auto}\n.pas-nav__link{display:inline-flex;align-items:center;gap:.4rem;min-height:44px;padding:0 .75rem;border-radius:10px;color:var(--muted);font-size:.9rem;font-weight:600;text-decoration:none;white-space:nowrap}\n.pas-nav__link:hover{color:var(--ink);background:var(--line)}\n.pas-nav__link[aria-current=\"page\"]{color:var(--accent);background:var(--line)}\n.pas-nav__toggle:focus-visible,.pas-nav__link:focus-visible{outline:2px solid var(--accent);outline-offset:2px}\n@media (max-width:639px){.pas-nav{flex:0 0 auto;margin:0}.pas-nav__toggle{display:inline-flex}.pas-nav__list{display:none;position:absolute;top:calc(100% + .5rem);left:0;z-index:60;flex-direction:column;align-items:stretch;min-width:12rem;padding:.5rem;overflow:visible;background:var(--paper);border:1px solid var(--line);border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.12)}.pas-nav[data-open=\"true\"] .pas-nav__list{display:flex}}\n";
|
|
13
|
+
//# sourceMappingURL=navbar-css.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navbar-css.d.ts","sourceRoot":"","sources":["../src/navbar-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,60CAQtB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavBar styles (#235) — the single source for both delivery paths:
|
|
3
|
+
* NavBar injects this into <head> at render (so an app needs no configuration),
|
|
4
|
+
* and the build writes it to dist/shell.css (`@proappstore/sdk/shell.css`) for
|
|
5
|
+
* apps that prefer to import it.
|
|
6
|
+
*
|
|
7
|
+
* Built on the canonical tokens only (PAS-UI-001), so it follows the app's
|
|
8
|
+
* light/dark theme. The Tailwind classes on NavBar's elements mirror these
|
|
9
|
+
* rules; Tailwind v4 emits utilities inside a cascade layer, so these unlayered
|
|
10
|
+
* rules win wherever the two meet and they cannot disagree.
|
|
11
|
+
*/
|
|
12
|
+
export const NAVBAR_CSS = `.pas-nav{position:relative;display:flex;align-items:center;flex:1 1 auto;min-width:0;margin:0 .5rem}
|
|
13
|
+
.pas-nav__toggle{display:none;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0;border:1px solid var(--line);border-radius:10px;background:transparent;color:var(--ink);font:inherit;cursor:pointer}
|
|
14
|
+
.pas-nav__list{display:flex;align-items:center;gap:.25rem;margin:0;padding:0;list-style:none;overflow-x:auto}
|
|
15
|
+
.pas-nav__link{display:inline-flex;align-items:center;gap:.4rem;min-height:44px;padding:0 .75rem;border-radius:10px;color:var(--muted);font-size:.9rem;font-weight:600;text-decoration:none;white-space:nowrap}
|
|
16
|
+
.pas-nav__link:hover{color:var(--ink);background:var(--line)}
|
|
17
|
+
.pas-nav__link[aria-current="page"]{color:var(--accent);background:var(--line)}
|
|
18
|
+
.pas-nav__toggle:focus-visible,.pas-nav__link:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
|
19
|
+
@media (max-width:639px){.pas-nav{flex:0 0 auto;margin:0}.pas-nav__toggle{display:inline-flex}.pas-nav__list{display:none;position:absolute;top:calc(100% + .5rem);left:0;z-index:60;flex-direction:column;align-items:stretch;min-width:12rem;padding:.5rem;overflow:visible;background:var(--paper);border:1px solid var(--line);border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.12)}.pas-nav[data-open="true"] .pas-nav__list{display:flex}}
|
|
20
|
+
`;
|
|
21
|
+
//# sourceMappingURL=navbar-css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navbar-css.js","sourceRoot":"","sources":["../src/navbar-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;CAQzB,CAAC"}
|
package/dist/navbar.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/** One screen in the app's main navigation. */
|
|
3
|
+
export interface NavItem {
|
|
4
|
+
label: string;
|
|
5
|
+
/** Same-origin path, e.g. `/` or `/cases`. */
|
|
6
|
+
href: string;
|
|
7
|
+
/** Optional icon, rendered before the label (mark it `aria-hidden`). */
|
|
8
|
+
icon?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Tab title while this item's route is current (#236, PAS-UI-003). ProShell
|
|
11
|
+
* applies it; a screen's own `useDocumentTitle` overrides it.
|
|
12
|
+
*/
|
|
13
|
+
title?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface NavBarProps {
|
|
16
|
+
items: NavItem[];
|
|
17
|
+
/**
|
|
18
|
+
* The route to mark as current. Defaults to `location.pathname`, kept in
|
|
19
|
+
* step with back/forward (`popstate`). Pass your router's location when you
|
|
20
|
+
* use one.
|
|
21
|
+
*/
|
|
22
|
+
currentPath?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Client-side navigation: called instead of a full page load on a plain
|
|
25
|
+
* left click. Without it the items are ordinary links.
|
|
26
|
+
*/
|
|
27
|
+
onNavigate?: (href: string) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The browser's current path, following back/forward. `initial` wins when
|
|
31
|
+
* given (router-driven apps, server rendering).
|
|
32
|
+
*/
|
|
33
|
+
export declare function useCurrentPath(initial?: string): [string, (path: string) => void];
|
|
34
|
+
/** The item to mark current: an exact match, else the longest prefix (`/cases` for `/cases/42`). */
|
|
35
|
+
export declare function activeHref(items: NavItem[], path: string): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* NavBar (#235) — the app's main navigation, rendered by ProShell's topbar
|
|
38
|
+
* from its `nav` prop, and usable on its own in a custom topbar.
|
|
39
|
+
*
|
|
40
|
+
* `<nav aria-label="Main">` landmark (PAS-UI-003), `aria-current="page"` on the
|
|
41
|
+
* current item, 44 px targets (PAS-UI-009), visible focus, and below 640 px a
|
|
42
|
+
* menu button (`aria-expanded` / `aria-controls`; Escape or a click outside
|
|
43
|
+
* closes it and returns focus). Renders nothing when there are no items.
|
|
44
|
+
*/
|
|
45
|
+
export declare function NavBar({ items, currentPath, onNavigate }: NavBarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
46
|
+
//# sourceMappingURL=navbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navbar.d.ts","sourceRoot":"","sources":["../src/navbar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2E,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGhH,+CAA+C;AAC/C,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,CAYjF;AAED,oGAAoG;AACpG,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOxE;AAYD;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,WAAW,kDAmErE"}
|
package/dist/navbar.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useInsertionEffect, useRef, useState } from 'react';
|
|
3
|
+
import { NAVBAR_CSS } from './navbar-css.js';
|
|
4
|
+
/**
|
|
5
|
+
* The browser's current path, following back/forward. `initial` wins when
|
|
6
|
+
* given (router-driven apps, server rendering).
|
|
7
|
+
*/
|
|
8
|
+
export function useCurrentPath(initial) {
|
|
9
|
+
const [path, setPath] = useState(() => initial ?? (typeof window === 'undefined' ? '/' : window.location.pathname));
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (initial !== undefined) {
|
|
12
|
+
setPath(initial);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const sync = () => setPath(window.location.pathname);
|
|
16
|
+
window.addEventListener('popstate', sync);
|
|
17
|
+
return () => window.removeEventListener('popstate', sync);
|
|
18
|
+
}, [initial]);
|
|
19
|
+
return [path, setPath];
|
|
20
|
+
}
|
|
21
|
+
/** The item to mark current: an exact match, else the longest prefix (`/cases` for `/cases/42`). */
|
|
22
|
+
export function activeHref(items, path) {
|
|
23
|
+
let best = null;
|
|
24
|
+
for (const { href } of items) {
|
|
25
|
+
const matches = href === path || (href !== '/' && path.startsWith(`${href.replace(/\/+$/, '')}/`));
|
|
26
|
+
if (matches && (best === null || href.length > best.length))
|
|
27
|
+
best = href;
|
|
28
|
+
}
|
|
29
|
+
return best;
|
|
30
|
+
}
|
|
31
|
+
function useNavbarStyles() {
|
|
32
|
+
useInsertionEffect(() => {
|
|
33
|
+
if (document.getElementById('pas-nav-css'))
|
|
34
|
+
return;
|
|
35
|
+
const style = document.createElement('style');
|
|
36
|
+
style.id = 'pas-nav-css';
|
|
37
|
+
style.textContent = NAVBAR_CSS;
|
|
38
|
+
document.head.appendChild(style);
|
|
39
|
+
}, []);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* NavBar (#235) — the app's main navigation, rendered by ProShell's topbar
|
|
43
|
+
* from its `nav` prop, and usable on its own in a custom topbar.
|
|
44
|
+
*
|
|
45
|
+
* `<nav aria-label="Main">` landmark (PAS-UI-003), `aria-current="page"` on the
|
|
46
|
+
* current item, 44 px targets (PAS-UI-009), visible focus, and below 640 px a
|
|
47
|
+
* menu button (`aria-expanded` / `aria-controls`; Escape or a click outside
|
|
48
|
+
* closes it and returns focus). Renders nothing when there are no items.
|
|
49
|
+
*/
|
|
50
|
+
export function NavBar({ items, currentPath, onNavigate }) {
|
|
51
|
+
useNavbarStyles();
|
|
52
|
+
const [path, setPath] = useCurrentPath(currentPath);
|
|
53
|
+
const [open, setOpen] = useState(false);
|
|
54
|
+
const listId = useId();
|
|
55
|
+
const navRef = useRef(null);
|
|
56
|
+
const toggleRef = useRef(null);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!open)
|
|
59
|
+
return;
|
|
60
|
+
const close = (returnFocus) => {
|
|
61
|
+
setOpen(false);
|
|
62
|
+
if (returnFocus)
|
|
63
|
+
toggleRef.current?.focus();
|
|
64
|
+
};
|
|
65
|
+
const onKey = (e) => { if (e.key === 'Escape')
|
|
66
|
+
close(true); };
|
|
67
|
+
const onPointer = (e) => { if (!navRef.current?.contains(e.target))
|
|
68
|
+
close(false); };
|
|
69
|
+
document.addEventListener('keydown', onKey);
|
|
70
|
+
document.addEventListener('pointerdown', onPointer);
|
|
71
|
+
return () => {
|
|
72
|
+
document.removeEventListener('keydown', onKey);
|
|
73
|
+
document.removeEventListener('pointerdown', onPointer);
|
|
74
|
+
};
|
|
75
|
+
}, [open]);
|
|
76
|
+
if (items.length === 0)
|
|
77
|
+
return null;
|
|
78
|
+
const current = activeHref(items, path);
|
|
79
|
+
const follow = (e, href) => {
|
|
80
|
+
setOpen(false);
|
|
81
|
+
if (!onNavigate || e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
|
|
82
|
+
return;
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
onNavigate(href);
|
|
85
|
+
if (currentPath === undefined)
|
|
86
|
+
setPath(href);
|
|
87
|
+
};
|
|
88
|
+
return (_jsxs("nav", { ref: navRef, "aria-label": "Main", className: "pas-nav relative flex min-w-0 flex-1 items-center", "data-open": open ? 'true' : 'false', children: [_jsx("button", { ref: toggleRef, type: "button", className: "pas-nav__toggle inline-flex min-h-11 min-w-11 items-center justify-center rounded-[10px] border border-[var(--line)] text-[var(--ink)] focus-visible:outline-2 focus-visible:outline-[var(--accent)] sm:hidden", "aria-expanded": open, "aria-controls": listId, "aria-label": "Menu", onClick: () => setOpen((o) => !o), children: _jsx("svg", { "aria-hidden": "true", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: _jsx("path", { d: open ? 'M6 6l12 12M18 6L6 18' : 'M4 7h16M4 12h16M4 17h16' }) }) }), _jsx("ul", { id: listId, className: "pas-nav__list m-0 flex list-none items-center gap-1 p-0", children: items.map((item) => (_jsx("li", { children: _jsxs("a", { href: item.href, "aria-current": item.href === current ? 'page' : undefined, className: "pas-nav__link inline-flex min-h-11 items-center gap-1.5 rounded-[10px] px-3 text-sm font-semibold whitespace-nowrap text-[var(--muted)] no-underline hover:text-[var(--ink)] focus-visible:outline-2 focus-visible:outline-[var(--accent)] aria-[current=page]:text-[var(--accent)]", onClick: (e) => follow(e, item.href), children: [item.icon, item.label] }) }, item.href))) })] }));
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=navbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navbar.js","sourceRoot":"","sources":["../src/navbar.tsx"],"names":[],"mappings":"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"}
|
package/dist/page.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Set the tab title for the current screen (#236, PAS-UI-003). Call it once in
|
|
4
|
+
* each routed screen; the title follows the value while the screen is mounted.
|
|
5
|
+
* Runs after ProShell applies a nav item's `title`, so the screen's own title
|
|
6
|
+
* wins on the same route.
|
|
7
|
+
*
|
|
8
|
+
* ```tsx
|
|
9
|
+
* useDocumentTitle(`${task.title} — Tasks`)
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare function useDocumentTitle(title: string | null | undefined): void;
|
|
13
|
+
export interface PageHeaderProps {
|
|
14
|
+
/** The screen's heading — rendered as its single `<h1>`. */
|
|
15
|
+
title: ReactNode;
|
|
16
|
+
/** Optional line under the heading. */
|
|
17
|
+
description?: ReactNode;
|
|
18
|
+
/** Optional controls aligned with the heading (e.g. a primary button). */
|
|
19
|
+
actions?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The screen's heading (#236): renders the page's one `<h1>` the same way on
|
|
23
|
+
* every screen (PAS-UI-003). ProShell moves focus to it after a client-side
|
|
24
|
+
* navigation, so keyboard and screen-reader users land on the new page.
|
|
25
|
+
*/
|
|
26
|
+
export declare function PageHeader({ title, description, actions }: PageHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
//# sourceMappingURL=page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../src/page.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAElD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAIvE;AAED,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,KAAK,EAAE,SAAS,CAAC;IACjB,uCAAuC;IACvC,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,eAAe,2CAY1E"}
|
package/dist/page.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Set the tab title for the current screen (#236, PAS-UI-003). Call it once in
|
|
5
|
+
* each routed screen; the title follows the value while the screen is mounted.
|
|
6
|
+
* Runs after ProShell applies a nav item's `title`, so the screen's own title
|
|
7
|
+
* wins on the same route.
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* useDocumentTitle(`${task.title} — Tasks`)
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function useDocumentTitle(title) {
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (title)
|
|
16
|
+
document.title = title;
|
|
17
|
+
}, [title]);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The screen's heading (#236): renders the page's one `<h1>` the same way on
|
|
21
|
+
* every screen (PAS-UI-003). ProShell moves focus to it after a client-side
|
|
22
|
+
* navigation, so keyboard and screen-reader users land on the new page.
|
|
23
|
+
*/
|
|
24
|
+
export function PageHeader({ title, description, actions }) {
|
|
25
|
+
return (_jsxs("div", { className: "pas-page-header mb-5 flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h1", { className: "pas-page-header__title m-0 text-2xl font-bold text-[var(--ink)]", tabIndex: -1, "data-pas-page-heading": "", children: title }), description && _jsx("p", { className: "pas-page-header__description mt-1 text-sm text-[var(--muted)]", children: description })] }), actions && _jsx("div", { className: "flex items-center gap-2", children: actions })] }));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=page.js.map
|
package/dist/page.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../src/page.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAkB,MAAM,OAAO,CAAC;AAElD;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAgC;IAC/D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK;YAAE,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;IACpC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AACd,CAAC;AAWD;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAmB;IACzE,OAAO,CACL,eAAK,SAAS,EAAC,qEAAqE,aAClF,0BACE,aAAI,SAAS,EAAC,iEAAiE,EAAC,QAAQ,EAAE,CAAC,CAAC,2BAAwB,EAAE,YACnH,KAAK,GACH,EACJ,WAAW,IAAI,YAAG,SAAS,EAAC,+DAA+D,YAAE,WAAW,GAAK,IAC1G,EACL,OAAO,IAAI,cAAK,SAAS,EAAC,yBAAyB,YAAE,OAAO,GAAO,IAChE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProShell's resilience and feedback layer styles (#236): skip link, offline
|
|
3
|
+
* banner, toast region, error and loading fallbacks, PageHeader. Same model as
|
|
4
|
+
* navbar-css.ts: canonical tokens only (PAS-UI-001), injected by ProShell at
|
|
5
|
+
* render so an app needs no configuration, and appended to dist/shell.css.
|
|
6
|
+
*/
|
|
7
|
+
export declare const SHELL_CSS = ".pas-skip-link:not(:focus){position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}\n.pas-skip-link:focus{position:fixed;top:.5rem;left:.5rem;z-index:1200;padding:.7rem 1rem;border:2px solid var(--accent);border-radius:10px;background:var(--paper);color:var(--ink);font-weight:600;text-decoration:none;outline:2px solid var(--accent);outline-offset:2px}\n.pas-main:focus{outline:none}\n.pas-offline{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.25rem .5rem .25rem 1rem;background:var(--panel);color:var(--ink);border-bottom:1px solid var(--line);border-left:3px solid var(--warning);font-size:.875rem}\n.pas-toast-region{position:fixed;bottom:1.25rem;left:50%;z-index:1100;display:flex;flex-direction:column;align-items:center;gap:.5rem;max-width:calc(100vw - 2rem);transform:translateX(-50%);pointer-events:none}\n.pas-toast{display:flex;align-items:center;gap:.75rem;padding:.25rem .25rem .25rem 1rem;background:var(--ink);color:var(--paper);border-left:3px solid var(--accent);border-radius:var(--radius,.75rem);box-shadow:0 8px 24px rgba(0,0,0,.3);font-size:.875rem;pointer-events:auto}\n.pas-toast[data-variant=\"success\"]{border-left-color:var(--success)}\n.pas-toast[data-variant=\"error\"]{border-left-color:var(--danger)}\n.pas-dismiss{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;font:inherit;font-size:1.1rem;line-height:1;cursor:pointer;opacity:.75}\n.pas-dismiss:hover{opacity:1}\n.pas-shell-loading{display:flex;flex:1;align-items:center;justify-content:center;padding:3rem 1rem}\n.pas-shell-error{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;padding:3rem 1rem;text-align:center;color:var(--ink)}\n.pas-shell-error h1{margin:0;font-size:1.25rem}\n.pas-shell-error p{margin:0;max-width:32rem;color:var(--muted);font-size:.9rem}\n.pas-shell-error__retry{min-height:44px;padding:0 1.25rem;border:0;border-radius:10px;background:var(--accent);color:var(--paper);font:inherit;font-weight:600;cursor:pointer}\n.pas-page-header{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:.75rem;margin:0 0 1.25rem}\n.pas-page-header__title{margin:0;color:var(--ink);font-size:1.5rem;font-weight:700;line-height:1.2}\n.pas-page-header__title:focus{outline:none}\n.pas-page-header__description{margin:.25rem 0 0;color:var(--muted);font-size:.9rem}\n.pas-dismiss:focus-visible,.pas-shell-error__retry:focus-visible{outline:2px solid var(--accent);outline-offset:2px}\n";
|
|
8
|
+
//# sourceMappingURL=shell-css.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-css.d.ts","sourceRoot":"","sources":["../src/shell-css.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,SAAS,2oFAoBrB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProShell's resilience and feedback layer styles (#236): skip link, offline
|
|
3
|
+
* banner, toast region, error and loading fallbacks, PageHeader. Same model as
|
|
4
|
+
* navbar-css.ts: canonical tokens only (PAS-UI-001), injected by ProShell at
|
|
5
|
+
* render so an app needs no configuration, and appended to dist/shell.css.
|
|
6
|
+
*/
|
|
7
|
+
export const SHELL_CSS = `.pas-skip-link:not(:focus){position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
|
|
8
|
+
.pas-skip-link:focus{position:fixed;top:.5rem;left:.5rem;z-index:1200;padding:.7rem 1rem;border:2px solid var(--accent);border-radius:10px;background:var(--paper);color:var(--ink);font-weight:600;text-decoration:none;outline:2px solid var(--accent);outline-offset:2px}
|
|
9
|
+
.pas-main:focus{outline:none}
|
|
10
|
+
.pas-offline{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.25rem .5rem .25rem 1rem;background:var(--panel);color:var(--ink);border-bottom:1px solid var(--line);border-left:3px solid var(--warning);font-size:.875rem}
|
|
11
|
+
.pas-toast-region{position:fixed;bottom:1.25rem;left:50%;z-index:1100;display:flex;flex-direction:column;align-items:center;gap:.5rem;max-width:calc(100vw - 2rem);transform:translateX(-50%);pointer-events:none}
|
|
12
|
+
.pas-toast{display:flex;align-items:center;gap:.75rem;padding:.25rem .25rem .25rem 1rem;background:var(--ink);color:var(--paper);border-left:3px solid var(--accent);border-radius:var(--radius,.75rem);box-shadow:0 8px 24px rgba(0,0,0,.3);font-size:.875rem;pointer-events:auto}
|
|
13
|
+
.pas-toast[data-variant="success"]{border-left-color:var(--success)}
|
|
14
|
+
.pas-toast[data-variant="error"]{border-left-color:var(--danger)}
|
|
15
|
+
.pas-dismiss{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;font:inherit;font-size:1.1rem;line-height:1;cursor:pointer;opacity:.75}
|
|
16
|
+
.pas-dismiss:hover{opacity:1}
|
|
17
|
+
.pas-shell-loading{display:flex;flex:1;align-items:center;justify-content:center;padding:3rem 1rem}
|
|
18
|
+
.pas-shell-error{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;padding:3rem 1rem;text-align:center;color:var(--ink)}
|
|
19
|
+
.pas-shell-error h1{margin:0;font-size:1.25rem}
|
|
20
|
+
.pas-shell-error p{margin:0;max-width:32rem;color:var(--muted);font-size:.9rem}
|
|
21
|
+
.pas-shell-error__retry{min-height:44px;padding:0 1.25rem;border:0;border-radius:10px;background:var(--accent);color:var(--paper);font:inherit;font-weight:600;cursor:pointer}
|
|
22
|
+
.pas-page-header{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:.75rem;margin:0 0 1.25rem}
|
|
23
|
+
.pas-page-header__title{margin:0;color:var(--ink);font-size:1.5rem;font-weight:700;line-height:1.2}
|
|
24
|
+
.pas-page-header__title:focus{outline:none}
|
|
25
|
+
.pas-page-header__description{margin:.25rem 0 0;color:var(--muted);font-size:.9rem}
|
|
26
|
+
.pas-dismiss:focus-visible,.pas-shell-error__retry:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
|
27
|
+
`;
|
|
28
|
+
//# sourceMappingURL=shell-css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-css.js","sourceRoot":"","sources":["../src/shell-css.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;CAoBxB,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Component, type ErrorInfo, type ReactNode, type RefObject } from 'react';
|
|
2
|
+
import type { ProAppStore } from './index.js';
|
|
3
|
+
export interface ShellErrorContext {
|
|
4
|
+
error: Error;
|
|
5
|
+
/** Clear the error and render the screen again. */
|
|
6
|
+
reset: () => void;
|
|
7
|
+
}
|
|
8
|
+
interface BoundaryProps {
|
|
9
|
+
app: ProAppStore;
|
|
10
|
+
renderError: ((ctx: ShellErrorContext) => ReactNode) | undefined;
|
|
11
|
+
/** A change (the current route) clears a caught error, so navigating away recovers. */
|
|
12
|
+
resetKey: string;
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
interface BoundaryState {
|
|
16
|
+
error: Error | null;
|
|
17
|
+
resetKey: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Catches a render error in the app's content (#236) so one broken screen
|
|
21
|
+
* shows a fallback instead of a white screen. The error is recorded through
|
|
22
|
+
* `app.logs` — an error React catches never reaches `window.onerror`, so the
|
|
23
|
+
* automatic capture would otherwise miss it.
|
|
24
|
+
*/
|
|
25
|
+
export declare class ShellErrorBoundary extends Component<BoundaryProps, BoundaryState> {
|
|
26
|
+
state: BoundaryState;
|
|
27
|
+
static getDerivedStateFromError(error: unknown): Partial<BoundaryState>;
|
|
28
|
+
static getDerivedStateFromProps(props: BoundaryProps, state: BoundaryState): Partial<BoundaryState> | null;
|
|
29
|
+
componentDidCatch(error: unknown, info: ErrorInfo): void;
|
|
30
|
+
reset: () => void;
|
|
31
|
+
render(): ReactNode;
|
|
32
|
+
}
|
|
33
|
+
export type ShellToastVariant = 'info' | 'success' | 'error';
|
|
34
|
+
export interface ToastOptions {
|
|
35
|
+
variant?: ShellToastVariant;
|
|
36
|
+
/** Milliseconds before it dismisses itself; 0 keeps it until dismissed. Default 4000. */
|
|
37
|
+
duration?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ToastApi {
|
|
40
|
+
/** Show a message; returns its id. */
|
|
41
|
+
show: (message: string, options?: ToastOptions) => number;
|
|
42
|
+
dismiss: (id: number) => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Raise a message from any screen inside ProShell (#236). Messages appear in
|
|
46
|
+
* the shell's single polite live region.
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* const toast = useToast()
|
|
50
|
+
* toast.show('Saved', { variant: 'success' })
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function useToast(): ToastApi;
|
|
54
|
+
/**
|
|
55
|
+
* The shell's toast queue. The region is rendered once and always, so it is
|
|
56
|
+
* already in the accessibility tree when a message arrives — a live region
|
|
57
|
+
* created together with its first message is often not announced. Items carry
|
|
58
|
+
* no live-region role of their own.
|
|
59
|
+
*/
|
|
60
|
+
export declare function ToastProvider({ children }: {
|
|
61
|
+
children: ReactNode;
|
|
62
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
63
|
+
/** `navigator.onLine`, kept current by the browser's online/offline events. */
|
|
64
|
+
export declare function useOnline(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* A banner under the topbar while the connection is down (#236). Its polite
|
|
67
|
+
* live region is always present, so the change is announced. Dismissible;
|
|
68
|
+
* clears itself on reconnect, and a later drop shows it again.
|
|
69
|
+
*/
|
|
70
|
+
export declare function OfflineBanner(): import("react/jsx-runtime").JSX.Element;
|
|
71
|
+
/** The first focusable element: hidden until focused, moves focus to the shell's `<main id="main">`. */
|
|
72
|
+
export declare function SkipLink({ mainRef }: {
|
|
73
|
+
mainRef: RefObject<HTMLElement | null>;
|
|
74
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
75
|
+
/**
|
|
76
|
+
* Scroll and focus on client-side route changes (#236). Forward navigation
|
|
77
|
+
* lands at the top; back/forward returns to where that route was left. After
|
|
78
|
+
* either, focus moves to the new screen's PageHeader `<h1>`, else to `<main>`.
|
|
79
|
+
*
|
|
80
|
+
* Only for client-side navigation (`enabled` = the app passed `onNavigate`):
|
|
81
|
+
* with ordinary links every navigation is a page load, and the browser already
|
|
82
|
+
* restores scroll and resets focus — taking scroll restoration over there would
|
|
83
|
+
* break it on the way back.
|
|
84
|
+
*
|
|
85
|
+
* Returns the function to call just before a forward navigation.
|
|
86
|
+
*/
|
|
87
|
+
export declare function useRouteChangeEffects(path: string, mainRef: RefObject<HTMLElement | null>, enabled: boolean): () => void;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=shell-resilience.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-resilience.d.ts","sourceRoot":"","sources":["../src/shell-resilience.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAQT,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK9C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,mDAAmD;IACnD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,UAAU,aAAa;IACrB,GAAG,EAAE,WAAW,CAAC;IACjB,WAAW,EAAE,CAAC,CAAC,GAAG,EAAE,iBAAiB,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;IACjE,uFAAuF;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;IACpE,KAAK,EAAE,aAAa,CAAkD;IAE/E,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC;IAIvE,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI;IAIjG,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IASjE,KAAK,QAAO,IAAI,CAAmC;IAE1C,MAAM,IAAI,SAAS;CAc7B;AAID,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,sCAAsC;IACtC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,MAAM,CAAC;IAC1D,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAcD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,IAAI,QAAQ,CAInC;AAkBD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAqBlE;AAID,+EAA+E;AAC/E,wBAAgB,SAAS,IAAI,OAAO,CAcnC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,4CAkB5B;AAID,wGAAwG;AACxG,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;CAAE,2CAe/E;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,IAAI,CA0CxH"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Component, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
|
|
3
|
+
import { describeError } from './logs.js';
|
|
4
|
+
/**
|
|
5
|
+
* Catches a render error in the app's content (#236) so one broken screen
|
|
6
|
+
* shows a fallback instead of a white screen. The error is recorded through
|
|
7
|
+
* `app.logs` — an error React catches never reaches `window.onerror`, so the
|
|
8
|
+
* automatic capture would otherwise miss it.
|
|
9
|
+
*/
|
|
10
|
+
export class ShellErrorBoundary extends Component {
|
|
11
|
+
state = { error: null, resetKey: this.props.resetKey };
|
|
12
|
+
static getDerivedStateFromError(error) {
|
|
13
|
+
return { error: error instanceof Error ? error : new Error(String(error)) };
|
|
14
|
+
}
|
|
15
|
+
static getDerivedStateFromProps(props, state) {
|
|
16
|
+
return props.resetKey !== state.resetKey ? { error: null, resetKey: props.resetKey } : null;
|
|
17
|
+
}
|
|
18
|
+
componentDidCatch(error, info) {
|
|
19
|
+
const described = describeError(error);
|
|
20
|
+
this.props.app.logs.capture('error', 'react.error-boundary', described.message, {
|
|
21
|
+
stack: described.stack,
|
|
22
|
+
componentStack: info.componentStack ?? undefined,
|
|
23
|
+
path: typeof window === 'undefined' ? undefined : window.location.pathname,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
reset = () => this.setState({ error: null });
|
|
27
|
+
render() {
|
|
28
|
+
const { error } = this.state;
|
|
29
|
+
if (!error)
|
|
30
|
+
return this.props.children;
|
|
31
|
+
if (this.props.renderError)
|
|
32
|
+
return this.props.renderError({ error, reset: this.reset });
|
|
33
|
+
return (_jsxs("div", { role: "alert", className: "pas-shell-error flex flex-1 flex-col items-center justify-center gap-3 px-4 py-12 text-center", children: [_jsx("h1", { children: "Something went wrong" }), _jsx("p", { children: "This screen hit an error and could not be shown. It has been reported. Try again, or use the navigation to go elsewhere." }), _jsx("button", { type: "button", className: "pas-shell-error__retry min-h-11 rounded-[10px] px-5 font-semibold", onClick: this.reset, children: "Try again" })] }));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** At most this many messages at once; the oldest goes first. */
|
|
37
|
+
const MAX_TOASTS = 4;
|
|
38
|
+
const ToastContext = createContext(null);
|
|
39
|
+
/**
|
|
40
|
+
* Raise a message from any screen inside ProShell (#236). Messages appear in
|
|
41
|
+
* the shell's single polite live region.
|
|
42
|
+
*
|
|
43
|
+
* ```tsx
|
|
44
|
+
* const toast = useToast()
|
|
45
|
+
* toast.show('Saved', { variant: 'success' })
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function useToast() {
|
|
49
|
+
const api = useContext(ToastContext);
|
|
50
|
+
if (!api)
|
|
51
|
+
throw new Error('useToast must be used inside <ProShell>');
|
|
52
|
+
return api;
|
|
53
|
+
}
|
|
54
|
+
function ToastItem({ toast, onDismiss }) {
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (toast.duration <= 0)
|
|
57
|
+
return;
|
|
58
|
+
const timer = setTimeout(() => onDismiss(toast.id), toast.duration);
|
|
59
|
+
return () => clearTimeout(timer);
|
|
60
|
+
}, [toast.id, toast.duration, onDismiss]);
|
|
61
|
+
return (_jsxs("div", { className: "pas-toast flex items-center gap-3 rounded-xl text-sm", "data-variant": toast.variant, children: [_jsx("span", { children: toast.message }), _jsx("button", { type: "button", className: "pas-dismiss min-h-11 min-w-11", "aria-label": "Dismiss", onClick: () => onDismiss(toast.id), children: "\u00D7" })] }));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The shell's toast queue. The region is rendered once and always, so it is
|
|
65
|
+
* already in the accessibility tree when a message arrives — a live region
|
|
66
|
+
* created together with its first message is often not announced. Items carry
|
|
67
|
+
* no live-region role of their own.
|
|
68
|
+
*/
|
|
69
|
+
export function ToastProvider({ children }) {
|
|
70
|
+
const [toasts, setToasts] = useState([]);
|
|
71
|
+
const nextId = useRef(1);
|
|
72
|
+
const dismiss = useCallback((id) => setToasts((all) => all.filter((t) => t.id !== id)), []);
|
|
73
|
+
const show = useCallback((message, options = {}) => {
|
|
74
|
+
const id = nextId.current++;
|
|
75
|
+
const toast = { id, message, variant: options.variant ?? 'info', duration: options.duration ?? 4000 };
|
|
76
|
+
setToasts((all) => [...all, toast].slice(-MAX_TOASTS));
|
|
77
|
+
return id;
|
|
78
|
+
}, []);
|
|
79
|
+
const api = useMemo(() => ({ show, dismiss }), [show, dismiss]);
|
|
80
|
+
return (_jsxs(ToastContext.Provider, { value: api, children: [children, _jsx("div", { role: "status", "aria-live": "polite", className: "pas-toast-region fixed bottom-5 left-1/2 flex -translate-x-1/2 flex-col items-center gap-2", children: toasts.map((toast) => _jsx(ToastItem, { toast: toast, onDismiss: dismiss }, toast.id)) })] }));
|
|
81
|
+
}
|
|
82
|
+
// ── Offline ─────────────────────────────────────────────────────
|
|
83
|
+
/** `navigator.onLine`, kept current by the browser's online/offline events. */
|
|
84
|
+
export function useOnline() {
|
|
85
|
+
const [online, setOnline] = useState(() => (typeof navigator === 'undefined' ? true : navigator.onLine));
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const up = () => setOnline(true);
|
|
88
|
+
const down = () => setOnline(false);
|
|
89
|
+
window.addEventListener('online', up);
|
|
90
|
+
window.addEventListener('offline', down);
|
|
91
|
+
setOnline(navigator.onLine);
|
|
92
|
+
return () => {
|
|
93
|
+
window.removeEventListener('online', up);
|
|
94
|
+
window.removeEventListener('offline', down);
|
|
95
|
+
};
|
|
96
|
+
}, []);
|
|
97
|
+
return online;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A banner under the topbar while the connection is down (#236). Its polite
|
|
101
|
+
* live region is always present, so the change is announced. Dismissible;
|
|
102
|
+
* clears itself on reconnect, and a later drop shows it again.
|
|
103
|
+
*/
|
|
104
|
+
export function OfflineBanner() {
|
|
105
|
+
const online = useOnline();
|
|
106
|
+
const [dismissed, setDismissed] = useState(false);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (online)
|
|
109
|
+
setDismissed(false);
|
|
110
|
+
}, [online]);
|
|
111
|
+
return (_jsx("div", { role: "status", "aria-live": "polite", children: !online && !dismissed && (_jsxs("div", { className: "pas-offline flex items-center justify-between gap-3 text-sm", children: [_jsx("span", { children: "You're offline. Changes can't be saved until the connection is back." }), _jsx("button", { type: "button", className: "pas-dismiss min-h-11 min-w-11", "aria-label": "Dismiss offline notice", onClick: () => setDismissed(true), children: "\u00D7" })] })) }));
|
|
112
|
+
}
|
|
113
|
+
// ── Skip link ───────────────────────────────────────────────────
|
|
114
|
+
/** The first focusable element: hidden until focused, moves focus to the shell's `<main id="main">`. */
|
|
115
|
+
export function SkipLink({ mainRef }) {
|
|
116
|
+
return (_jsx("a", { href: "#main", className: "pas-skip-link", onClick: (e) => {
|
|
117
|
+
// Focus directly rather than following the fragment: a hash change is a
|
|
118
|
+
// history navigation, which a router would see as a route change.
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
mainRef.current?.focus();
|
|
121
|
+
}, children: "Skip to content" }));
|
|
122
|
+
}
|
|
123
|
+
// ── Route changes: scroll and focus ─────────────────────────────
|
|
124
|
+
/**
|
|
125
|
+
* Scroll and focus on client-side route changes (#236). Forward navigation
|
|
126
|
+
* lands at the top; back/forward returns to where that route was left. After
|
|
127
|
+
* either, focus moves to the new screen's PageHeader `<h1>`, else to `<main>`.
|
|
128
|
+
*
|
|
129
|
+
* Only for client-side navigation (`enabled` = the app passed `onNavigate`):
|
|
130
|
+
* with ordinary links every navigation is a page load, and the browser already
|
|
131
|
+
* restores scroll and resets focus — taking scroll restoration over there would
|
|
132
|
+
* break it on the way back.
|
|
133
|
+
*
|
|
134
|
+
* Returns the function to call just before a forward navigation.
|
|
135
|
+
*/
|
|
136
|
+
export function useRouteChangeEffects(path, mainRef, enabled) {
|
|
137
|
+
const positions = useRef(new Map());
|
|
138
|
+
const lastPath = useRef(path);
|
|
139
|
+
const kind = useRef('push');
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (!enabled)
|
|
142
|
+
return;
|
|
143
|
+
const previous = window.history.scrollRestoration;
|
|
144
|
+
window.history.scrollRestoration = 'manual';
|
|
145
|
+
// Runs before the re-render the same popstate causes, while the page still
|
|
146
|
+
// shows the route being left.
|
|
147
|
+
const onPop = () => {
|
|
148
|
+
positions.current.set(lastPath.current, window.scrollY);
|
|
149
|
+
kind.current = 'pop';
|
|
150
|
+
};
|
|
151
|
+
window.addEventListener('popstate', onPop);
|
|
152
|
+
return () => {
|
|
153
|
+
window.removeEventListener('popstate', onPop);
|
|
154
|
+
window.history.scrollRestoration = previous;
|
|
155
|
+
};
|
|
156
|
+
}, [enabled]);
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
if (!enabled || path === lastPath.current)
|
|
159
|
+
return;
|
|
160
|
+
lastPath.current = path;
|
|
161
|
+
const back = kind.current === 'pop';
|
|
162
|
+
kind.current = 'push';
|
|
163
|
+
// A frame later, so a router that renders the new screen in its own update
|
|
164
|
+
// has committed it before we scroll to it and look for its heading.
|
|
165
|
+
const frame = requestAnimationFrame(() => {
|
|
166
|
+
window.scrollTo(0, back ? positions.current.get(path) ?? 0 : 0);
|
|
167
|
+
const main = mainRef.current;
|
|
168
|
+
const target = main?.querySelector('[data-pas-page-heading]') ?? main;
|
|
169
|
+
target?.focus({ preventScroll: true });
|
|
170
|
+
});
|
|
171
|
+
return () => cancelAnimationFrame(frame);
|
|
172
|
+
}, [path, enabled, mainRef]);
|
|
173
|
+
return useCallback(() => {
|
|
174
|
+
positions.current.set(lastPath.current, window.scrollY);
|
|
175
|
+
kind.current = 'push';
|
|
176
|
+
}, []);
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=shell-resilience.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-resilience.js","sourceRoot":"","sources":["../src/shell-resilience.tsx"],"names":[],"mappings":"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"}
|
package/dist/shell.css
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.pas-nav{position:relative;display:flex;align-items:center;flex:1 1 auto;min-width:0;margin:0 .5rem}
|
|
2
|
+
.pas-nav__toggle{display:none;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0;border:1px solid var(--line);border-radius:10px;background:transparent;color:var(--ink);font:inherit;cursor:pointer}
|
|
3
|
+
.pas-nav__list{display:flex;align-items:center;gap:.25rem;margin:0;padding:0;list-style:none;overflow-x:auto}
|
|
4
|
+
.pas-nav__link{display:inline-flex;align-items:center;gap:.4rem;min-height:44px;padding:0 .75rem;border-radius:10px;color:var(--muted);font-size:.9rem;font-weight:600;text-decoration:none;white-space:nowrap}
|
|
5
|
+
.pas-nav__link:hover{color:var(--ink);background:var(--line)}
|
|
6
|
+
.pas-nav__link[aria-current="page"]{color:var(--accent);background:var(--line)}
|
|
7
|
+
.pas-nav__toggle:focus-visible,.pas-nav__link:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
|
8
|
+
@media (max-width:639px){.pas-nav{flex:0 0 auto;margin:0}.pas-nav__toggle{display:inline-flex}.pas-nav__list{display:none;position:absolute;top:calc(100% + .5rem);left:0;z-index:60;flex-direction:column;align-items:stretch;min-width:12rem;padding:.5rem;overflow:visible;background:var(--paper);border:1px solid var(--line);border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.12)}.pas-nav[data-open="true"] .pas-nav__list{display:flex}}
|
|
9
|
+
.pas-skip-link:not(:focus){position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
|
|
10
|
+
.pas-skip-link:focus{position:fixed;top:.5rem;left:.5rem;z-index:1200;padding:.7rem 1rem;border:2px solid var(--accent);border-radius:10px;background:var(--paper);color:var(--ink);font-weight:600;text-decoration:none;outline:2px solid var(--accent);outline-offset:2px}
|
|
11
|
+
.pas-main:focus{outline:none}
|
|
12
|
+
.pas-offline{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.25rem .5rem .25rem 1rem;background:var(--panel);color:var(--ink);border-bottom:1px solid var(--line);border-left:3px solid var(--warning);font-size:.875rem}
|
|
13
|
+
.pas-toast-region{position:fixed;bottom:1.25rem;left:50%;z-index:1100;display:flex;flex-direction:column;align-items:center;gap:.5rem;max-width:calc(100vw - 2rem);transform:translateX(-50%);pointer-events:none}
|
|
14
|
+
.pas-toast{display:flex;align-items:center;gap:.75rem;padding:.25rem .25rem .25rem 1rem;background:var(--ink);color:var(--paper);border-left:3px solid var(--accent);border-radius:var(--radius,.75rem);box-shadow:0 8px 24px rgba(0,0,0,.3);font-size:.875rem;pointer-events:auto}
|
|
15
|
+
.pas-toast[data-variant="success"]{border-left-color:var(--success)}
|
|
16
|
+
.pas-toast[data-variant="error"]{border-left-color:var(--danger)}
|
|
17
|
+
.pas-dismiss{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;font:inherit;font-size:1.1rem;line-height:1;cursor:pointer;opacity:.75}
|
|
18
|
+
.pas-dismiss:hover{opacity:1}
|
|
19
|
+
.pas-shell-loading{display:flex;flex:1;align-items:center;justify-content:center;padding:3rem 1rem}
|
|
20
|
+
.pas-shell-error{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;padding:3rem 1rem;text-align:center;color:var(--ink)}
|
|
21
|
+
.pas-shell-error h1{margin:0;font-size:1.25rem}
|
|
22
|
+
.pas-shell-error p{margin:0;max-width:32rem;color:var(--muted);font-size:.9rem}
|
|
23
|
+
.pas-shell-error__retry{min-height:44px;padding:0 1.25rem;border:0;border-radius:10px;background:var(--accent);color:var(--paper);font:inherit;font-weight:600;cursor:pointer}
|
|
24
|
+
.pas-page-header{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:.75rem;margin:0 0 1.25rem}
|
|
25
|
+
.pas-page-header__title{margin:0;color:var(--ink);font-size:1.5rem;font-weight:700;line-height:1.2}
|
|
26
|
+
.pas-page-header__title:focus{outline:none}
|
|
27
|
+
.pas-page-header__description{margin:.25rem 0 0;color:var(--muted);font-size:.9rem}
|
|
28
|
+
.pas-dismiss:focus-visible,.pas-shell-error__retry:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
package/dist/shell.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ import { type ReactNode } from 'react';
|
|
|
2
2
|
import type { ProAppStore } from './index.js';
|
|
3
3
|
import type { User } from './base-types.js';
|
|
4
4
|
import type { Subscription } from './types.js';
|
|
5
|
+
import { type NavItem } from './navbar.js';
|
|
6
|
+
import { type ShellErrorContext } from './shell-resilience.js';
|
|
7
|
+
export type { NavItem } from './navbar.js';
|
|
8
|
+
export type { ShellErrorContext } from './shell-resilience.js';
|
|
5
9
|
export interface MenuItem {
|
|
6
10
|
label: string;
|
|
7
11
|
onClick: () => void;
|
|
@@ -21,6 +25,16 @@ export interface ProShellRenderContext {
|
|
|
21
25
|
profileMenu: ReactNode;
|
|
22
26
|
/** PRO badge when the current subscription is active; otherwise null. */
|
|
23
27
|
proBadge: ReactNode;
|
|
28
|
+
/** The app's main navigation (`nav` / `renderNav`), or null when none is declared.
|
|
29
|
+
* A custom `renderTopbar` should place it. */
|
|
30
|
+
nav: ReactNode;
|
|
31
|
+
}
|
|
32
|
+
export interface ProShellNavContext {
|
|
33
|
+
items: NavItem[];
|
|
34
|
+
/** The path the shell considers current (`location.pathname`, following back/forward). */
|
|
35
|
+
currentPath: string;
|
|
36
|
+
/** Navigate to `href`: the shell's `onNavigate`, else a full page load. */
|
|
37
|
+
onNavigate: (href: string) => void;
|
|
24
38
|
}
|
|
25
39
|
export interface ProShellProps {
|
|
26
40
|
/** The ProAppStore SDK instance from initPro(). */
|
|
@@ -29,6 +43,23 @@ export interface ProShellProps {
|
|
|
29
43
|
children: ReactNode;
|
|
30
44
|
/** App name shown in the topbar. */
|
|
31
45
|
appName?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The app's screens — the standard way to give an app navigation (#235).
|
|
48
|
+
* ProShell renders them as a `<nav aria-label="Main">` in its topbar, marks
|
|
49
|
+
* the current route, and collapses to a menu button on small screens.
|
|
50
|
+
*
|
|
51
|
+
* ```tsx
|
|
52
|
+
* <ProShell app={app} appName="Cases" nav={[{ label: 'Home', href: '/' }, { label: 'Cases', href: '/cases' }]}>
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
nav?: NavItem[];
|
|
56
|
+
/** Replace the built-in NavBar (still placed in the topbar) with your own. */
|
|
57
|
+
renderNav?: (ctx: ProShellNavContext) => ReactNode;
|
|
58
|
+
/**
|
|
59
|
+
* Client-side navigation for nav clicks (e.g. your router's `navigate`).
|
|
60
|
+
* Without it, nav items are ordinary links (full page load).
|
|
61
|
+
*/
|
|
62
|
+
onNavigate?: (href: string) => void;
|
|
32
63
|
/**
|
|
33
64
|
* If true, allow free users to see the app (no subscription gate).
|
|
34
65
|
*
|
|
@@ -40,7 +71,7 @@ export interface ProShellProps {
|
|
|
40
71
|
showThemeToggle?: boolean;
|
|
41
72
|
/** Custom items added to the profile dropdown (above sign-out). */
|
|
42
73
|
menuItems?: MenuItem[];
|
|
43
|
-
/** Hide the default ProShell topbar.
|
|
74
|
+
/** Hide the default ProShell topbar. Prefer `nav`; this also hides the navigation. */
|
|
44
75
|
hideTopbar?: boolean;
|
|
45
76
|
/** Hide the default ProShell footer. */
|
|
46
77
|
hideFooter?: boolean;
|
|
@@ -53,6 +84,13 @@ export interface ProShellProps {
|
|
|
53
84
|
renderTopbar?: (ctx: ProShellRenderContext) => ReactNode;
|
|
54
85
|
/** Replace the default footer. Return null to omit it. */
|
|
55
86
|
renderFooter?: (ctx: ProShellRenderContext) => ReactNode;
|
|
87
|
+
/**
|
|
88
|
+
* Replace the fallback shown when a screen throws while rendering (#236).
|
|
89
|
+
* The error is already recorded via `app.logs`; call `reset` to retry.
|
|
90
|
+
*/
|
|
91
|
+
renderError?: (ctx: ShellErrorContext) => ReactNode;
|
|
92
|
+
/** Replace the spinner shown while a lazy-loaded screen loads (#236). */
|
|
93
|
+
renderLoading?: () => ReactNode;
|
|
56
94
|
}
|
|
57
95
|
/**
|
|
58
96
|
* ProShell — platform-level Shell for all ProAppStore apps.
|
|
@@ -61,6 +99,10 @@ export interface ProShellProps {
|
|
|
61
99
|
* - Auth initialization + sign-in gate
|
|
62
100
|
* - Subscription check + upgrade wall (unless allowFree=true)
|
|
63
101
|
* - Topbar with avatar, app name, menu (sign out, delete account, manage billing)
|
|
102
|
+
* - Main navigation from the `nav` prop (<nav aria-label="Main">, current route, mobile menu)
|
|
103
|
+
* - Resilience and feedback (#236): error boundary + Suspense around the content,
|
|
104
|
+
* `useToast` region, offline banner, skip link, nav-item titles, and scroll +
|
|
105
|
+
* focus handling on client-side route changes
|
|
64
106
|
* - Theme support via CSS custom properties
|
|
65
107
|
* - Only renders children when all gates pass
|
|
66
108
|
*
|
|
@@ -73,12 +115,12 @@ export interface ProShellProps {
|
|
|
73
115
|
*
|
|
74
116
|
* export default function App() {
|
|
75
117
|
* return (
|
|
76
|
-
* <ProShell app={app} appName="Meetup">
|
|
118
|
+
* <ProShell app={app} appName="Meetup" nav={[{ label: 'Events', href: '/' }, { label: 'Groups', href: '/groups' }]}>
|
|
77
119
|
* <MeetupApp />
|
|
78
120
|
* </ProShell>
|
|
79
121
|
* )
|
|
80
122
|
* }
|
|
81
123
|
* ```
|
|
82
124
|
*/
|
|
83
|
-
export declare function ProShell({ app, children, appName, allowFree, showThemeToggle, menuItems, hideTopbar, hideFooter, renderTopbar, renderFooter, }: ProShellProps): import("react/jsx-runtime").JSX.Element;
|
|
125
|
+
export declare function ProShell({ app, children, appName, nav, renderNav, onNavigate, allowFree, showThemeToggle, menuItems, hideTopbar, hideFooter, renderTopbar, renderFooter, renderError, renderLoading, }: ProShellProps): import("react/jsx-runtime").JSX.Element;
|
|
84
126
|
//# sourceMappingURL=shell.d.ts.map
|
package/dist/shell.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../src/shell.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../src/shell.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA8E,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACnH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAsC,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAE/E,OAAO,EAML,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,GAAG,EAAE,WAAW,CAAC;IACjB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,kFAAkF;IAClF,IAAI,EAAE,IAAI,CAAC;IACX,sEAAsE;IACtE,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,mDAAmD;IACnD,cAAc,EAAE,SAAS,CAAC;IAC1B,6EAA6E;IAC7E,WAAW,EAAE,SAAS,CAAC;IACvB,yEAAyE;IACzE,QAAQ,EAAE,SAAS,CAAC;IACpB;mDAC+C;IAC/C,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,0FAA0F;IAC1F,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,GAAG,EAAE,WAAW,CAAC;IACjB,6EAA6E;IAC7E,QAAQ,EAAE,SAAS,CAAC;IACpB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC;IAChB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,SAAS,CAAC;IACnD;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4DAA4D;IAC5D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,sFAAsF;IACtF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,SAAS,CAAC;IACzD,0DAA0D;IAC1D,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,SAAS,CAAC;IACzD;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,SAAS,CAAC;IACpD,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,SAAS,CAAC;CACjC;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,QAAQ,EACR,OAAO,EACP,GAAG,EACH,SAAS,EACT,UAAU,EACV,SAAgB,EAChB,eAAsB,EACtB,SAAS,EACT,UAAkB,EAClB,UAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,aAAa,GACd,EAAE,aAAa,2CAkJf"}
|
package/dist/shell.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { ProfileMenu, ProBadge, GateScreen, TextSizeToggle } from './ui.js';
|
|
2
|
+
import { Suspense, useEffect, useInsertionEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { ProfileMenu, ProBadge, GateScreen, TextSizeToggle, Spinner } from './ui.js';
|
|
4
4
|
import { ProProvider } from './provider.js';
|
|
5
|
+
import { activeHref, NavBar, useCurrentPath } from './navbar.js';
|
|
6
|
+
import { SHELL_CSS } from './shell-css.js';
|
|
7
|
+
import { OfflineBanner, ShellErrorBoundary, SkipLink, ToastProvider, useRouteChangeEffects, } from './shell-resilience.js';
|
|
5
8
|
/**
|
|
6
9
|
* ProShell — platform-level Shell for all ProAppStore apps.
|
|
7
10
|
*
|
|
@@ -9,6 +12,10 @@ import { ProProvider } from './provider.js';
|
|
|
9
12
|
* - Auth initialization + sign-in gate
|
|
10
13
|
* - Subscription check + upgrade wall (unless allowFree=true)
|
|
11
14
|
* - Topbar with avatar, app name, menu (sign out, delete account, manage billing)
|
|
15
|
+
* - Main navigation from the `nav` prop (<nav aria-label="Main">, current route, mobile menu)
|
|
16
|
+
* - Resilience and feedback (#236): error boundary + Suspense around the content,
|
|
17
|
+
* `useToast` region, offline banner, skip link, nav-item titles, and scroll +
|
|
18
|
+
* focus handling on client-side route changes
|
|
12
19
|
* - Theme support via CSS custom properties
|
|
13
20
|
* - Only renders children when all gates pass
|
|
14
21
|
*
|
|
@@ -21,17 +28,37 @@ import { ProProvider } from './provider.js';
|
|
|
21
28
|
*
|
|
22
29
|
* export default function App() {
|
|
23
30
|
* return (
|
|
24
|
-
* <ProShell app={app} appName="Meetup">
|
|
31
|
+
* <ProShell app={app} appName="Meetup" nav={[{ label: 'Events', href: '/' }, { label: 'Groups', href: '/groups' }]}>
|
|
25
32
|
* <MeetupApp />
|
|
26
33
|
* </ProShell>
|
|
27
34
|
* )
|
|
28
35
|
* }
|
|
29
36
|
* ```
|
|
30
37
|
*/
|
|
31
|
-
export function ProShell({ app, children, appName, allowFree = true, showThemeToggle = true, menuItems, hideTopbar = false, hideFooter = false, renderTopbar, renderFooter, }) {
|
|
38
|
+
export function ProShell({ app, children, appName, nav, renderNav, onNavigate, allowFree = true, showThemeToggle = true, menuItems, hideTopbar = false, hideFooter = false, renderTopbar, renderFooter, renderError, renderLoading, }) {
|
|
32
39
|
const [user, setUser] = useState(app.auth.user);
|
|
33
40
|
const [subscription, setSubscription] = useState(null);
|
|
34
41
|
const [gate, setGate] = useState('loading');
|
|
42
|
+
const [currentPath, setCurrentPath] = useCurrentPath();
|
|
43
|
+
const mainRef = useRef(null);
|
|
44
|
+
const beforeNavigate = useRouteChangeEffects(currentPath, mainRef, onNavigate !== undefined);
|
|
45
|
+
useInsertionEffect(() => {
|
|
46
|
+
if (document.getElementById('pas-shell-css'))
|
|
47
|
+
return;
|
|
48
|
+
const style = document.createElement('style');
|
|
49
|
+
style.id = 'pas-shell-css';
|
|
50
|
+
style.textContent = SHELL_CSS;
|
|
51
|
+
document.head.appendChild(style);
|
|
52
|
+
}, []);
|
|
53
|
+
// A nav item's `title` becomes the tab title on its route. A layout effect runs
|
|
54
|
+
// before every passive effect, so a screen's own useDocumentTitle still wins.
|
|
55
|
+
const navItems = nav ?? [];
|
|
56
|
+
const activeItem = navItems.find((item) => item.href === activeHref(navItems, currentPath));
|
|
57
|
+
const navTitle = activeItem?.title;
|
|
58
|
+
useLayoutEffect(() => {
|
|
59
|
+
if (navTitle)
|
|
60
|
+
document.title = navTitle;
|
|
61
|
+
}, [navTitle, currentPath]);
|
|
35
62
|
useEffect(() => {
|
|
36
63
|
app.auth.init();
|
|
37
64
|
return app.auth.onChange((u) => {
|
|
@@ -65,6 +92,24 @@ export function ProShell({ app, children, appName, allowFree = true, showThemeTo
|
|
|
65
92
|
return _jsx(GateScreen, { gate: "signed-out", app: app, appName: appName });
|
|
66
93
|
}
|
|
67
94
|
const profileMenu = (_jsx(ProfileMenu, { app: app, showThemeToggle: showThemeToggle, children: menuItems?.map((item, i) => (_jsx("button", { onClick: item.onClick, style: menuItemStyle, children: item.label }, i))) }));
|
|
95
|
+
// Client-side navigation goes through the shell, so it knows the route changed
|
|
96
|
+
// (scroll, focus, titles). Without onNavigate, items are plain links.
|
|
97
|
+
const navigate = onNavigate
|
|
98
|
+
? (href) => {
|
|
99
|
+
beforeNavigate();
|
|
100
|
+
onNavigate(href);
|
|
101
|
+
setCurrentPath(href);
|
|
102
|
+
}
|
|
103
|
+
: undefined;
|
|
104
|
+
const navNode = navItems.length === 0 ? null : renderNav
|
|
105
|
+
? renderNav({
|
|
106
|
+
items: navItems,
|
|
107
|
+
currentPath,
|
|
108
|
+
onNavigate: navigate ?? ((href) => window.location.assign(href)),
|
|
109
|
+
})
|
|
110
|
+
: navigate
|
|
111
|
+
? _jsx(NavBar, { items: navItems, currentPath: currentPath, onNavigate: navigate })
|
|
112
|
+
: _jsx(NavBar, { items: navItems });
|
|
68
113
|
const shellContext = {
|
|
69
114
|
app,
|
|
70
115
|
appName,
|
|
@@ -73,11 +118,13 @@ export function ProShell({ app, children, appName, allowFree = true, showThemeTo
|
|
|
73
118
|
textSizeToggle: _jsx(TextSizeToggle, {}),
|
|
74
119
|
profileMenu,
|
|
75
120
|
proBadge: subscription?.status === 'active' ? _jsx(ProBadge, {}) : null,
|
|
121
|
+
nav: navNode,
|
|
76
122
|
};
|
|
77
|
-
const topbar = renderTopbar ? renderTopbar(shellContext) : hideTopbar ? null : (_jsxs("header", { style: styles.topbar, children: [_jsxs("div", { style: styles.topbarLeft, children: [_jsx("a", { href: "https://proappstore.online", style: styles.logoLink, children: "Pro" }), appName && _jsx("span", { style: styles.appName, children: appName }), shellContext.proBadge] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '0.5rem' }, children: [shellContext.textSizeToggle, shellContext.profileMenu] })] }));
|
|
123
|
+
const topbar = renderTopbar ? renderTopbar(shellContext) : hideTopbar ? null : (_jsxs("header", { style: styles.topbar, children: [_jsxs("div", { style: styles.topbarLeft, children: [_jsx("a", { href: "https://proappstore.online", style: styles.logoLink, children: "Pro" }), appName && _jsx("span", { style: styles.appName, children: appName }), shellContext.proBadge] }), shellContext.nav, _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '0.5rem' }, children: [shellContext.textSizeToggle, shellContext.profileMenu] })] }));
|
|
78
124
|
const footer = renderFooter ? renderFooter(shellContext) : hideFooter ? null : (_jsxs("footer", { style: styles.footer, children: ["Part of", ' ', _jsx("a", { href: "https://proappstore.online", style: { color: 'var(--accent)', fontWeight: 600, textDecoration: 'none' }, children: "ProAppStore" })] }));
|
|
125
|
+
const loading = renderLoading ? renderLoading() : (_jsx("div", { className: "pas-shell-loading flex flex-1 items-center justify-center px-4 py-12", children: _jsx(Spinner, { size: 28 }) }));
|
|
79
126
|
// --- Ready: render app with topbar ---
|
|
80
|
-
return (_jsx(ProProvider, { app: app, children: _jsxs("div", { style: styles.shell, children: [topbar, _jsx("main", { style: styles.main, children: children }), footer] }) }));
|
|
127
|
+
return (_jsx(ProProvider, { app: app, children: _jsx(ToastProvider, { children: _jsxs("div", { style: styles.shell, children: [_jsx(SkipLink, { mainRef: mainRef }), topbar, _jsx(OfflineBanner, {}), _jsx("main", { id: "main", ref: mainRef, tabIndex: -1, className: "pas-main", style: styles.main, children: _jsx(ShellErrorBoundary, { app: app, renderError: renderError, resetKey: currentPath, children: _jsx(Suspense, { fallback: loading, children: children }) }) }), footer] }) }) }));
|
|
81
128
|
}
|
|
82
129
|
const menuItemStyle = {
|
|
83
130
|
display: 'block', width: '100%', padding: '0.5rem 1rem',
|
package/dist/shell.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../src/shell.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAkB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../src/shell.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAInH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAgB,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,qBAAqB,GAEtB,MAAM,uBAAuB,CAAC;AAiG/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,GAAG,EACH,QAAQ,EACR,OAAO,EACP,GAAG,EACH,SAAS,EACT,UAAU,EACV,SAAS,GAAG,IAAI,EAChB,eAAe,GAAG,IAAI,EACtB,SAAS,EACT,UAAU,GAAG,KAAK,EAClB,UAAU,GAAG,KAAK,EAClB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,aAAa,GACC;IACd,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAC;IAC5E,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAO,SAAS,CAAC,CAAC;IAClD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,cAAc,EAAE,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAc,IAAI,CAAC,CAAC;IAC1C,MAAM,cAAc,GAAG,qBAAqB,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,KAAK,SAAS,CAAC,CAAC;IAE7F,kBAAkB,CAAC,GAAG,EAAE;QACtB,IAAI,QAAQ,CAAC,cAAc,CAAC,eAAe,CAAC;YAAE,OAAO;QACrD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9C,KAAK,CAAC,EAAE,GAAG,eAAe,CAAC;QAC3B,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,gFAAgF;IAChF,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,GAAG,IAAI,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IAC5F,MAAM,QAAQ,GAAG,UAAU,EAAE,KAAK,CAAC;IACnC,eAAe,CAAC,GAAG,EAAE;QACnB,IAAI,QAAQ;YAAE,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC;IAC1C,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IAE5B,SAAS,CAAC,GAAG,EAAE;QACb,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE;YAC7B,OAAO,CAAC,CAAC,CAAC,CAAC;YACX,IAAI,CAAC,CAAC;gBAAE,OAAO,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEV,iCAAiC;IACjC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACrC,eAAe,CAAC,GAAG,CAAC,CAAC;YACrB,IAAI,SAAS,IAAI,GAAG,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC1C,OAAO,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,iBAAiB,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YACZ,eAAe,CAAC,IAAI,CAAC,CAAC;YACtB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;IAE3B,gBAAgB;IAChB,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,KAAC,UAAU,IAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAI,CAAC;IAChE,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,KAAC,UAAU,IAAC,IAAI,EAAC,YAAY,EAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAI,CAAC;IACtE,CAAC;IAED,MAAM,WAAW,GAAG,CAClB,KAAC,WAAW,IAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,eAAe,YACpD,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAC3B,iBAAgB,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,YAAG,IAAI,CAAC,KAAK,IAA3D,CAAC,CAAoE,CACnF,CAAC,GACU,CACf,CAAC;IAEF,+EAA+E;IAC/E,sEAAsE;IACtE,MAAM,QAAQ,GAAG,UAAU;QACzB,CAAC,CAAC,CAAC,IAAY,EAAE,EAAE;YACjB,cAAc,EAAE,CAAC;YACjB,UAAU,CAAC,IAAI,CAAC,CAAC;YACjB,cAAc,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QACD,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACtD,CAAC,CAAC,SAAS,CAAC;YACV,KAAK,EAAE,QAAQ;YACf,WAAW;YACX,UAAU,EAAE,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;SACjE,CAAC;QACF,CAAC,CAAC,QAAQ;YACR,CAAC,CAAC,KAAC,MAAM,IAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,GAAI;YAC7E,CAAC,CAAC,KAAC,MAAM,IAAC,KAAK,EAAE,QAAQ,GAAI,CAAC;IAElC,MAAM,YAAY,GAA0B;QAC1C,GAAG;QACH,OAAO;QACP,IAAI;QACJ,YAAY;QACZ,cAAc,EAAE,KAAC,cAAc,KAAG;QAClC,WAAW;QACX,QAAQ,EAAE,YAAY,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAC,QAAQ,KAAG,CAAC,CAAC,CAAC,IAAI;QACjE,GAAG,EAAE,OAAO;KACb,CAAC;IAEF,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC7E,kBAAQ,KAAK,EAAE,MAAM,CAAC,MAAM,aAC1B,eAAK,KAAK,EAAE,MAAM,CAAC,UAAU,aAC3B,YAAG,IAAI,EAAC,4BAA4B,EAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,oBAAS,EACnE,OAAO,IAAI,eAAM,KAAK,EAAE,MAAM,CAAC,OAAO,YAAG,OAAO,GAAQ,EACxD,YAAY,CAAC,QAAQ,IAClB,EACL,YAAY,CAAC,GAAG,EACjB,eAAK,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,aACjE,YAAY,CAAC,cAAc,EAC3B,YAAY,CAAC,WAAW,IACrB,IACC,CACV,CAAC;IAEF,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC7E,kBAAQ,KAAK,EAAE,MAAM,CAAC,MAAM,wBAClB,GAAG,EACX,YAAG,IAAI,EAAC,4BAA4B,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,4BAE3G,IACG,CACV,CAAC;IAEF,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAChD,cAAK,SAAS,EAAC,sEAAsE,YACnF,KAAC,OAAO,IAAC,IAAI,EAAE,EAAE,GAAI,GACjB,CACP,CAAC;IAEF,wCAAwC;IACxC,OAAO,CACL,KAAC,WAAW,IAAC,GAAG,EAAE,GAAG,YACrB,KAAC,aAAa,cACd,eAAK,KAAK,EAAE,MAAM,CAAC,KAAK,aACtB,KAAC,QAAQ,IAAC,OAAO,EAAE,OAAO,GAAI,EAC7B,MAAM,EACP,KAAC,aAAa,KAAG,EAEjB,eAAM,EAAE,EAAC,MAAM,EAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,EAAC,UAAU,EAAC,KAAK,EAAE,MAAM,CAAC,IAAI,YACjF,KAAC,kBAAkB,IAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,YAC3E,KAAC,QAAQ,IAAC,QAAQ,EAAE,OAAO,YAAG,QAAQ,GAAY,GAC/B,GAChB,EAEN,MAAM,IACH,GACU,GACF,CACf,CAAC;AACJ,CAAC;AAED,MAAM,aAAa,GAAwB;IACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;IACvD,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IACrD,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS;IACtC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS;CAC3C,CAAC;AAEF,MAAM,MAAM,GAAwC;IAClD,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE;IACxE,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe;QACtE,OAAO,EAAE,aAAa;QACtB,YAAY,EAAE,uBAAuB;QACrC,UAAU,EAAE,cAAc;QAC1B,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE;KACvC;IACD,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE;IACrE,QAAQ,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE;IAC/F,OAAO,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE;IACxE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE;IAC3D,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS;QACzD,KAAK,EAAE,cAAc;QACrB,SAAS,EAAE,uBAAuB;KACnC;CACF,CAAC"}
|
package/dist/ui.d.ts
CHANGED
|
@@ -17,4 +17,10 @@ export { GateScreen } from './ui-gate.js';
|
|
|
17
17
|
export type { GateScreenProps } from './ui-gate.js';
|
|
18
18
|
export { Button, Card, Input, Spinner, Modal, EmptyState, Tabs, Toast } from './ui-base.js';
|
|
19
19
|
export type { ButtonProps, ButtonVariant, CardProps, InputProps, SpinnerProps, ModalProps, EmptyStateProps, TabItem, TabsProps, ToastProps, ToastVariant, } from './ui-base.js';
|
|
20
|
+
export { NavBar } from './navbar.js';
|
|
21
|
+
export type { NavBarProps, NavItem } from './navbar.js';
|
|
22
|
+
export { useToast, useOnline } from './shell-resilience.js';
|
|
23
|
+
export type { ToastApi, ToastOptions, ShellToastVariant } from './shell-resilience.js';
|
|
24
|
+
export { PageHeader, useDocumentTitle } from './page.js';
|
|
25
|
+
export type { PageHeaderProps } from './page.js';
|
|
20
26
|
//# sourceMappingURL=ui.d.ts.map
|
package/dist/ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChH,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC5F,YAAY,EACV,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAC3E,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,GAC9D,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChH,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC5F,YAAY,EACV,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAC3E,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,GAC9D,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGxD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/ui.js
CHANGED
|
@@ -17,4 +17,9 @@ export { ProProfilePage } from './ui-profile-page.js';
|
|
|
17
17
|
export { GateScreen } from './ui-gate.js';
|
|
18
18
|
// General-purpose primitives (Button, Card, Input, Modal, Spinner, Tabs, Toast, EmptyState)
|
|
19
19
|
export { Button, Card, Input, Spinner, Modal, EmptyState, Tabs, Toast } from './ui-base.js';
|
|
20
|
+
// NavBar (#235) — the app's main navigation; ProShell renders it from its `nav` prop
|
|
21
|
+
export { NavBar } from './navbar.js';
|
|
22
|
+
// Shell feedback + page helpers (#236) — useToast needs <ProShell>; the rest work anywhere
|
|
23
|
+
export { useToast, useOnline } from './shell-resilience.js';
|
|
24
|
+
export { PageHeader, useDocumentTitle } from './page.js';
|
|
20
25
|
//# sourceMappingURL=ui.js.map
|
package/dist/ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,4BAA4B;AAC5B,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzE,mDAAmD;AACnD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAShH,6BAA6B;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,iBAAiB;AACjB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,aAAa;AACb,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,4FAA4F;AAC5F,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,4BAA4B;AAC5B,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzE,mDAAmD;AACnD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAShH,6BAA6B;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,iBAAiB;AACjB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,aAAa;AACb,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,4FAA4F;AAC5F,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAM5F,qFAAqF;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,2FAA2F;AAC3F,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proappstore/sdk",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.58",
|
|
4
4
|
"description": "Browser SDK for paid apps on proappstore.online — subscriptions, license keys, premium modules.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"./ui": {
|
|
23
23
|
"types": "./dist/ui.d.ts",
|
|
24
24
|
"import": "./dist/ui.js"
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
|
+
"./shell.css": "./dist/shell.css"
|
|
26
27
|
},
|
|
27
28
|
"repository": {
|
|
28
29
|
"type": "git",
|
|
@@ -43,12 +44,14 @@
|
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@types/react": "^19.0.0",
|
|
47
|
+
"@types/react-dom": "^19.3.0",
|
|
46
48
|
"react": "^19.0.0",
|
|
49
|
+
"react-dom": "19.2.6",
|
|
47
50
|
"typescript": "^5.7.0"
|
|
48
51
|
},
|
|
49
52
|
"sideEffects": false,
|
|
50
53
|
"scripts": {
|
|
51
|
-
"build": "tsc",
|
|
54
|
+
"build": "tsc && node scripts/emit-shell-css.mjs",
|
|
52
55
|
"typecheck": "tsc --noEmit"
|
|
53
56
|
}
|
|
54
57
|
}
|