@guuey/agent-layout 0.16.0
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/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/bind.d.ts +56 -0
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/machine.d.ts +59 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +52 -0
- package/dist/react.d.ts +109 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +121 -0
- package/dist/tones.d.ts +79 -0
- package/dist/tones.d.ts.map +1 -0
- package/dist/tones.js +131 -0
- package/package.json +55 -0
- package/src/bind.ts +73 -0
- package/src/index.ts +54 -0
- package/src/machine.ts +76 -0
- package/src/react.tsx +305 -0
- package/src/tones.ts +156 -0
- package/styles.css +180 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Loqu, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# @guuey/agent-layout
|
|
2
|
+
|
|
3
|
+
**Agent-mode layout** — the layout category for surfaces where an app and its
|
|
4
|
+
agent share one screen: app menus in the upper sidebar, the agent rail below,
|
|
5
|
+
and a content pane whose ground **follows the user's attention** between the
|
|
6
|
+
two. Address the agent and the pane takes the agent's tone; navigate and it
|
|
7
|
+
returns to the app's. One law: _layout follows attention; transport owns the
|
|
8
|
+
stream_ — the tone flips on submit, never on stream events, and interrupting
|
|
9
|
+
is the transport's business.
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import {
|
|
13
|
+
AgentModeProvider,
|
|
14
|
+
AgentModeShell,
|
|
15
|
+
AgentModeSidebar,
|
|
16
|
+
SidebarPanel,
|
|
17
|
+
ActivePane,
|
|
18
|
+
bindGuueyChat,
|
|
19
|
+
useAgentMode,
|
|
20
|
+
} from "@guuey/agent-layout/react";
|
|
21
|
+
import "@guuey/agent-layout/styles.css";
|
|
22
|
+
|
|
23
|
+
function Shell() {
|
|
24
|
+
const { dispatch } = useAgentMode();
|
|
25
|
+
return (
|
|
26
|
+
<AgentModeShell>
|
|
27
|
+
<AgentModeSidebar>
|
|
28
|
+
<SidebarPanel section="app">{/* your menus — zero wiring */}</SidebarPanel>
|
|
29
|
+
<SidebarPanel section="agent">
|
|
30
|
+
<GuueyChat {...bindGuueyChat(dispatch)} />
|
|
31
|
+
</SidebarPanel>
|
|
32
|
+
</AgentModeSidebar>
|
|
33
|
+
<ActivePane>{/* your routes / canvas */}</ActivePane>
|
|
34
|
+
</AgentModeShell>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
<AgentModeProvider mode={mode} navigationKey={pathname} identity={<Logo />}>
|
|
39
|
+
<Shell />
|
|
40
|
+
</AgentModeProvider>;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- **Two tones, calibrated**: the default pair is the founder-certified
|
|
44
|
+
warm-paper/neutral-chrome step, light and dark. Overrides are validated
|
|
45
|
+
against a perceptibility floor (ΔL\* ≥ 6, or a hue-temperature step) —
|
|
46
|
+
two tones that measure alike are rejected with an explanation.
|
|
47
|
+
- **Route-derived follow**: pass your router's location key as
|
|
48
|
+
`navigationKey`; every navigation returns the pane to the app tone with
|
|
49
|
+
zero per-link wiring. Same-page menu clicks are caught by the app panel's
|
|
50
|
+
capture-phase listener.
|
|
51
|
+
- **No stale-content hold**: while the agent has the room and nothing is
|
|
52
|
+
presented yet, the pane shows a working state (your `identity` + pulse),
|
|
53
|
+
never the previous page under the agent's tone.
|
|
54
|
+
- **Mode-aware**: pass the same `mode` you give your chat surface — the lib
|
|
55
|
+
rides your existing light/dark machinery and adds none of its own.
|
|
56
|
+
- **Not a chat dependency**: `bindGuueyChat` pairs with `@guuey/chat`
|
|
57
|
+
structurally; any agent surface can call the machine directly through
|
|
58
|
+
`useAgentMode()`.
|
|
59
|
+
|
|
60
|
+
React DOM only, zero runtime dependencies, `react >= 18` peer.
|
package/dist/bind.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `@guuey/chat` bridge (guuey#403 §4) — pairs with the kit WITHOUT
|
|
3
|
+
* importing it. This package deliberately has NO dependency on
|
|
4
|
+
* `@guuey/chat` (the layout stays consumable by a surface that brings its
|
|
5
|
+
* own agent — ggui console's path calls `agentSubmit()` from
|
|
6
|
+
* `useAgentMode()` directly), so the kit's shapes are mirrored here
|
|
7
|
+
* STRUCTURALLY, the fs-contract discipline:
|
|
8
|
+
*
|
|
9
|
+
* - {@link GuueyChatActivityEventShape} mirrors `GuueyChatActivityEvent`
|
|
10
|
+
* (oss/packages/chat/src/react/guuey-chat.tsx — sync comment on the
|
|
11
|
+
* definition points back here);
|
|
12
|
+
* - {@link PlanViewSummaryShape} mirrors the two fields of
|
|
13
|
+
* `PlanViewSummary` this bridge reads (`key`, `origin`).
|
|
14
|
+
*
|
|
15
|
+
* The template's typecheck is the seam prover: it passes GuueyChat's real
|
|
16
|
+
* callbacks into these structural slots — a drift on either side breaks
|
|
17
|
+
* the template build, never silently.
|
|
18
|
+
*/
|
|
19
|
+
import type { AgentModeInput } from "./machine.js";
|
|
20
|
+
/**
|
|
21
|
+
* Structural mirror of `GuueyChatActivityEvent` (@guuey/chat). `submit`
|
|
22
|
+
* fires on every successful send — composer, `handle.send`, and the
|
|
23
|
+
* `ui/message` doorbell paths alike; `settled` fires when the invoke
|
|
24
|
+
* returns to `ready` (success, error, and abort all settle).
|
|
25
|
+
*/
|
|
26
|
+
export interface GuueyChatActivityEventShape {
|
|
27
|
+
type: "submit" | "settled";
|
|
28
|
+
}
|
|
29
|
+
/** The two roster fields the bridge reads (structural `PlanViewSummary`). */
|
|
30
|
+
export interface PlanViewSummaryShape {
|
|
31
|
+
key: string;
|
|
32
|
+
origin: "live" | "history";
|
|
33
|
+
}
|
|
34
|
+
/** What the bridge needs from the layout side — `useAgentMode().dispatch`. */
|
|
35
|
+
export type AgentModeBinding = (input: AgentModeInput) => void;
|
|
36
|
+
/** The GuueyChat-shaped props {@link bindGuueyChat} returns. */
|
|
37
|
+
export interface GuueyChatBindingProps {
|
|
38
|
+
onActivity: (event: GuueyChatActivityEventShape) => void;
|
|
39
|
+
onViewsChange: (views: readonly PlanViewSummaryShape[]) => void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Wire a GuueyChat surface into the active-panel machine: spread the
|
|
43
|
+
* returned props onto `<GuueyChat>` (or compose them inside your own
|
|
44
|
+
* handlers — each is a plain function).
|
|
45
|
+
*
|
|
46
|
+
* - `submit` → `agentSubmit` (tone flips ON SUBMIT — the §3 law);
|
|
47
|
+
* - `settled` → `agentSettled` (no tone transition; ends the working
|
|
48
|
+
* state and the streaming flag);
|
|
49
|
+
* - a roster change whose LIVE view count GREW → `agentViewMounted`
|
|
50
|
+
* (the founder's (d): content replaced the working state). Counting
|
|
51
|
+
* growth — not presence — keeps earlier turns' lingering live views
|
|
52
|
+
* and rehydrated history views from clearing a fresh submit's pending
|
|
53
|
+
* window spuriously.
|
|
54
|
+
*/
|
|
55
|
+
export declare function bindGuueyChat(dispatch: AgentModeBinding): GuueyChatBindingProps;
|
|
56
|
+
//# sourceMappingURL=bind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC5B;AAED,6EAA6E;AAC7E,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAE/D,gEAAgE;AAChE,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,CAAC,KAAK,EAAE,2BAA2B,KAAK,IAAI,CAAC;IACzD,aAAa,EAAE,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,KAAK,IAAI,CAAC;CACjE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,qBAAqB,CAa/E"}
|
package/dist/bind.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire a GuueyChat surface into the active-panel machine: spread the
|
|
3
|
+
* returned props onto `<GuueyChat>` (or compose them inside your own
|
|
4
|
+
* handlers — each is a plain function).
|
|
5
|
+
*
|
|
6
|
+
* - `submit` → `agentSubmit` (tone flips ON SUBMIT — the §3 law);
|
|
7
|
+
* - `settled` → `agentSettled` (no tone transition; ends the working
|
|
8
|
+
* state and the streaming flag);
|
|
9
|
+
* - a roster change whose LIVE view count GREW → `agentViewMounted`
|
|
10
|
+
* (the founder's (d): content replaced the working state). Counting
|
|
11
|
+
* growth — not presence — keeps earlier turns' lingering live views
|
|
12
|
+
* and rehydrated history views from clearing a fresh submit's pending
|
|
13
|
+
* window spuriously.
|
|
14
|
+
*/
|
|
15
|
+
export function bindGuueyChat(dispatch) {
|
|
16
|
+
let liveCount = 0;
|
|
17
|
+
return {
|
|
18
|
+
onActivity: (event) => {
|
|
19
|
+
if (event.type === "submit")
|
|
20
|
+
dispatch({ type: "agentSubmit" });
|
|
21
|
+
else
|
|
22
|
+
dispatch({ type: "agentSettled" });
|
|
23
|
+
},
|
|
24
|
+
onViewsChange: (views) => {
|
|
25
|
+
const next = views.filter((v) => v.origin === "live").length;
|
|
26
|
+
if (next > liveCount)
|
|
27
|
+
dispatch({ type: "agentViewMounted" });
|
|
28
|
+
liveCount = next;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@guuey/agent-layout` — the agent-mode layout category (guuey#403).
|
|
3
|
+
*
|
|
4
|
+
* Root entry: the pure machine, the tone math, the token names, and the
|
|
5
|
+
* `@guuey/chat` bridge — everything React-free. Components live under
|
|
6
|
+
* `@guuey/agent-layout/react`; the stylesheet under
|
|
7
|
+
* `@guuey/agent-layout/styles.css`.
|
|
8
|
+
*/
|
|
9
|
+
export { agentModeReduce, INITIAL_AGENT_MODE_STATE, type ActivePanel, type AgentModeInput, type AgentModeState, } from "./machine.js";
|
|
10
|
+
export { assertToneFloor, DEFAULT_TONES, deriveTones, hexToLab, meetsToneFloor, mixHex, toneDelta, type TonePair, } from "./tones.js";
|
|
11
|
+
export { bindGuueyChat, type AgentModeBinding, type GuueyChatActivityEventShape, type GuueyChatBindingProps, type PlanViewSummaryShape, } from "./bind.js";
|
|
12
|
+
/**
|
|
13
|
+
* The token vocabulary (§2) — one prefix, kebab-case, `-on` suffix keeps
|
|
14
|
+
* each tone's pair adjacent in sorted listings (platform-ruled naming).
|
|
15
|
+
* `--guuey-layout-pane-tone` is LIB-WRITTEN state: apps read it, never set
|
|
16
|
+
* it — overriding it silently breaks the category's defining behavior.
|
|
17
|
+
*/
|
|
18
|
+
export declare const LAYOUT_TOKENS: {
|
|
19
|
+
readonly toneUpper: "--guuey-layout-tone-upper";
|
|
20
|
+
readonly toneUpperOn: "--guuey-layout-tone-upper-on";
|
|
21
|
+
readonly toneLower: "--guuey-layout-tone-lower";
|
|
22
|
+
readonly toneLowerOn: "--guuey-layout-tone-lower-on";
|
|
23
|
+
readonly paneTone: "--guuey-layout-pane-tone";
|
|
24
|
+
readonly toneTransition: "--guuey-layout-tone-transition";
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The follow fade — founder-certified on the ggui#633 calibration: the
|
|
28
|
+
* eased ~150ms color fade ("arrives fast, lands soft" at panel scale).
|
|
29
|
+
*/
|
|
30
|
+
export declare const DEFAULT_TONE_TRANSITION_MS = 150;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,eAAe,EACf,aAAa,EACb,WAAW,EACX,QAAQ,EACR,cAAc,EACd,MAAM,EACN,SAAS,EACT,KAAK,QAAQ,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC;AAEnB;;;;;GAKG;AACH,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,0BAA0B,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@guuey/agent-layout` — the agent-mode layout category (guuey#403).
|
|
3
|
+
*
|
|
4
|
+
* Root entry: the pure machine, the tone math, the token names, and the
|
|
5
|
+
* `@guuey/chat` bridge — everything React-free. Components live under
|
|
6
|
+
* `@guuey/agent-layout/react`; the stylesheet under
|
|
7
|
+
* `@guuey/agent-layout/styles.css`.
|
|
8
|
+
*/
|
|
9
|
+
export { agentModeReduce, INITIAL_AGENT_MODE_STATE, } from "./machine.js";
|
|
10
|
+
export { assertToneFloor, DEFAULT_TONES, deriveTones, hexToLab, meetsToneFloor, mixHex, toneDelta, } from "./tones.js";
|
|
11
|
+
export { bindGuueyChat, } from "./bind.js";
|
|
12
|
+
/**
|
|
13
|
+
* The token vocabulary (§2) — one prefix, kebab-case, `-on` suffix keeps
|
|
14
|
+
* each tone's pair adjacent in sorted listings (platform-ruled naming).
|
|
15
|
+
* `--guuey-layout-pane-tone` is LIB-WRITTEN state: apps read it, never set
|
|
16
|
+
* it — overriding it silently breaks the category's defining behavior.
|
|
17
|
+
*/
|
|
18
|
+
export const LAYOUT_TOKENS = {
|
|
19
|
+
toneUpper: "--guuey-layout-tone-upper",
|
|
20
|
+
toneUpperOn: "--guuey-layout-tone-upper-on",
|
|
21
|
+
toneLower: "--guuey-layout-tone-lower",
|
|
22
|
+
toneLowerOn: "--guuey-layout-tone-lower-on",
|
|
23
|
+
paneTone: "--guuey-layout-pane-tone",
|
|
24
|
+
toneTransition: "--guuey-layout-tone-transition",
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The follow fade — founder-certified on the ggui#633 calibration: the
|
|
28
|
+
* eased ~150ms color fade ("arrives fast, lands soft" at panel scale).
|
|
29
|
+
*/
|
|
30
|
+
export const DEFAULT_TONE_TRANSITION_MS = 150;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The active-panel machine (guuey#403 §3) — pure data-in/data-out, no React.
|
|
3
|
+
*
|
|
4
|
+
* ONE law (platform's words): **layout follows attention; transport owns
|
|
5
|
+
* the stream.** The tone tracks the user's locus of action — submit flips
|
|
6
|
+
* it ON SUBMIT (not first token, not completion), navigation flips it back,
|
|
7
|
+
* and stream end changes nothing.
|
|
8
|
+
*
|
|
9
|
+
* State beyond the panel itself (the ggui#633 calibration additions):
|
|
10
|
+
*
|
|
11
|
+
* - `streaming` — a turn is in flight. Read by ONE rule only: closing an
|
|
12
|
+
* agent view returns to the menu UNLESS still streaming (the console's
|
|
13
|
+
* shipped behavior).
|
|
14
|
+
* - `pending` — the founder's (d) requirement: on flip to the agent tone
|
|
15
|
+
* with no view mounted yet, the pane must NEVER hold prior page content
|
|
16
|
+
* on the agent ground — it presents the working state immediately.
|
|
17
|
+
* `pending` arms on submit and clears on view-mount, on settle (the
|
|
18
|
+
* answer is in the log even when no view came), and on return-to-menu.
|
|
19
|
+
*
|
|
20
|
+
* The machine is consumed through `useAgentMode()` / the Provider; this
|
|
21
|
+
* module is exported for tests and for non-React hosts that want the exact
|
|
22
|
+
* transition table.
|
|
23
|
+
*/
|
|
24
|
+
export type ActivePanel = "app" | "agent";
|
|
25
|
+
export interface AgentModeState {
|
|
26
|
+
activePanel: ActivePanel;
|
|
27
|
+
/** A turn is in flight (submit → settled). */
|
|
28
|
+
streaming: boolean;
|
|
29
|
+
/** Working-state window: submitted, nothing presented yet (founder (d)). */
|
|
30
|
+
pending: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare const INITIAL_AGENT_MODE_STATE: AgentModeState;
|
|
33
|
+
export type AgentModeInput =
|
|
34
|
+
/** App-side chrome interaction (NavLink click, panel focus) OR a route change. */
|
|
35
|
+
{
|
|
36
|
+
type: "menuInteraction";
|
|
37
|
+
}
|
|
38
|
+
/** The user sent a message — the agent bridge fired. */
|
|
39
|
+
| {
|
|
40
|
+
type: "agentSubmit";
|
|
41
|
+
}
|
|
42
|
+
/** The turn reached `ready`. NO panel transition (platform-ruled: no bounce-back). */
|
|
43
|
+
| {
|
|
44
|
+
type: "agentSettled";
|
|
45
|
+
}
|
|
46
|
+
/** A live view mounted — the working state has been replaced by content. */
|
|
47
|
+
| {
|
|
48
|
+
type: "agentViewMounted";
|
|
49
|
+
}
|
|
50
|
+
/** The user closed an agent view (canvas "back" affordance). */
|
|
51
|
+
| {
|
|
52
|
+
type: "agentViewClosed";
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The transition table (§3, verbatim rules). Pure; last input wins — the
|
|
56
|
+
* transition duration is the only debounce (no timers, no queue).
|
|
57
|
+
*/
|
|
58
|
+
export declare function agentModeReduce(state: AgentModeState, input: AgentModeInput): AgentModeState;
|
|
59
|
+
//# sourceMappingURL=machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,OAAO,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,8CAA8C;IAC9C,SAAS,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,wBAAwB,EAAE,cAKtC,CAAC;AAEF,MAAM,MAAM,cAAc;AACxB,kFAAkF;AAChF;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE;AAC7B,wDAAwD;GACtD;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE;AACzB,sFAAsF;GACpF;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE;AAC1B,4EAA4E;GAC1E;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE;AAC9B,gEAAgE;GAC9D;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEhC;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,GAAG,cAAc,CAkB5F"}
|
package/dist/machine.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The active-panel machine (guuey#403 §3) — pure data-in/data-out, no React.
|
|
3
|
+
*
|
|
4
|
+
* ONE law (platform's words): **layout follows attention; transport owns
|
|
5
|
+
* the stream.** The tone tracks the user's locus of action — submit flips
|
|
6
|
+
* it ON SUBMIT (not first token, not completion), navigation flips it back,
|
|
7
|
+
* and stream end changes nothing.
|
|
8
|
+
*
|
|
9
|
+
* State beyond the panel itself (the ggui#633 calibration additions):
|
|
10
|
+
*
|
|
11
|
+
* - `streaming` — a turn is in flight. Read by ONE rule only: closing an
|
|
12
|
+
* agent view returns to the menu UNLESS still streaming (the console's
|
|
13
|
+
* shipped behavior).
|
|
14
|
+
* - `pending` — the founder's (d) requirement: on flip to the agent tone
|
|
15
|
+
* with no view mounted yet, the pane must NEVER hold prior page content
|
|
16
|
+
* on the agent ground — it presents the working state immediately.
|
|
17
|
+
* `pending` arms on submit and clears on view-mount, on settle (the
|
|
18
|
+
* answer is in the log even when no view came), and on return-to-menu.
|
|
19
|
+
*
|
|
20
|
+
* The machine is consumed through `useAgentMode()` / the Provider; this
|
|
21
|
+
* module is exported for tests and for non-React hosts that want the exact
|
|
22
|
+
* transition table.
|
|
23
|
+
*/
|
|
24
|
+
export const INITIAL_AGENT_MODE_STATE = {
|
|
25
|
+
// A surface opens as the app; the agent earns the room by being addressed.
|
|
26
|
+
activePanel: "app",
|
|
27
|
+
streaming: false,
|
|
28
|
+
pending: false,
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The transition table (§3, verbatim rules). Pure; last input wins — the
|
|
32
|
+
* transition duration is the only debounce (no timers, no queue).
|
|
33
|
+
*/
|
|
34
|
+
export function agentModeReduce(state, input) {
|
|
35
|
+
switch (input.type) {
|
|
36
|
+
case "menuInteraction":
|
|
37
|
+
// Re-follows the user WITHOUT touching the stream (mid-stream click
|
|
38
|
+
// included — interruption semantics live in transport, never here).
|
|
39
|
+
return { ...state, activePanel: "app", pending: false };
|
|
40
|
+
case "agentSubmit":
|
|
41
|
+
return { activePanel: "agent", streaming: true, pending: true };
|
|
42
|
+
case "agentSettled":
|
|
43
|
+
// Stream end changes nothing about the panel — the tone tracks the
|
|
44
|
+
// user's locus of action, not the agent's state.
|
|
45
|
+
return { ...state, streaming: false, pending: false };
|
|
46
|
+
case "agentViewMounted":
|
|
47
|
+
return { ...state, pending: false };
|
|
48
|
+
case "agentViewClosed":
|
|
49
|
+
// Closing a view returns to the menu UNLESS still streaming.
|
|
50
|
+
return state.streaming ? state : { ...state, activePanel: "app" };
|
|
51
|
+
}
|
|
52
|
+
}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@guuey/agent-layout/react` — the Provider + primitives (guuey#403 §4).
|
|
3
|
+
* React DOM only, by design: cross-platform semantics live in
|
|
4
|
+
* `@guuey/chat`'s selection contract (portal's consult on the proposal).
|
|
5
|
+
*
|
|
6
|
+
* Engineering shape (ggui#633's scar, adopted): the active-panel state
|
|
7
|
+
* lives in its OWN provider, separate from any chat/transcript state —
|
|
8
|
+
* shells must never re-render per streaming token. The context value
|
|
9
|
+
* changes ONLY on machine transitions; every callback identity is stable.
|
|
10
|
+
*/
|
|
11
|
+
import { type HTMLAttributes, type ReactNode } from "react";
|
|
12
|
+
import { type ActivePanel, type AgentModeInput } from "./machine.js";
|
|
13
|
+
import { type TonePair } from "./tones.js";
|
|
14
|
+
export interface AgentModeProviderProps {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* The presentation mode — the SAME host-resolved value the surface
|
|
18
|
+
* passes to `<GuueyChat mode>`; this lib rides the existing mode
|
|
19
|
+
* machinery and adds none of its own (the ggui#633 binding rule: never
|
|
20
|
+
* fixed-dark, never a second mode system). Default `"light"`, matching
|
|
21
|
+
* the kit's own default.
|
|
22
|
+
*/
|
|
23
|
+
mode?: "light" | "dark";
|
|
24
|
+
/**
|
|
25
|
+
* Tone override pair for the CURRENT mode (host-palette / app-theme
|
|
26
|
+
* tiers — §2's tier chain). Validated against the perceptibility floor
|
|
27
|
+
* at wiring time (reject-under-floor, explanatory throw). Base defaults
|
|
28
|
+
* (the ggui#633 shipped pair + its dark mirror) apply when absent.
|
|
29
|
+
*/
|
|
30
|
+
tones?: TonePair;
|
|
31
|
+
/** The follow fade in ms — default the founder-certified eased 150. */
|
|
32
|
+
transitionMs?: number;
|
|
33
|
+
/**
|
|
34
|
+
* The surface's identity mark (logo / brand node) for the working state
|
|
35
|
+
* (founder (d)): shown with the built-in spinner while the agent has the
|
|
36
|
+
* room but nothing is presented yet.
|
|
37
|
+
*/
|
|
38
|
+
identity?: ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* The route-derived follow signal (ggui#633's scar: hand-wiring
|
|
41
|
+
* per-link missed 20+ surfaces — sub-nav tabs, in-content links,
|
|
42
|
+
* `router.push`). Pass your router's location key (`usePathname()`,
|
|
43
|
+
* `useLocation().key`, …): ANY change dispatches `menuInteraction`.
|
|
44
|
+
* The initial value dispatches nothing.
|
|
45
|
+
*/
|
|
46
|
+
navigationKey?: unknown;
|
|
47
|
+
}
|
|
48
|
+
export declare function AgentModeProvider({ children, mode, tones, transitionMs, identity, navigationKey, }: AgentModeProviderProps): ReactNode;
|
|
49
|
+
export interface UseAgentModeResult {
|
|
50
|
+
activePanel: ActivePanel;
|
|
51
|
+
/** A turn is in flight (submit → settled). */
|
|
52
|
+
streaming: boolean;
|
|
53
|
+
/** The founder-(d) working-state window is open. */
|
|
54
|
+
pending: boolean;
|
|
55
|
+
/** The raw machine door — `bindGuueyChat(dispatch)` wires a kit surface. */
|
|
56
|
+
dispatch: (input: AgentModeInput) => void;
|
|
57
|
+
/** Escape hatch for surfaces with custom needs (documented as rarely needed). */
|
|
58
|
+
setActivePanel: (panel: ActivePanel) => void;
|
|
59
|
+
/** The <1024px overlay drawer (lib-owned state; Shell renders the toggle). */
|
|
60
|
+
drawerOpen: boolean;
|
|
61
|
+
setDrawerOpen: (open: boolean) => void;
|
|
62
|
+
}
|
|
63
|
+
export declare function useAgentMode(): UseAgentModeResult;
|
|
64
|
+
/**
|
|
65
|
+
* The grid: sidebar column + pane. Below 1024px (the console family's own
|
|
66
|
+
* sidebar boundary — one muscle memory across surfaces) the sidebar leaves
|
|
67
|
+
* the grid and becomes an overlay drawer, and the follow is SUSPENDED —
|
|
68
|
+
* the pane holds the lower (agent) tone (stylesheet-enforced; §4's ruled
|
|
69
|
+
* degraded mode). The drawer toggle renders only at drawer widths.
|
|
70
|
+
*
|
|
71
|
+
* Children: an {@link AgentModeSidebar} (wrapping the two panels) and an
|
|
72
|
+
* {@link ActivePane}. The wrapper is structural — the drawer must slide as
|
|
73
|
+
* ONE element, so the two panels share a positioned parent (the §4 sketch
|
|
74
|
+
* elides it; the contract is unchanged).
|
|
75
|
+
*/
|
|
76
|
+
export declare function AgentModeShell({ children, className, ...rest }: HTMLAttributes<HTMLDivElement>): ReactNode;
|
|
77
|
+
/** The sidebar column: the two panels' shared, drawer-slidable parent. */
|
|
78
|
+
export declare function AgentModeSidebar({ children, className, ...rest }: HTMLAttributes<HTMLElement>): ReactNode;
|
|
79
|
+
export interface SidebarPanelProps extends HTMLAttributes<HTMLDivElement> {
|
|
80
|
+
section: "app" | "agent";
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* One sidebar section. `section="app"` wires `menuInteraction` on
|
|
84
|
+
* pointer/focus interactions inside it (capture-phase — apps write ZERO
|
|
85
|
+
* per-link wiring; this covers same-page clicks the route signal cannot
|
|
86
|
+
* see). `section="agent"` hosts the agent surface and wires nothing — the
|
|
87
|
+
* agent bridge speaks through the machine.
|
|
88
|
+
*/
|
|
89
|
+
export declare function SidebarPanel({ section, children, className, ...rest }: SidebarPanelProps): ReactNode;
|
|
90
|
+
export interface ActivePaneProps extends HTMLAttributes<HTMLDivElement> {
|
|
91
|
+
/**
|
|
92
|
+
* Replaces the built-in working-state treatment (identity + pulse) shown
|
|
93
|
+
* while the agent has the room and nothing is presented yet (founder
|
|
94
|
+
* (d): NEVER hold prior page content on the agent ground).
|
|
95
|
+
*/
|
|
96
|
+
workingState?: ReactNode;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The right pane: paints `--guuey-layout-pane-tone`, animates per the
|
|
100
|
+
* transition token, honors `prefers-reduced-motion` (stylesheet: instant
|
|
101
|
+
* snap). While the founder-(d) window is open the pane presents the
|
|
102
|
+
* working state INSTEAD of its children — prior page content never sits
|
|
103
|
+
* on the agent ground.
|
|
104
|
+
*/
|
|
105
|
+
export declare function ActivePane({ children, workingState, className, ...rest }: ActivePaneProps): ReactNode;
|
|
106
|
+
export { bindGuueyChat } from "./bind.js";
|
|
107
|
+
export type { AgentModeInput, AgentModeState, ActivePanel } from "./machine.js";
|
|
108
|
+
export type { TonePair } from "./tones.js";
|
|
109
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAUL,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAa3E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,IAAc,EACd,KAAK,EACL,YAAyC,EACzC,QAAe,EACf,aAAa,GACd,EAAE,sBAAsB,GAAG,SAAS,CAiDpC;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,8CAA8C;IAC9C,SAAS,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,iFAAiF;IACjF,cAAc,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,8EAA8E;IAC9E,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,YAAY,IAAI,kBAAkB,CAoBjD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACR,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAqB5C;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACR,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG,SAAS,CAUzC;AAED,MAAM,WAAW,iBAAkB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACvE,OAAO,EAAE,KAAK,GAAG,OAAO,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,iBAAiB,GAAG,SAAS,CAcpG;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACrE;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,eAAe,GAAG,SAAS,CAwBrG;AAMD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChF,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* `@guuey/agent-layout/react` — the Provider + primitives (guuey#403 §4).
|
|
4
|
+
* React DOM only, by design: cross-platform semantics live in
|
|
5
|
+
* `@guuey/chat`'s selection contract (portal's consult on the proposal).
|
|
6
|
+
*
|
|
7
|
+
* Engineering shape (ggui#633's scar, adopted): the active-panel state
|
|
8
|
+
* lives in its OWN provider, separate from any chat/transcript state —
|
|
9
|
+
* shells must never re-render per streaming token. The context value
|
|
10
|
+
* changes ONLY on machine transitions; every callback identity is stable.
|
|
11
|
+
*/
|
|
12
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState, } from "react";
|
|
13
|
+
import { agentModeReduce, INITIAL_AGENT_MODE_STATE, } from "./machine.js";
|
|
14
|
+
import { assertToneFloor, DEFAULT_TONES } from "./tones.js";
|
|
15
|
+
import { DEFAULT_TONE_TRANSITION_MS, LAYOUT_TOKENS } from "./index.js";
|
|
16
|
+
const AgentModeContext = createContext(null);
|
|
17
|
+
export function AgentModeProvider({ children, mode = "light", tones, transitionMs = DEFAULT_TONE_TRANSITION_MS, identity = null, navigationKey, }) {
|
|
18
|
+
const [state, dispatch] = useReducer(agentModeReduce, INITIAL_AGENT_MODE_STATE);
|
|
19
|
+
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
20
|
+
// Route-derived follow: any CHANGE of the key = the user navigated.
|
|
21
|
+
const navRef = useRef({ initial: true, key: navigationKey });
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (navRef.current.initial) {
|
|
24
|
+
navRef.current = { initial: false, key: navigationKey };
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (Object.is(navRef.current.key, navigationKey))
|
|
28
|
+
return;
|
|
29
|
+
navRef.current.key = navigationKey;
|
|
30
|
+
dispatch({ type: "menuInteraction" });
|
|
31
|
+
setDrawerOpen(false);
|
|
32
|
+
}, [navigationKey]);
|
|
33
|
+
const resolvedTones = useMemo(() => {
|
|
34
|
+
const pair = tones ?? DEFAULT_TONES[mode];
|
|
35
|
+
// Reject-under-floor at wiring time — an override that measures alike
|
|
36
|
+
// defeats the category (§2); the base defaults pass by construction.
|
|
37
|
+
if (tones !== undefined)
|
|
38
|
+
assertToneFloor(tones);
|
|
39
|
+
return pair;
|
|
40
|
+
}, [tones, mode]);
|
|
41
|
+
const value = useMemo(() => ({ state, dispatch, drawerOpen, setDrawerOpen, identity }), [state, drawerOpen, identity]);
|
|
42
|
+
// Token application (§2): tones + transition as inline custom properties
|
|
43
|
+
// on the shell scope; `pane-tone` is LIB-WRITTEN from the machine state.
|
|
44
|
+
const vars = {
|
|
45
|
+
[LAYOUT_TOKENS.toneUpper]: resolvedTones.upper,
|
|
46
|
+
[LAYOUT_TOKENS.toneUpperOn]: resolvedTones.upperOn,
|
|
47
|
+
[LAYOUT_TOKENS.toneLower]: resolvedTones.lower,
|
|
48
|
+
[LAYOUT_TOKENS.toneLowerOn]: resolvedTones.lowerOn,
|
|
49
|
+
[LAYOUT_TOKENS.paneTone]: state.activePanel === "agent" ? resolvedTones.lower : resolvedTones.upper,
|
|
50
|
+
[LAYOUT_TOKENS.toneTransition]: `${transitionMs}ms`,
|
|
51
|
+
};
|
|
52
|
+
return (_jsx(AgentModeContext.Provider, { value: value, children: _jsx("div", { className: "guuey-agent-layout", "data-mode": mode, "data-active-panel": state.activePanel, style: vars, children: children }) }));
|
|
53
|
+
}
|
|
54
|
+
export function useAgentMode() {
|
|
55
|
+
const ctx = useContext(AgentModeContext);
|
|
56
|
+
if (ctx === null) {
|
|
57
|
+
throw new Error("useAgentMode: no <AgentModeProvider> above this component.");
|
|
58
|
+
}
|
|
59
|
+
const { state, dispatch, drawerOpen, setDrawerOpen } = ctx;
|
|
60
|
+
const setActivePanel = useCallback((panel) => dispatch(panel === "app" ? { type: "menuInteraction" } : { type: "agentSubmit" }), [dispatch]);
|
|
61
|
+
return {
|
|
62
|
+
activePanel: state.activePanel,
|
|
63
|
+
streaming: state.streaming,
|
|
64
|
+
pending: state.pending,
|
|
65
|
+
dispatch,
|
|
66
|
+
setActivePanel,
|
|
67
|
+
drawerOpen,
|
|
68
|
+
setDrawerOpen,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The grid: sidebar column + pane. Below 1024px (the console family's own
|
|
73
|
+
* sidebar boundary — one muscle memory across surfaces) the sidebar leaves
|
|
74
|
+
* the grid and becomes an overlay drawer, and the follow is SUSPENDED —
|
|
75
|
+
* the pane holds the lower (agent) tone (stylesheet-enforced; §4's ruled
|
|
76
|
+
* degraded mode). The drawer toggle renders only at drawer widths.
|
|
77
|
+
*
|
|
78
|
+
* Children: an {@link AgentModeSidebar} (wrapping the two panels) and an
|
|
79
|
+
* {@link ActivePane}. The wrapper is structural — the drawer must slide as
|
|
80
|
+
* ONE element, so the two panels share a positioned parent (the §4 sketch
|
|
81
|
+
* elides it; the contract is unchanged).
|
|
82
|
+
*/
|
|
83
|
+
export function AgentModeShell({ children, className, ...rest }) {
|
|
84
|
+
const { drawerOpen, setDrawerOpen } = useAgentMode();
|
|
85
|
+
return (_jsxs("div", { ...rest, className: joinClass("guuey-layout-shell", className), "data-drawer-open": drawerOpen ? "true" : undefined, children: [_jsxs("button", { type: "button", className: "guuey-layout-drawer-toggle", "aria-expanded": drawerOpen, "aria-controls": "guuey-layout-sidebar", onClick: () => setDrawerOpen(!drawerOpen), children: [_jsx("span", { "aria-hidden": "true", children: "\u2630" }), _jsx("span", { className: "guuey-layout-sr-only", children: "Menu" })] }), children] }));
|
|
86
|
+
}
|
|
87
|
+
/** The sidebar column: the two panels' shared, drawer-slidable parent. */
|
|
88
|
+
export function AgentModeSidebar({ children, className, ...rest }) {
|
|
89
|
+
return (_jsx("aside", { ...rest, id: "guuey-layout-sidebar", className: joinClass("guuey-layout-sidebar", className), children: children }));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* One sidebar section. `section="app"` wires `menuInteraction` on
|
|
93
|
+
* pointer/focus interactions inside it (capture-phase — apps write ZERO
|
|
94
|
+
* per-link wiring; this covers same-page clicks the route signal cannot
|
|
95
|
+
* see). `section="agent"` hosts the agent surface and wires nothing — the
|
|
96
|
+
* agent bridge speaks through the machine.
|
|
97
|
+
*/
|
|
98
|
+
export function SidebarPanel({ section, children, className, ...rest }) {
|
|
99
|
+
const { dispatch } = useAgentMode();
|
|
100
|
+
const onMenuInteraction = section === "app" ? () => dispatch({ type: "menuInteraction" }) : undefined;
|
|
101
|
+
return (_jsx("div", { ...rest, className: joinClass(`guuey-layout-panel guuey-layout-panel-${section}`, className), onPointerDownCapture: onMenuInteraction, onFocusCapture: onMenuInteraction, children: children }));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The right pane: paints `--guuey-layout-pane-tone`, animates per the
|
|
105
|
+
* transition token, honors `prefers-reduced-motion` (stylesheet: instant
|
|
106
|
+
* snap). While the founder-(d) window is open the pane presents the
|
|
107
|
+
* working state INSTEAD of its children — prior page content never sits
|
|
108
|
+
* on the agent ground.
|
|
109
|
+
*/
|
|
110
|
+
export function ActivePane({ children, workingState, className, ...rest }) {
|
|
111
|
+
const ctx = useContext(AgentModeContext);
|
|
112
|
+
if (ctx === null)
|
|
113
|
+
throw new Error("ActivePane: no <AgentModeProvider> above this component.");
|
|
114
|
+
const { state, identity } = ctx;
|
|
115
|
+
const working = state.activePanel === "agent" && state.pending;
|
|
116
|
+
return (_jsx("main", { ...rest, className: joinClass("guuey-layout-pane", className), children: working ? ((workingState ?? (_jsxs("div", { className: "guuey-layout-working", role: "status", children: [identity !== null ? _jsx("div", { className: "guuey-layout-working-identity", children: identity }) : null, _jsxs("span", { className: "guuey-layout-working-pulse", "aria-hidden": "true", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), _jsx("span", { className: "guuey-layout-sr-only", children: "Working\u2026" })] })))) : (children) }));
|
|
117
|
+
}
|
|
118
|
+
function joinClass(base, extra) {
|
|
119
|
+
return extra === undefined || extra === "" ? base : `${base} ${extra}`;
|
|
120
|
+
}
|
|
121
|
+
export { bindGuueyChat } from "./bind.js";
|