@anthusai/papyrus 5.41.2 → 5.41.3

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/app/globals.css CHANGED
@@ -10170,3 +10170,36 @@ img {
10170
10170
  }
10171
10171
  }
10172
10172
 
10173
+
10174
+ .papyrus-console-mobile-trigger { display: none; }
10175
+ @media (max-width: 900px) {
10176
+ .edition-progress__button--console { display: none; }
10177
+ .papyrus-console-mobile-trigger {
10178
+ display: inline-flex;
10179
+ align-items: center;
10180
+ justify-content: center;
10181
+ position: fixed;
10182
+ right: 16px;
10183
+ bottom: calc(76px + env(safe-area-inset-bottom));
10184
+ z-index: 1200;
10185
+ min-width: 64px;
10186
+ min-height: 44px;
10187
+ padding: 8px 16px;
10188
+ background: rgb(var(--paper-rgb));
10189
+ color: var(--ink);
10190
+ border: 1px solid currentColor;
10191
+ font: 600 14px Arial, sans-serif;
10192
+ }
10193
+ .papyrus-console-mobile-trigger:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
10194
+ .papyrus-console--open {
10195
+ --papyrus-console-width: 100vw;
10196
+ background: rgb(var(--paper-rgb));
10197
+ height: 100dvh;
10198
+ padding-bottom: env(safe-area-inset-bottom);
10199
+ box-sizing: border-box;
10200
+ }
10201
+ }
10202
+
10203
+ @media (max-width: 900px) {
10204
+ .papyrus-console__header button { min-width: 44px; min-height: 44px; }
10205
+ }
@@ -0,0 +1,68 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState, type ReactNode } from "react";
4
+
5
+ export function PapyrusConsoleFrame({ available, open, reserveSpace, onOpen, onClose, page, children }: {
6
+ available: boolean;
7
+ open: boolean;
8
+ reserveSpace: boolean;
9
+ onOpen: () => void;
10
+ onClose: () => void;
11
+ page: ReactNode;
12
+ children: ReactNode;
13
+ }) {
14
+ const [mobile, setMobile] = useState(false);
15
+ const [viewport, setViewport] = useState<{ top: number; height: number } | null>(null);
16
+ const panel = useRef<HTMLElement>(null);
17
+ const modal = available && open && mobile;
18
+
19
+ useEffect(() => {
20
+ const media = window.matchMedia("(max-width: 900px)");
21
+ const update = () => setMobile(media.matches);
22
+ update();
23
+ media.addEventListener("change", update);
24
+ return () => media.removeEventListener("change", update);
25
+ }, []);
26
+
27
+ useEffect(() => {
28
+ if (!modal) return;
29
+ const visual = window.visualViewport;
30
+ const update = () => setViewport({ top: visual?.offsetTop ?? 0, height: visual?.height ?? window.innerHeight });
31
+ update();
32
+ visual?.addEventListener("resize", update);
33
+ visual?.addEventListener("scroll", update, { passive: true });
34
+ return () => {
35
+ visual?.removeEventListener("resize", update);
36
+ visual?.removeEventListener("scroll", update);
37
+ };
38
+ }, [modal]);
39
+
40
+ useEffect(() => {
41
+ if (!modal) return;
42
+ const previous = document.activeElement;
43
+ const frame = requestAnimationFrame(() => panel.current?.querySelector<HTMLElement>("button")?.focus());
44
+ return () => {
45
+ cancelAnimationFrame(frame);
46
+ requestAnimationFrame(() => {
47
+ if (previous instanceof HTMLElement && previous !== document.body && previous.isConnected && !previous.closest("[inert]")) previous.focus();
48
+ else Array.from(document.querySelectorAll<HTMLElement>(".papyrus-console-mobile-trigger, .edition-progress__button--console, .papyrus-console__header button")).find(element => element.getClientRects().length > 0)?.focus();
49
+ });
50
+ };
51
+ }, [modal]);
52
+
53
+ return <>
54
+ <div className={reserveSpace ? "papyrus-console-page papyrus-console-page--open" : "papyrus-console-page"} inert={modal || undefined}>{page}</div>
55
+ {available && !open ? <button className="papyrus-console-mobile-trigger" type="button" aria-label="Open private chat" aria-expanded={false} aria-controls="papyrus-console-panel" onClick={onOpen}>Chat</button> : null}
56
+ {available ? <aside ref={panel} id="papyrus-console-panel" className={open ? "papyrus-console papyrus-console--open" : "papyrus-console"} aria-label="Papyrus console" role={modal ? "dialog" : undefined} aria-modal={modal || undefined}
57
+ style={modal && viewport ? { top: viewport.top, height: viewport.height, bottom: "auto" } : undefined}
58
+ onKeyDown={event => {
59
+ if (!modal) return;
60
+ if (event.key === "Escape") { event.preventDefault(); onClose(); return; }
61
+ if (event.key !== "Tab") return;
62
+ const focusable = Array.from(panel.current?.querySelectorAll<HTMLElement>('button:not(:disabled), a[href], input:not(:disabled), textarea:not(:disabled), select:not(:disabled), [tabindex="0"]') ?? []).filter(element => element.getClientRects().length > 0);
63
+ const first = focusable[0], last = focusable.at(-1);
64
+ if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last?.focus(); }
65
+ else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first?.focus(); }
66
+ }}>{children}</aside> : null}
67
+ </>;
68
+ }
@@ -35,6 +35,7 @@ import {
35
35
  type ReaderMotionSetting,
36
36
  } from "./reader-settings";
37
37
  import { PapyrusConsoleConversation, type ConsoleConversationMessage } from "./papyrus-console-conversation";
38
+ import { PapyrusConsoleFrame } from "./papyrus-console-frame";
38
39
  import { PapyrusPrivateChatPanel } from "./papyrus-private-chat-panel";
39
40
  import { ModelSelector } from "./ai-elements/model-selector";
40
41
  import { Suggestion, Suggestions } from "./ai-elements/suggestion";
@@ -358,20 +359,15 @@ export function PapyrusConsoleShell({ children, privateChatEnabled = false }: Pa
358
359
 
359
360
  return (
360
361
  <PapyrusConsoleContext.Provider value={consoleContext}>
361
- <div className={canUseConsole && open ? "papyrus-console-page papyrus-console-page--open" : "papyrus-console-page"}>
362
- {children}
363
- </div>
364
- {shouldOfferConsole ? (
365
- <aside className={open ? "papyrus-console papyrus-console--open" : "papyrus-console"} aria-label="Papyrus console">
366
- {open ? (
367
- canUseConsole
368
- ? privateChatEnabled
369
- ? <PapyrusPrivateChatPanel onClose={toggleOpen} />
370
- : <ConsolePanel actorEmail={session?.auth.status === "signedIn" ? (session.auth.email ?? null) : null} actorLabel={session?.auth.label ?? "Papyrus editor"} onClose={toggleOpen} />
371
- : <ConsoleAccessPanel onClose={toggleOpen} session={session} />
372
- ) : null}
373
- </aside>
374
- ) : null}
362
+ <PapyrusConsoleFrame available={shouldOfferConsole} open={open} reserveSpace={canUseConsole && open} onClose={toggleOpen} onOpen={openConsole} page={children}>
363
+ {open ? (
364
+ canUseConsole
365
+ ? privateChatEnabled
366
+ ? <PapyrusPrivateChatPanel onClose={toggleOpen} />
367
+ : <ConsolePanel actorEmail={session?.auth.status === "signedIn" ? (session.auth.email ?? null) : null} actorLabel={session?.auth.label ?? "Papyrus editor"} onClose={toggleOpen} />
368
+ : <ConsoleAccessPanel onClose={toggleOpen} session={session} />
369
+ ) : null}
370
+ </PapyrusConsoleFrame>
375
371
  </PapyrusConsoleContext.Provider>
376
372
  );
377
373
  }
package/package.json CHANGED
@@ -118,6 +118,7 @@
118
118
  "./components/newsroom-topics-view": "./components/newsroom-topics-view.tsx",
119
119
  "./components/notification-center": "./components/notification-center.tsx",
120
120
  "./components/papyrus-console-conversation": "./components/papyrus-console-conversation.tsx",
121
+ "./components/papyrus-console-frame": "./components/papyrus-console-frame.tsx",
121
122
  "./components/papyrus-console-shell": "./components/papyrus-console-shell.tsx",
122
123
  "./components/papyrus-private-chat-panel": "./components/papyrus-private-chat-panel.tsx",
123
124
  "./components/pictogram-figure": "./components/pictogram-figure.tsx",
@@ -458,7 +459,7 @@
458
459
  "optional": true
459
460
  }
460
461
  },
461
- "version": "5.41.2",
462
+ "version": "5.41.3",
462
463
  "dependencies": {
463
464
  "@aws-amplify/adapter-nextjs": "^1.7.3",
464
465
  "@aws-crypto/sha256-js": "5.2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.41.2",
2
+ "version": "5.41.3",
3
3
  "routes": [
4
4
  {
5
5
  "file": "app/%5F_preview/[[...path]]/route.ts",