@burdenoff/fe-libs 2026.1021.9 → 2026.1021.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chrome/AppShellLayout.d.ts +14 -0
- package/dist/chrome/AppShellLayout.js +40 -34
- package/dist/shared/assistant/api.d.ts +2 -5
- package/dist/shared/assistant/api.js +21 -6
- package/dist/shared/assistant/conversation.d.ts +2 -5
- package/dist/shared/assistant/product.d.ts +2 -5
- package/dist/shared/assistant/turnProgress.d.ts +2 -5
- package/dist/shared/assistant/types.d.ts +10 -4
- package/dist/shared/assistant/usageReporting.d.ts +2 -4
- package/dist/shared/assistant/usageReporting.js +14 -2
- package/dist/shared/components/SkipToContent.d.ts +95 -0
- package/dist/shared/components/SkipToContent.js +61 -0
- package/dist/shared/components/index.d.ts +2 -0
- package/dist/shared/pages/AiPage.js +49 -48
- package/dist/shared-components.js +23 -22
- package/dist/shared.js +98 -97
- package/dist/ui/modern-landing.d.ts +4 -0
- package/dist/ui/modern-landing.js +129 -125
- package/dist/ui/native-welcome.js +56 -55
- package/package.json +1 -1
|
@@ -52,6 +52,18 @@ export interface AppShellLayoutProps {
|
|
|
52
52
|
* `bottomBar` + `NativeTopBar`.
|
|
53
53
|
*/
|
|
54
54
|
nativeCompact?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Id of the `<main>` landmark, which the skip link targets.
|
|
57
|
+
* Default `'main-content'` (`MAIN_CONTENT_ID`).
|
|
58
|
+
*/
|
|
59
|
+
mainId?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Render the visually-hidden "Skip to content" link as the first focusable
|
|
62
|
+
* element of the shell (WCAG 2.4.1). Default `true`.
|
|
63
|
+
*/
|
|
64
|
+
skipLink?: boolean;
|
|
65
|
+
/** Overrides the skip link text (default: the `appShell.skipToContent` shell label). */
|
|
66
|
+
skipLinkLabel?: string;
|
|
55
67
|
}
|
|
56
68
|
/**
|
|
57
69
|
* AppShellLayout Component
|
|
@@ -64,6 +76,8 @@ export interface AppShellLayoutProps {
|
|
|
64
76
|
* - Visibility controls for each section
|
|
65
77
|
* - Responsive layout: overlay on mobile, push on desktop
|
|
66
78
|
* - Custom content styling
|
|
79
|
+
* - One `<main id="main-content">` landmark plus a "Skip to content" link
|
|
80
|
+
* ahead of the header (keyboard users bypass the header and nav)
|
|
67
81
|
*
|
|
68
82
|
* Responsive Behavior:
|
|
69
83
|
* - Mobile (< md): Sidebar as overlay drawer with backdrop
|
|
@@ -1,50 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MAIN_CONTENT_ID as e, MainLandmark as t, SkipToContentLink as n } from "../shared/components/SkipToContent.js";
|
|
2
|
+
import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
2
3
|
//#region src/chrome/AppShellLayout.tsx
|
|
3
|
-
var
|
|
4
|
-
let
|
|
5
|
-
paddingTop:
|
|
6
|
-
paddingBottom:
|
|
4
|
+
var o = ({ header: o, sidebar: s, footer: c, bottomPanel: l, rightPanel: u, statusBar: d, children: f, headerVisible: p = !0, footerVisible: m = !0, sidebarVisible: h = !0, contentClassName: g, contentPadding: _ = "px-6 lg:px-8 py-6", footerInContent: v = !1, safeArea: y = !0, bottomBar: b, nativeCompact: x = !1, mainId: S = e, skipLink: C = !0, skipLinkLabel: w }) => {
|
|
5
|
+
let T = x ? "p-0" : _, E = v ? `flex-1 overflow-auto bg-bg-canvas flex flex-col ${T}` : `flex-1 overflow-auto bg-bg-canvas ${T}`, D = g || E, O = "max(var(--safe-top, 0px), env(safe-area-inset-top, 0px))", k = "max(var(--safe-bottom, 0px), env(safe-area-inset-bottom, 0px))", A = "max(var(--safe-left, 0px), env(safe-area-inset-left, 0px))", j = "max(var(--safe-right, 0px), env(safe-area-inset-right, 0px))", M = y ? x ? {
|
|
6
|
+
paddingTop: x && p && o ? void 0 : O,
|
|
7
|
+
paddingBottom: b ? void 0 : k
|
|
7
8
|
} : {
|
|
8
|
-
paddingTop:
|
|
9
|
-
paddingBottom:
|
|
10
|
-
paddingLeft:
|
|
11
|
-
paddingRight:
|
|
12
|
-
} : {},
|
|
13
|
-
...
|
|
14
|
-
...
|
|
15
|
-
paddingLeft:
|
|
16
|
-
paddingRight:
|
|
9
|
+
paddingTop: O,
|
|
10
|
+
paddingBottom: k,
|
|
11
|
+
paddingLeft: A,
|
|
12
|
+
paddingRight: j
|
|
13
|
+
} : {}, N = b || x && y ? {
|
|
14
|
+
...b ? { paddingBottom: "var(--mobile-tabbar-height, 0px)" } : {},
|
|
15
|
+
...x && y ? {
|
|
16
|
+
paddingLeft: A,
|
|
17
|
+
paddingRight: j
|
|
17
18
|
} : {}
|
|
18
19
|
} : void 0;
|
|
19
|
-
return /* @__PURE__ */
|
|
20
|
+
return /* @__PURE__ */ a("div", {
|
|
20
21
|
className: "flex flex-col h-screen bg-bg-canvas",
|
|
21
|
-
style:
|
|
22
|
-
"data-native-shell":
|
|
22
|
+
style: M,
|
|
23
|
+
"data-native-shell": x ? "" : void 0,
|
|
23
24
|
children: [
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
C && /* @__PURE__ */ i(n, {
|
|
26
|
+
targetId: S,
|
|
27
|
+
label: w
|
|
28
|
+
}),
|
|
29
|
+
p && o,
|
|
30
|
+
/* @__PURE__ */ a("div", {
|
|
26
31
|
className: "flex flex-1 overflow-hidden relative",
|
|
27
|
-
children: [
|
|
32
|
+
children: [h && s, /* @__PURE__ */ a("div", {
|
|
28
33
|
className: "flex flex-1 overflow-hidden",
|
|
29
|
-
children: [/* @__PURE__ */
|
|
34
|
+
children: [/* @__PURE__ */ a("div", {
|
|
30
35
|
className: "flex flex-col flex-1 overflow-hidden",
|
|
31
|
-
children: [/* @__PURE__ */ t
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
children: [/* @__PURE__ */ i(t, {
|
|
37
|
+
id: S,
|
|
38
|
+
className: `scrollbar-slim ${D}`,
|
|
39
|
+
style: N,
|
|
34
40
|
"data-shell-scroll-container": !0,
|
|
35
|
-
children:
|
|
36
|
-
className:
|
|
37
|
-
children:
|
|
38
|
-
}),
|
|
39
|
-
}),
|
|
40
|
-
}),
|
|
41
|
+
children: v ? /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i("div", {
|
|
42
|
+
className: m ? "flex-1" : "flex-1 min-h-0",
|
|
43
|
+
children: f
|
|
44
|
+
}), m && c] }) : f
|
|
45
|
+
}), l]
|
|
46
|
+
}), u]
|
|
41
47
|
})]
|
|
42
48
|
}),
|
|
43
|
-
!
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
!v && m && c,
|
|
50
|
+
d,
|
|
51
|
+
b
|
|
46
52
|
]
|
|
47
53
|
});
|
|
48
54
|
};
|
|
49
55
|
//#endregion
|
|
50
|
-
export {
|
|
56
|
+
export { o as AppShellLayout };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AssistantUiCatalogue } from './uiActions/uiCatalogue';
|
|
2
|
-
import { AssistantMode, AssistantPromptPart, AssistantRawMessage, AssistantSandboxAuthContext, AssistantArtifact, AssistantSessionInfo, DownloadedAssistantArtifact, StreamAccess } from './types';
|
|
2
|
+
import { AssistantMode, AssistantPromptPart, AssistantRawMessage, AssistantTokenUsage, AssistantSandboxAuthContext, AssistantArtifact, AssistantSessionInfo, DownloadedAssistantArtifact, StreamAccess } from './types';
|
|
3
3
|
import { SandboxWriteCapabilities, WriteApprovalMode, WriteExecutionState } from './writeProposals';
|
|
4
4
|
import { WriteReplyKind, WriteReplyOrigin } from './writeReplyBinder';
|
|
5
5
|
/**
|
|
@@ -568,7 +568,4 @@ export declare function downloadAssistantArtifact(sandboxId: string, workspaceId
|
|
|
568
568
|
*/
|
|
569
569
|
mode: AssistantMode | undefined, authContext: AssistantSandboxAuthContext): Promise<DownloadedAssistantArtifact>;
|
|
570
570
|
export declare function checkAssistantAiCredits(workspaceId: string, authContext: AssistantSandboxAuthContext): Promise<boolean>;
|
|
571
|
-
export declare function reportAssistantAiTokenUsage(workspaceId: string, sessionId: string, messageId: string, model: string | undefined, tokens:
|
|
572
|
-
input: number;
|
|
573
|
-
output: number;
|
|
574
|
-
}, authContext: AssistantSandboxAuthContext): Promise<void>;
|
|
571
|
+
export declare function reportAssistantAiTokenUsage(workspaceId: string, sessionId: string, messageId: string, model: string | undefined, tokens: AssistantTokenUsage, authContext: AssistantSandboxAuthContext): Promise<void>;
|
|
@@ -594,20 +594,35 @@ async function We(e, t) {
|
|
|
594
594
|
authContext: t
|
|
595
595
|
})).checkAiCredits;
|
|
596
596
|
}
|
|
597
|
-
async function Ge(e, t, n, r,
|
|
598
|
-
let
|
|
599
|
-
|
|
597
|
+
async function Ge(e, t, n, r, o, s) {
|
|
598
|
+
let c = Math.max(0, Math.round(o.input ?? 0)), l = Math.max(0, Math.round(o.output ?? 0)), u = Math.max(0, Math.round(o.cache?.read ?? 0)), d = Math.max(0, Math.round(o.cache?.write ?? 0));
|
|
599
|
+
if (c + l + u + d === 0 || !r) return;
|
|
600
|
+
let f = !1;
|
|
601
|
+
if (o.cache) try {
|
|
602
|
+
f = (await i({
|
|
603
|
+
query: "query AiCacheTokensSupported { aiCacheTokensSupported }",
|
|
604
|
+
operationName: "AiCacheTokensSupported",
|
|
605
|
+
variables: {},
|
|
606
|
+
workspaceId: e,
|
|
607
|
+
authContext: s
|
|
608
|
+
})).aiCacheTokensSupported === !0;
|
|
609
|
+
} catch {}
|
|
610
|
+
await a({
|
|
600
611
|
query: ee,
|
|
601
612
|
operationName: "ReportAiTokenUsage",
|
|
602
613
|
variables: { input: {
|
|
603
614
|
sessionId: t,
|
|
604
615
|
messageId: n,
|
|
605
616
|
model: r,
|
|
606
|
-
inputTokens:
|
|
607
|
-
outputTokens:
|
|
617
|
+
inputTokens: c,
|
|
618
|
+
outputTokens: l,
|
|
619
|
+
...f ? {
|
|
620
|
+
cacheReadTokens: u,
|
|
621
|
+
cacheWriteTokens: d
|
|
622
|
+
} : {}
|
|
608
623
|
} },
|
|
609
624
|
workspaceId: e,
|
|
610
|
-
authContext:
|
|
625
|
+
authContext: s
|
|
611
626
|
});
|
|
612
627
|
}
|
|
613
628
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PendingWrite } from './pendingWrite';
|
|
2
2
|
import { WriteProposalMessageRef } from './writeProposalDiscovery';
|
|
3
3
|
import { AssistantMessageAttachment } from './attachments';
|
|
4
|
-
import { AssistantMode } from './types';
|
|
4
|
+
import { AssistantMode, AssistantTokenUsage } from './types';
|
|
5
5
|
export type AssistantSandboxStatus = "none" | "provisioning" | "running" | "stopping" | "error";
|
|
6
6
|
export type AssistantConversationStatus = "idle" | "provisioning" | "connecting" | "streaming" | "complete" | "error";
|
|
7
7
|
/**
|
|
@@ -259,10 +259,7 @@ export interface Message {
|
|
|
259
259
|
role: "user" | "assistant" | "system";
|
|
260
260
|
content: string;
|
|
261
261
|
timestamp: string;
|
|
262
|
-
tokens?:
|
|
263
|
-
input: number;
|
|
264
|
-
output: number;
|
|
265
|
-
};
|
|
262
|
+
tokens?: AssistantTokenUsage;
|
|
266
263
|
metadata?: AssistantMessageMetadata;
|
|
267
264
|
/**
|
|
268
265
|
* ★ BOFF-7335: where this message stands with server history — `pending`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LocalUiCommandOptions } from './localUiCommands';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { AssistantModeConfig } from './conversation';
|
|
4
|
-
import { AssistantMode, PageContext } from './types';
|
|
4
|
+
import { AssistantMode, AssistantTokenUsage, PageContext } from './types';
|
|
5
5
|
import { WriteApprovalMode, WriteProposalView } from './writeProposals';
|
|
6
6
|
/**
|
|
7
7
|
* The sixth argument of `buildPrompt` (BOFF-7803 5a, design §3.5): which write
|
|
@@ -100,10 +100,7 @@ export interface AssistantProductCapabilities {
|
|
|
100
100
|
sessionId: string;
|
|
101
101
|
messageId?: string;
|
|
102
102
|
model?: string;
|
|
103
|
-
tokens:
|
|
104
|
-
input: number;
|
|
105
|
-
output: number;
|
|
106
|
-
};
|
|
103
|
+
tokens: AssistantTokenUsage;
|
|
107
104
|
}) => Promise<void>;
|
|
108
105
|
/**
|
|
109
106
|
* Where the assistant's files land in the workspace file library.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PendingWrite } from './pendingWrite';
|
|
2
2
|
import { AssistantProgressOptions } from './progress';
|
|
3
|
-
import { AssistantRawMessage } from './types';
|
|
3
|
+
import { AssistantRawMessage, AssistantTokenUsage } from './types';
|
|
4
4
|
/** What one poll of the sandbox says this turn has produced so far. */
|
|
5
5
|
export interface AssistantTurnProgress {
|
|
6
6
|
/**
|
|
@@ -35,10 +35,7 @@ export interface AssistantTurnProgress {
|
|
|
35
35
|
*/
|
|
36
36
|
usedTools?: boolean;
|
|
37
37
|
done: boolean;
|
|
38
|
-
tokens?:
|
|
39
|
-
input: number;
|
|
40
|
-
output: number;
|
|
41
|
-
};
|
|
38
|
+
tokens?: AssistantTokenUsage;
|
|
42
39
|
/**
|
|
43
40
|
* Identity + model of the message these tokens came from, needed to charge the
|
|
44
41
|
* turn: `messageId` is half the server's idempotency hash and `model` selects the
|
|
@@ -104,6 +104,15 @@ export type AssistantPromptPart = {
|
|
|
104
104
|
data?: string;
|
|
105
105
|
name?: string;
|
|
106
106
|
};
|
|
107
|
+
/** Runtime input excludes the separately reported provider cache counts. */
|
|
108
|
+
export interface AssistantTokenUsage {
|
|
109
|
+
input: number;
|
|
110
|
+
output: number;
|
|
111
|
+
cache?: {
|
|
112
|
+
read?: number;
|
|
113
|
+
write?: number;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
107
116
|
export interface AssistantRawMessage {
|
|
108
117
|
info?: {
|
|
109
118
|
id?: string;
|
|
@@ -115,10 +124,7 @@ export interface AssistantRawMessage {
|
|
|
115
124
|
parentID?: string;
|
|
116
125
|
providerID?: string;
|
|
117
126
|
modelID?: string;
|
|
118
|
-
tokens?:
|
|
119
|
-
input: number;
|
|
120
|
-
output: number;
|
|
121
|
-
};
|
|
127
|
+
tokens?: AssistantTokenUsage;
|
|
122
128
|
time?: {
|
|
123
129
|
created?: number;
|
|
124
130
|
completed?: number;
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { AssistantSendRefusal } from './turnOutcome';
|
|
2
|
+
import { AssistantTokenUsage } from './types';
|
|
2
3
|
/** One finished turn's charge, as a product's `reportTokenUsage` receives it. */
|
|
3
4
|
export interface UsageReport {
|
|
4
5
|
workspaceId: string;
|
|
5
6
|
sessionId: string;
|
|
6
7
|
messageId?: string;
|
|
7
8
|
model?: string;
|
|
8
|
-
tokens:
|
|
9
|
-
input: number;
|
|
10
|
-
output: number;
|
|
11
|
-
};
|
|
9
|
+
tokens: AssistantTokenUsage;
|
|
12
10
|
}
|
|
13
11
|
/** Sends one report to its ledger. Rejects when the ledger did not record it. */
|
|
14
12
|
export type UsageReporter = (report: UsageReport) => Promise<void>;
|
|
@@ -48,14 +48,26 @@ var v = (e) => typeof e == "number" && Number.isFinite(e) && e >= 0, y = (e) =>
|
|
|
48
48
|
function b(e, t) {
|
|
49
49
|
if (!e || typeof e != "object") return null;
|
|
50
50
|
let n = e, r = n.tokens;
|
|
51
|
-
|
|
51
|
+
if (n.workspaceId !== t || typeof n.sessionId != "string" || n.sessionId.length === 0 || !y(n.messageId) || !y(n.model) || !r || typeof r != "object" || !v(r.input) || !v(r.output)) return null;
|
|
52
|
+
let i;
|
|
53
|
+
if (r.cache !== void 0) {
|
|
54
|
+
if (!r.cache || typeof r.cache != "object" || Array.isArray(r.cache)) return null;
|
|
55
|
+
let e = r.cache;
|
|
56
|
+
if (e.read !== void 0 && !v(e.read) || e.write !== void 0 && !v(e.write)) return null;
|
|
57
|
+
i = {
|
|
58
|
+
...v(e.read) ? { read: e.read } : {},
|
|
59
|
+
...v(e.write) ? { write: e.write } : {}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
52
63
|
workspaceId: t,
|
|
53
64
|
sessionId: n.sessionId,
|
|
54
65
|
...typeof n.messageId == "string" ? { messageId: n.messageId } : {},
|
|
55
66
|
...typeof n.model == "string" ? { model: n.model } : {},
|
|
56
67
|
tokens: {
|
|
57
68
|
input: r.input,
|
|
58
|
-
output: r.output
|
|
69
|
+
output: r.output,
|
|
70
|
+
...i ? { cache: i } : {}
|
|
59
71
|
}
|
|
60
72
|
};
|
|
61
73
|
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Skip link + `<main>` landmark primitives (WCAG 2.4.1 "Bypass Blocks").
|
|
4
|
+
*
|
|
5
|
+
* Every product page needs exactly ONE `<main>` landmark, and a keyboard user
|
|
6
|
+
* needs a way past the header/nav to reach it. The signed-in shell
|
|
7
|
+
* (`AppShellLayout`) and the public landing/auth pages (`PublicLayout`,
|
|
8
|
+
* `ModernLanding`, `NativeWelcome`) all build on these, so the id, the label
|
|
9
|
+
* and the focus behaviour are the same on every product.
|
|
10
|
+
*
|
|
11
|
+
* ★ One `<main>` per page, whatever the nesting. `MainLandmark` marks its
|
|
12
|
+
* subtree; a `MainLandmark` rendered inside another one (a public page
|
|
13
|
+
* mounted inside the signed-in shell, `ModernLanding` wrapped in
|
|
14
|
+
* `PublicLayout`) renders a plain `<div>` instead of a second `<main>`, and
|
|
15
|
+
* a nested `SkipToContentLink` renders nothing, because the outer layout
|
|
16
|
+
* already owns both.
|
|
17
|
+
*/
|
|
18
|
+
/** The id every shared layout gives its `<main>`; the skip link's default target. */
|
|
19
|
+
export declare const MAIN_CONTENT_ID = "main-content";
|
|
20
|
+
/** True inside a `MainLandmark` (so a page-level `<main>` already exists). */
|
|
21
|
+
export declare function useInsideMainLandmark(): boolean;
|
|
22
|
+
/** The minimal element surface `focusSkipTarget` needs (a DOM `HTMLElement` fits). */
|
|
23
|
+
export interface SkipTarget {
|
|
24
|
+
hasAttribute(name: string): boolean;
|
|
25
|
+
setAttribute(name: string, value: string): void;
|
|
26
|
+
focus(options?: FocusOptions): void;
|
|
27
|
+
scrollIntoView?(arg?: boolean | ScrollIntoViewOptions): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Move focus (and the viewport) to the skip-link target.
|
|
31
|
+
*
|
|
32
|
+
* Returns false when there is no target, so the caller can leave the native
|
|
33
|
+
* `#hash` jump alone. A target that is not focusable on its own gets
|
|
34
|
+
* `tabindex="-1"` first: an element that cannot take focus would leave the
|
|
35
|
+
* sequential focus point where it was, and the next Tab would land back in
|
|
36
|
+
* the header.
|
|
37
|
+
*/
|
|
38
|
+
export declare function focusSkipTarget(target: SkipTarget | null): boolean;
|
|
39
|
+
export interface SkipToContentLinkProps {
|
|
40
|
+
/** Id of the element to jump to. Default `MAIN_CONTENT_ID`. */
|
|
41
|
+
targetId?: string;
|
|
42
|
+
/** Visible text when focused. Default: the `appShell.skipToContent` shell label. */
|
|
43
|
+
label?: string;
|
|
44
|
+
className?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* "Skip to content" link: visually hidden until it takes keyboard focus, then
|
|
48
|
+
* pinned to the top-left above all chrome. Render it as the FIRST focusable
|
|
49
|
+
* element of the page, before the header.
|
|
50
|
+
*
|
|
51
|
+
* The click is handled in script rather than left to the `#hash`: under a
|
|
52
|
+
* `HashRouter` (installed apps) a hash change is a route change, and in every
|
|
53
|
+
* router the native jump scrolls without reliably moving focus.
|
|
54
|
+
*/
|
|
55
|
+
export declare function SkipToContentLink({ targetId, label, className, }: SkipToContentLinkProps): import('react/jsx-runtime').JSX.Element | null;
|
|
56
|
+
export interface MainLandmarkProps extends Omit<HTMLAttributes<HTMLElement>, 'id' | 'tabIndex'> {
|
|
57
|
+
/** Element id, the skip link's target. Default `MAIN_CONTENT_ID`. */
|
|
58
|
+
id?: string;
|
|
59
|
+
children?: ReactNode;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The page's `<main>` landmark: `id` for the skip link and `tabIndex={-1}` so
|
|
63
|
+
* focus can land on it (programmatic only; it never joins the Tab order).
|
|
64
|
+
* Inside another `MainLandmark` it renders a `<div>` with no id, so a page
|
|
65
|
+
* never has two `<main>`s or two `#main-content`s.
|
|
66
|
+
*/
|
|
67
|
+
export declare function MainLandmark({ id, className, children, ...rest }: MainLandmarkProps): import('react/jsx-runtime').JSX.Element;
|
|
68
|
+
export interface PublicLayoutProps {
|
|
69
|
+
/** Page header (brand, sign-in button). Rendered between the skip link and `<main>`. */
|
|
70
|
+
header?: ReactNode;
|
|
71
|
+
/** Page footer. Rendered after `<main>`. */
|
|
72
|
+
footer?: ReactNode;
|
|
73
|
+
children: ReactNode;
|
|
74
|
+
/** `<main>` id. Default `MAIN_CONTENT_ID`. */
|
|
75
|
+
mainId?: string;
|
|
76
|
+
/** Overrides the skip link text. */
|
|
77
|
+
skipLinkLabel?: string;
|
|
78
|
+
/** Classes for the outer wrapper. */
|
|
79
|
+
className?: string;
|
|
80
|
+
/** Classes for `<main>` (it already grows to fill the page). */
|
|
81
|
+
mainClassName?: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Landmark frame for public (signed-out) routes: the landing page and the
|
|
85
|
+
* `/auth/*` pages, which render outside `AppShellLayout` and so had no
|
|
86
|
+
* `<main>` and no skip link.
|
|
87
|
+
*
|
|
88
|
+
* ```tsx
|
|
89
|
+
* <PublicLayout header={<LandingHeader />} footer={<LandingFooter />}>
|
|
90
|
+
* <Hero />
|
|
91
|
+
* <Features />
|
|
92
|
+
* </PublicLayout>
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare function PublicLayout({ header, footer, children, mainId, skipLinkLabel, className, mainClassName, }: PublicLayoutProps): import('react/jsx-runtime').JSX.Element;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useShellLabel as e } from "../providers/shell/useShellLabel.js";
|
|
2
|
+
import { cn as t } from "../../shared-utils.js";
|
|
3
|
+
import { createContext as n, useContext as r } from "react";
|
|
4
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
|
+
//#region src/shared/components/SkipToContent.tsx
|
|
6
|
+
var o = "main-content", s = n(!1);
|
|
7
|
+
function c() {
|
|
8
|
+
return r(s);
|
|
9
|
+
}
|
|
10
|
+
function l(e) {
|
|
11
|
+
return e ? (e.hasAttribute("tabindex") || e.setAttribute("tabindex", "-1"), e.focus({ preventScroll: !0 }), e.scrollIntoView?.({ block: "start" }), !0) : !1;
|
|
12
|
+
}
|
|
13
|
+
function u({ targetId: n = o, label: r, className: a }) {
|
|
14
|
+
let s = e();
|
|
15
|
+
return c() ? null : /* @__PURE__ */ i("a", {
|
|
16
|
+
href: `#${n}`,
|
|
17
|
+
onClick: (e) => {
|
|
18
|
+
l(document.getElementById(n)) && e.preventDefault();
|
|
19
|
+
},
|
|
20
|
+
"data-skip-link": "",
|
|
21
|
+
className: t("sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-[var(--z-toast,1400)]", "focus:rounded-lg focus:border focus:border-border-subtle focus:bg-bg-surface focus:px-4 focus:py-2", "focus:text-sm focus:font-medium focus:text-text-primary focus:shadow-elevation-3", "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]", a),
|
|
22
|
+
children: r ?? s("appShell.skipToContent", "Skip to content")
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function d({ id: e = o, className: n, children: r, ...a }) {
|
|
26
|
+
return c() ? /* @__PURE__ */ i("div", {
|
|
27
|
+
className: n,
|
|
28
|
+
...a,
|
|
29
|
+
children: r
|
|
30
|
+
}) : /* @__PURE__ */ i(s.Provider, {
|
|
31
|
+
value: !0,
|
|
32
|
+
children: /* @__PURE__ */ i("main", {
|
|
33
|
+
id: e,
|
|
34
|
+
tabIndex: -1,
|
|
35
|
+
className: t("focus:outline-none", n),
|
|
36
|
+
...a,
|
|
37
|
+
children: r
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function f({ header: e, footer: n, children: r, mainId: s = o, skipLinkLabel: c, className: l, mainClassName: f }) {
|
|
42
|
+
return /* @__PURE__ */ a("div", {
|
|
43
|
+
className: t("flex min-h-[100dvh] flex-col", l),
|
|
44
|
+
"data-public-layout": "",
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ i(u, {
|
|
47
|
+
targetId: s,
|
|
48
|
+
label: c
|
|
49
|
+
}),
|
|
50
|
+
e,
|
|
51
|
+
/* @__PURE__ */ i(d, {
|
|
52
|
+
id: s,
|
|
53
|
+
className: t("flex-1", f),
|
|
54
|
+
children: r
|
|
55
|
+
}),
|
|
56
|
+
n
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { o as MAIN_CONTENT_ID, d as MainLandmark, f as PublicLayout, u as SkipToContentLink, l as focusSkipTarget, c as useInsideMainLandmark };
|
|
@@ -28,6 +28,8 @@ export type { UpgradeInlineBannerProps } from './UpgradeInlineBanner';
|
|
|
28
28
|
export { QuotaUpgradeBridge, useQuotaUpgradeBridge, dispatchProductQuotaExhausted, resolveQuotaUpgradeCopy, quotaEventKind, claimQuotaDialog, captureQuotaDialogOwners, useQuotaDialogOwnership, withQuotaDialogOwnership, DEFAULT_QUOTA_UPGRADE_COPY, } from './QuotaUpgradeBridge';
|
|
29
29
|
export type { QuotaUpgradeBridgeProps, QuotaUpgradeBridgeOptions, QuotaUpgradeCopy, QuotaUpgradeCopyByKind, ProductQuotaExhaustedDetail, } from './QuotaUpgradeBridge';
|
|
30
30
|
export { getSSORedirectUrl, redirectToSSO, SSORedirectSpinner, checkSLO, checkRemoteSLO, clearLocalAuthState, } from './SSORedirectGuard';
|
|
31
|
+
export { MAIN_CONTENT_ID, MainLandmark, PublicLayout, SkipToContentLink, focusSkipTarget, useInsideMainLandmark, } from './SkipToContent';
|
|
32
|
+
export type { MainLandmarkProps, PublicLayoutProps, SkipTarget, SkipToContentLinkProps, } from './SkipToContent';
|
|
31
33
|
export { LandingOrDashboardRedirect, LandingGateView, resolveLandingGate, hasStoredValidSession, } from './LandingOrDashboardRedirect';
|
|
32
34
|
export type { LandingOrDashboardRedirectProps, LandingGateViewProps, LandingGateDecision, LandingGateInput, } from './LandingOrDashboardRedirect';
|
|
33
35
|
export { AssistantWidget, ASSISTANT_WIDGET_TOGGLE_EVENT } from './assistantWidget/AssistantWidget';
|