@elizaos/ui 2.0.0-alpha.344 → 2.0.0-alpha.346

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.
Files changed (43) hide show
  1. package/package.json +1 -1
  2. package/packages/typescript/src/features/basic-capabilities/providers/actionState.d.ts.map +1 -1
  3. package/packages/typescript/src/features/basic-capabilities/providers/actionState.js +8 -51
  4. package/packages/typescript/src/features/basic-capabilities/providers/actions.d.ts.map +1 -1
  5. package/packages/typescript/src/features/basic-capabilities/providers/actions.js +2 -2
  6. package/packages/typescript/src/features/basic-capabilities/providers/non-actionable-chatter.d.ts.map +1 -1
  7. package/packages/typescript/src/features/basic-capabilities/providers/non-actionable-chatter.js +2 -4
  8. package/packages/typescript/src/features/basic-capabilities/providers/providers.d.ts.map +1 -1
  9. package/packages/typescript/src/features/basic-capabilities/providers/providers.js +2 -2
  10. package/packages/typescript/src/features/knowledge/utils.d.ts.map +1 -1
  11. package/packages/typescript/src/features/knowledge/utils.js +4 -3
  12. package/packages/typescript/src/runtime.d.ts +2 -0
  13. package/packages/typescript/src/runtime.d.ts.map +1 -1
  14. package/packages/typescript/src/runtime.js +80 -0
  15. package/packages/typescript/src/services/message.d.ts +3 -1
  16. package/packages/typescript/src/services/message.d.ts.map +1 -1
  17. package/packages/typescript/src/services/message.js +91 -135
  18. package/packages/typescript/src/utils/action-results.d.ts +33 -0
  19. package/packages/typescript/src/utils/action-results.d.ts.map +1 -0
  20. package/packages/typescript/src/utils/action-results.js +169 -0
  21. package/packages/typescript/src/utils/context-catalog.d.ts.map +1 -1
  22. package/packages/typescript/src/utils/context-catalog.js +11 -0
  23. package/packages/typescript/src/utils/context-routing.d.ts +3 -0
  24. package/packages/typescript/src/utils/context-routing.d.ts.map +1 -1
  25. package/packages/typescript/src/utils/context-routing.js +88 -0
  26. package/packages/typescript/src/utils/message-text.d.ts +5 -0
  27. package/packages/typescript/src/utils/message-text.d.ts.map +1 -0
  28. package/packages/typescript/src/utils/message-text.js +24 -0
  29. package/packages/typescript/src/utils.d.ts +2 -1
  30. package/packages/typescript/src/utils.d.ts.map +1 -1
  31. package/packages/typescript/src/utils.js +2 -1
  32. package/packages/ui/src/components/composites/chat/chat-composer.d.ts.map +1 -1
  33. package/packages/ui/src/components/composites/chat/chat-composer.js +101 -19
  34. package/packages/ui/src/layouts/page-layout/page-layout-mobile-drawer.d.ts.map +1 -1
  35. package/packages/ui/src/layouts/page-layout/page-layout-mobile-drawer.js +23 -4
  36. package/packages/ui/src/layouts/workspace-layout/index.d.ts +1 -0
  37. package/packages/ui/src/layouts/workspace-layout/index.d.ts.map +1 -1
  38. package/packages/ui/src/layouts/workspace-layout/index.js +1 -0
  39. package/packages/ui/src/layouts/workspace-layout/workspace-layout.d.ts.map +1 -1
  40. package/packages/ui/src/layouts/workspace-layout/workspace-layout.js +8 -2
  41. package/packages/ui/src/layouts/workspace-layout/workspace-mobile-sidebar-controls.d.ts +13 -0
  42. package/packages/ui/src/layouts/workspace-layout/workspace-mobile-sidebar-controls.d.ts.map +1 -0
  43. package/packages/ui/src/layouts/workspace-layout/workspace-mobile-sidebar-controls.js +5 -0
@@ -1,4 +1,5 @@
1
1
  import { resolveActionContexts, resolveProviderContexts, } from "./context-catalog";
2
+ import { normalizeUserMessageText } from "./message-text";
2
3
  export const AVAILABLE_CONTEXTS_STATE_KEY = "availableContexts";
3
4
  export const CONTEXT_ROUTING_METADATA_KEY = "__responseContext";
4
5
  export const CONTEXT_ROUTING_STATE_KEY = "__contextRouting";
@@ -107,6 +108,9 @@ export function getActiveRoutingContexts(routing) {
107
108
  contextSet.add("general");
108
109
  return Array.from(contextSet);
109
110
  }
111
+ export function getActiveRoutingContextsForTurn(state, message) {
112
+ return getActiveRoutingContexts(mergeContextRouting(state, message));
113
+ }
110
114
  export function shouldIncludeByContext(declaredContexts, activeContexts) {
111
115
  if (!declaredContexts || declaredContexts.length === 0) {
112
116
  return true;
@@ -152,6 +156,90 @@ export function deriveAvailableContexts(actions, providers) {
152
156
  }
153
157
  return Array.from(contextSet).sort((a, b) => `${a}`.localeCompare(`${b}`));
154
158
  }
159
+ const CONTEXT_SIGNALS = [
160
+ {
161
+ context: "code",
162
+ patterns: [
163
+ /\b(repo|repository|codebase|branch|commit|pull request|pr|diff|workspace|file|directory)\b/u,
164
+ /\b(code|coding|implement|debug|fix|refactor|patch|test|typecheck|lint|build|component|api|server|client)\b/u,
165
+ /\b(task agents?|sub-?agents?|coding agents?|codex|claude code|spawn an? agent|agent running|what are you working on)\b/u,
166
+ ],
167
+ },
168
+ {
169
+ context: "automation",
170
+ patterns: [
171
+ /\b(schedule|remind|reminder|cron|workflow|automate|automation|run this|execute|deploy|release|monitor)\b/u,
172
+ /\b(task agents?|sub-?agents?|agent running|pause that|resume that|stop that|continue that|what are you working on)\b/u,
173
+ ],
174
+ },
175
+ {
176
+ context: "knowledge",
177
+ patterns: [
178
+ /\b(uploaded|document|file|pdf|knowledge|remember|recall|search|lookup|find|summari[sz]e|analy[sz]e|research)\b/u,
179
+ /\b(what is|what was|where is|tell me about|explain)\b/u,
180
+ ],
181
+ },
182
+ {
183
+ context: "browser",
184
+ patterns: [
185
+ /\b(browser|browse|website|web page|url|click|type into|screenshot|navigate|extract page)\b/u,
186
+ ],
187
+ },
188
+ {
189
+ context: "media",
190
+ patterns: [
191
+ /\b(image|picture|photo|video|audio|voice|transcribe|screenshot|draw|generate an image)\b/u,
192
+ ],
193
+ },
194
+ {
195
+ context: "wallet",
196
+ patterns: [
197
+ /\b(wallet|token|swap|bridge|stake|unstake|balance|portfolio|transaction|sign message|contract)\b/u,
198
+ ],
199
+ },
200
+ {
201
+ context: "social",
202
+ patterns: [
203
+ /\b(message|dm|email|inbox|contact|relationship|follow up|calendar|meeting|call|send .* to)\b/u,
204
+ ],
205
+ },
206
+ {
207
+ context: "system",
208
+ patterns: [
209
+ /\b(settings?|configure|configuration|plugin|secret|api key|model provider|oauth|login|auth)\b/u,
210
+ ],
211
+ },
212
+ ];
213
+ export function inferContextRoutingFromText(text) {
214
+ const normalized = normalizeUserMessageText({
215
+ content: { text: text ?? "" },
216
+ });
217
+ if (!normalized) {
218
+ return { primaryContext: "general", secondaryContexts: [] };
219
+ }
220
+ const scored = CONTEXT_SIGNALS.map((signal) => ({
221
+ context: signal.context,
222
+ score: signal.patterns.reduce((score, pattern) => score + (pattern.test(normalized) ? 1 : 0), 0),
223
+ }))
224
+ .filter((entry) => entry.score > 0)
225
+ .sort((left, right) => right.score - left.score);
226
+ if (scored.length === 0) {
227
+ return { primaryContext: "general", secondaryContexts: [] };
228
+ }
229
+ const primaryContext = scored[0].context;
230
+ const secondaryContexts = scored
231
+ .slice(1)
232
+ .filter((entry) => entry.score >= Math.max(1, scored[0].score - 1))
233
+ .map((entry) => entry.context);
234
+ return { primaryContext, secondaryContexts };
235
+ }
236
+ export function inferContextRoutingFromMessage(message) {
237
+ return inferContextRoutingFromText(typeof message.content === "string"
238
+ ? message.content
239
+ : typeof message.content?.text === "string"
240
+ ? message.content.text
241
+ : "");
242
+ }
155
243
  export function attachAvailableContexts(state, runtime) {
156
244
  const availableContexts = deriveAvailableContexts(runtime.actions, runtime.providers);
157
245
  return {
@@ -0,0 +1,5 @@
1
+ import type { Memory } from "../types/memory";
2
+ export declare function extractUserText(raw: string): string;
3
+ export declare function getUserMessageText(message: Pick<Memory, "content"> | null | undefined): string;
4
+ export declare function normalizeUserMessageText(message: Pick<Memory, "content"> | null | undefined): string;
5
+ //# sourceMappingURL=message-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-text.d.ts","sourceRoot":"","sources":["../../../../../../typescript/src/utils/message-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAO9C,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GACjD,MAAM,CAQR;AAED,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GACjD,MAAM,CAER"}
@@ -0,0 +1,24 @@
1
+ const KNOWLEDGE_AUGMENTATION_PREFIX = "Answer the user request using the contextual knowledge";
2
+ const USER_REQUEST_WRAPPER = /<user_request>\s*([\s\S]*?)\s*<\/user_request>/i;
3
+ const LANGUAGE_INSTRUCTION_SUFFIX = /\n*\[language instruction:[^\]]*\]\s*$/i;
4
+ export function extractUserText(raw) {
5
+ let text = raw;
6
+ if (text.trimStart().startsWith(KNOWLEDGE_AUGMENTATION_PREFIX)) {
7
+ const match = text.match(USER_REQUEST_WRAPPER);
8
+ if (match?.[1]) {
9
+ text = match[1];
10
+ }
11
+ }
12
+ return text.replace(LANGUAGE_INSTRUCTION_SUFFIX, "").trim();
13
+ }
14
+ export function getUserMessageText(message) {
15
+ const raw = typeof message?.content === "string"
16
+ ? message.content
17
+ : typeof message?.content?.text === "string"
18
+ ? message.content.text
19
+ : "";
20
+ return extractUserText(raw);
21
+ }
22
+ export function normalizeUserMessageText(message) {
23
+ return getUserMessageText(message).toLowerCase().replace(/\s+/g, " ").trim();
24
+ }
@@ -185,8 +185,9 @@ export declare function stringToUuid(target: string | number): UUID;
185
185
  */
186
186
  export declare function prewarmUuidCache(values: string[]): Promise<void>;
187
187
  export declare const getContentTypeFromMimeType: (mimeType: string) => ContentType | undefined;
188
- export { AVAILABLE_CONTEXTS_STATE_KEY, attachAvailableContexts, CONTEXT_ROUTING_METADATA_KEY, CONTEXT_ROUTING_STATE_KEY, type ContextRoutingDecision, deriveAvailableContexts, getActiveRoutingContexts, getContextRoutingFromMessage, getContextRoutingFromState, mergeContextRouting, parseContextList, parseContextRoutingMetadata, setContextRoutingMetadata, shouldIncludeByContext, } from "./utils/context-routing";
188
+ export { AVAILABLE_CONTEXTS_STATE_KEY, attachAvailableContexts, CONTEXT_ROUTING_METADATA_KEY, CONTEXT_ROUTING_STATE_KEY, type ContextRoutingDecision, deriveAvailableContexts, getActiveRoutingContexts, getActiveRoutingContextsForTurn, getContextRoutingFromMessage, getContextRoutingFromState, inferContextRoutingFromMessage, inferContextRoutingFromText, mergeContextRouting, parseContextList, parseContextRoutingMetadata, setContextRoutingMetadata, shouldIncludeByContext, } from "./utils/context-routing";
189
189
  export { extractAndParseJSONObjectFromText } from "./utils/json-llm";
190
+ export { extractUserText, getUserMessageText, normalizeUserMessageText, } from "./utils/message-text";
190
191
  export { getLocalServerUrl } from "./utils/node";
191
192
  export { extractFirstSentence, hasFirstSentence } from "./utils/text-splitting";
192
193
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../typescript/src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../typescript/src/utils.ts"],"names":[],"mappings":"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"}
@@ -1111,8 +1111,9 @@ export const getContentTypeFromMimeType = (mimeType) => {
1111
1111
  }
1112
1112
  return undefined;
1113
1113
  };
1114
- export { AVAILABLE_CONTEXTS_STATE_KEY, attachAvailableContexts, CONTEXT_ROUTING_METADATA_KEY, CONTEXT_ROUTING_STATE_KEY, deriveAvailableContexts, getActiveRoutingContexts, getContextRoutingFromMessage, getContextRoutingFromState, mergeContextRouting, parseContextList, parseContextRoutingMetadata, setContextRoutingMetadata, shouldIncludeByContext, } from "./utils/context-routing";
1114
+ export { AVAILABLE_CONTEXTS_STATE_KEY, attachAvailableContexts, CONTEXT_ROUTING_METADATA_KEY, CONTEXT_ROUTING_STATE_KEY, deriveAvailableContexts, getActiveRoutingContexts, getActiveRoutingContextsForTurn, getContextRoutingFromMessage, getContextRoutingFromState, inferContextRoutingFromMessage, inferContextRoutingFromText, mergeContextRouting, parseContextList, parseContextRoutingMetadata, setContextRoutingMetadata, shouldIncludeByContext, } from "./utils/context-routing";
1115
1115
  export { extractAndParseJSONObjectFromText } from "./utils/json-llm";
1116
+ export { extractUserText, getUserMessageText, normalizeUserMessageText, } from "./utils/message-text";
1116
1117
  // `export * from "./utils"` (in index.node.ts etc.) resolves to this file, not
1117
1118
  // to a `./utils/index.ts`. Any helper in the `utils/` directory that needs to be
1118
1119
  // reachable from `@elizaos/core` must be re-exported here.
@@ -1 +1 @@
1
- {"version":3,"file":"chat-composer.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/composites/chat/chat-composer.tsx"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,SAAS,EAIf,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,sBAAsB;IACrC,mBAAmB,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9C,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAAC;IACjD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,aAAa,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC9B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC;IAC/D,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IACnD,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,sBAAsB,CAAC;IAC9B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAkB,EAClB,WAAW,EACX,SAAS,EACT,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,KAAK,EACL,iBAAiB,EACjB,oBAA2B,EAC3B,CAAC,EACD,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,MAAM,EACN,MAAM,EACN,cAAc,EACd,kBAAkB,EAClB,qBAA6B,EAC7B,YAAY,EACZ,gBAAwB,EACxB,WAAW,EACX,iBAAiB,GAClB,EAAE,iBAAiB,2CA4jBnB"}
1
+ {"version":3,"file":"chat-composer.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/composites/chat/chat-composer.tsx"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiEhD,MAAM,WAAW,sBAAsB;IACrC,mBAAmB,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9C,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAAC;IACjD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,aAAa,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC9B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC;IAC/D,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IACnD,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,sBAAsB,CAAC;IAC9B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAkB,EAClB,WAAW,EACX,SAAS,EACT,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,KAAK,EACL,iBAAiB,EACjB,oBAA2B,EAC3B,CAAC,EACD,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,MAAM,EACN,MAAM,EACN,cAAc,EACd,kBAAkB,EAClB,qBAA6B,EAC7B,YAAY,EACZ,gBAAwB,EACxB,WAAW,EACX,iBAAiB,GAClB,EAAE,iBAAiB,2CAooBnB"}
@@ -1,12 +1,51 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { ArrowUp, Mic, Paperclip, Plus, Send, Square, Volume2, VolumeX, } from "lucide-react";
3
- import { useEffect, useRef, useState, } from "react";
3
+ import { useEffect, useLayoutEffect, useRef, useState, } from "react";
4
4
  import { Button } from "../../ui/button";
5
5
  import { Textarea } from "../../ui/textarea";
6
6
  import { CreateTaskPopover } from "./create-task-popover";
7
+ const INLINE_TEXTAREA_MIN_HEIGHT_PX = 32;
8
+ const INLINE_TEXTAREA_MAX_HEIGHT_PX = 128;
9
+ const INLINE_STACKED_INLINE_PADDING_PX = 12;
10
+ const inlineTextareaClass = "block h-8 max-h-[128px] min-h-0 w-full min-w-0 resize-none overflow-y-hidden appearance-none rounded-none border-0 bg-transparent px-2 py-[6px] text-sm leading-5 text-txt shadow-none outline-none ring-0 placeholder:text-muted/60 focus:!border-0 focus:!outline-none focus:!ring-0 focus-visible:!border-0 focus-visible:!outline-none focus-visible:!ring-0 focus-visible:!ring-offset-0 focus-visible:!shadow-none";
11
+ const inlineMeasureTextareaClass = `${inlineTextareaClass} pointer-events-none fixed left-0 top-0 z-[-1] opacity-0`;
12
+ const chatComposerFocusResetClass = "[&_button:focus]:!outline-none [&_button:focus-visible]:!outline-none [&_button:focus-visible]:!ring-0 [&_button:focus-visible]:!ring-offset-0 [&_button:focus-visible]:!shadow-none [&_textarea:focus]:!outline-none [&_textarea:focus-visible]:!outline-none [&_textarea:focus-visible]:!ring-0 [&_textarea:focus-visible]:!ring-offset-0 [&_textarea:focus-visible]:!shadow-none";
13
+ function getTextareaVerticalPadding(textarea) {
14
+ const styles = window.getComputedStyle(textarea);
15
+ const paddingTop = Number.parseFloat(styles.paddingTop);
16
+ const paddingBottom = Number.parseFloat(styles.paddingBottom);
17
+ const verticalPadding = paddingTop + paddingBottom;
18
+ if (Number.isFinite(paddingTop) &&
19
+ Number.isFinite(paddingBottom) &&
20
+ verticalPadding > 0) {
21
+ return verticalPadding;
22
+ }
23
+ return 12;
24
+ }
25
+ function getTextareaLineHeight(textarea) {
26
+ const lineHeight = Number.parseFloat(window.getComputedStyle(textarea).lineHeight);
27
+ return Number.isFinite(lineHeight) && lineHeight > 0 ? lineHeight : 20;
28
+ }
29
+ function measureInlineTextarea(textarea, value, width) {
30
+ textarea.value = value.endsWith("\n") ? `${value} ` : value || " ";
31
+ textarea.style.width = `${Math.max(1, width)}px`;
32
+ textarea.style.height = "auto";
33
+ textarea.style.overflowY = "hidden";
34
+ const scrollHeight = textarea.scrollHeight;
35
+ const contentHeight = Math.max(0, scrollHeight - getTextareaVerticalPadding(textarea));
36
+ const lineHeight = getTextareaLineHeight(textarea);
37
+ return {
38
+ scrollHeight,
39
+ wraps: contentHeight > lineHeight * 1.25,
40
+ };
41
+ }
7
42
  export function ChatComposer({ variant, layout = "default", textareaRef, chatInput, chatPendingImagesCount, isComposerLocked, isAgentStarting, chatSending, voice, agentVoiceEnabled, showAgentVoiceToggle = true, t, onAttachImage, onChatInputChange, onKeyDown, onSend, onStop, onStopSpeaking, onToggleAgentVoice, codingAgentsAvailable = false, onCreateTask, hideAttachButton = false, placeholder, textareaAriaLabel, }) {
8
43
  const [isNarrow, setIsNarrow] = useState(() => typeof window !== "undefined" && window.innerWidth < 310);
9
44
  const [isInlineMultiline, setIsInlineMultiline] = useState(false);
45
+ const [inlineMeasureVersion, setInlineMeasureVersion] = useState(0);
46
+ const inlineRootRef = useRef(null);
47
+ const inlineMeasureRef = useRef(null);
48
+ const lastInlineSingleLineWidthRef = useRef(null);
10
49
  useEffect(() => {
11
50
  if (typeof window === "undefined" || !window.matchMedia)
12
51
  return;
@@ -53,9 +92,6 @@ export function ChatComposer({ variant, layout = "default", textareaRef, chatInp
53
92
  ? t("chat.listening")
54
93
  : inputPlaceholder
55
94
  : inputPlaceholder;
56
- const inlineTextareaClass = isInlineMultiline
57
- ? "block h-8 max-h-[128px] min-h-0 w-full min-w-0 resize-none overflow-y-hidden appearance-none rounded-none border-0 bg-transparent px-2 py-[6px] text-sm leading-5 text-txt shadow-none outline-none ring-0 placeholder:text-muted/60 focus:border-0 focus:outline-none focus:ring-0 focus-visible:border-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:shadow-none"
58
- : "block h-8 max-h-[128px] min-h-0 w-full min-w-0 resize-none overflow-y-hidden appearance-none rounded-none border-0 bg-transparent px-1 py-[5px] text-sm leading-5 text-txt shadow-none outline-none ring-0 placeholder:text-muted/60 focus:border-0 focus:outline-none focus:ring-0 focus-visible:border-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:shadow-none";
59
95
  useEffect(() => {
60
96
  return () => {
61
97
  if (holdTimerRef.current) {
@@ -64,24 +100,70 @@ export function ChatComposer({ variant, layout = "default", textareaRef, chatInp
64
100
  }
65
101
  };
66
102
  }, []);
67
- // biome-ignore lint/correctness/useExhaustiveDependencies: chatInput changes must rerun inline textarea autosizing.
68
103
  useEffect(() => {
104
+ if (!isInline)
105
+ return;
106
+ const root = inlineRootRef.current;
107
+ if (!root || typeof ResizeObserver === "undefined")
108
+ return;
109
+ let frame = 0;
110
+ const observer = new ResizeObserver(() => {
111
+ if (frame)
112
+ cancelAnimationFrame(frame);
113
+ frame = requestAnimationFrame(() => {
114
+ setInlineMeasureVersion((version) => version + 1);
115
+ });
116
+ });
117
+ observer.observe(root);
118
+ return () => {
119
+ if (frame)
120
+ cancelAnimationFrame(frame);
121
+ observer.disconnect();
122
+ };
123
+ }, [isInline]);
124
+ // biome-ignore lint/correctness/useExhaustiveDependencies: inlineMeasureVersion is a ResizeObserver tick that reruns measurement after width changes.
125
+ useLayoutEffect(() => {
69
126
  if (!isInline) {
70
127
  setIsInlineMultiline(false);
128
+ lastInlineSingleLineWidthRef.current = null;
71
129
  return;
72
130
  }
73
131
  const textarea = textareaRef.current;
74
- if (!textarea)
132
+ const measureTextarea = inlineMeasureRef.current;
133
+ const root = inlineRootRef.current;
134
+ if (!textarea || !measureTextarea || !root)
75
135
  return;
76
- const minHeight = 32;
77
- const maxHeight = 128;
78
- textarea.style.height = "auto";
79
- const nextHeight = Math.min(Math.max(textarea.scrollHeight, minHeight), maxHeight);
136
+ const measuredSingleLineWidth = textarea.clientWidth > 0 ? textarea.clientWidth : null;
137
+ const currentSingleLineWidth = isInlineMultiline
138
+ ? lastInlineSingleLineWidthRef.current
139
+ : measuredSingleLineWidth;
140
+ if (!isInlineMultiline && measuredSingleLineWidth) {
141
+ lastInlineSingleLineWidthRef.current = measuredSingleLineWidth;
142
+ }
143
+ const decisionWidth = currentSingleLineWidth ??
144
+ Math.max(1, root.clientWidth - INLINE_STACKED_INLINE_PADDING_PX);
145
+ const stackedWidth = Math.max(1, root.clientWidth - INLINE_STACKED_INLINE_PADDING_PX);
146
+ const decision = measureInlineTextarea(measureTextarea, chatInput, decisionWidth);
147
+ const nextIsInlineMultiline = chatInput.includes("\n") || decision.wraps;
148
+ const heightMeasurement = nextIsInlineMultiline
149
+ ? measureInlineTextarea(measureTextarea, chatInput, stackedWidth)
150
+ : decision;
151
+ const nextHeight = nextIsInlineMultiline
152
+ ? Math.min(Math.max(heightMeasurement.scrollHeight, INLINE_TEXTAREA_MIN_HEIGHT_PX), INLINE_TEXTAREA_MAX_HEIGHT_PX)
153
+ : INLINE_TEXTAREA_MIN_HEIGHT_PX;
80
154
  textarea.style.height = `${nextHeight}px`;
81
155
  textarea.style.overflowY =
82
- textarea.scrollHeight > maxHeight ? "auto" : "hidden";
83
- setIsInlineMultiline(nextHeight > minHeight);
84
- }, [chatInput, isInline, textareaRef]);
156
+ heightMeasurement.scrollHeight > INLINE_TEXTAREA_MAX_HEIGHT_PX
157
+ ? "auto"
158
+ : "hidden";
159
+ setIsInlineMultiline(nextIsInlineMultiline);
160
+ }, [
161
+ chatInput,
162
+ inlineMeasureVersion,
163
+ isInline,
164
+ isInlineMultiline,
165
+ textareaRef,
166
+ ]);
85
167
  const startPushToTalk = () => {
86
168
  if (isComposerLocked || voice.isListening)
87
169
  return;
@@ -161,13 +243,13 @@ export function ChatComposer({ variant, layout = "default", textareaRef, chatInp
161
243
  const inlineStopButton = (_jsx(Button, { variant: "surfaceDestructive", "data-testid": "chat-composer-action", className: "h-8 w-8 shrink-0 rounded-full bg-danger/15 p-0 text-danger shadow-none transition-colors hover:bg-danger/25 focus-visible:ring-0 focus-visible:ring-offset-0", onClick: onStop, size: "icon", title: actionButtonLabel, "aria-label": actionButtonLabel, children: _jsx(Square, { className: "h-3.5 w-3.5 fill-current" }) }));
162
244
  const inlineStopSpeakingButton = (_jsx(Button, { variant: "surfaceDestructive", "data-testid": "chat-composer-action", className: "h-8 w-8 shrink-0 rounded-full bg-danger/15 p-0 text-danger shadow-none transition-colors hover:bg-danger/25 focus-visible:ring-0 focus-visible:ring-offset-0", onClick: onStopSpeaking, size: "icon", title: actionButtonLabel, "aria-label": actionButtonLabel, children: _jsx(Square, { className: "h-3.5 w-3.5 fill-current" }) }));
163
245
  const inlineTrailingActions = shouldShowStopButton ? (inlineStopButton) : !isGameModal && voice.isSpeaking && !hasDraft ? (inlineStopSpeakingButton) : isInlineMultiline ? (_jsxs(_Fragment, { children: [inlineMicButton, inlineSendButton] })) : hasDraft ? (inlineSendButton) : (inlineMicButton);
164
- return (_jsx("div", { "data-inline-layout": isInlineMultiline ? "stacked" : "single-line", className: isInlineMultiline
165
- ? "flex min-h-[64px] flex-col gap-1 rounded-[22px] border border-border/35 bg-card/45 px-1.5 py-1.5"
166
- : "flex min-h-[40px] items-center gap-1 rounded-full border border-border/35 bg-card/45 px-1 py-1", children: isInlineMultiline ? (_jsxs(_Fragment, { children: [inlineTextarea, _jsxs("div", { className: "flex min-w-0 items-center gap-1", children: [inlineAttachButton, renderCreateTaskButton(), _jsx("div", { className: "min-w-0 flex-1" }), inlineTrailingActions] })] })) : (_jsxs(_Fragment, { children: [inlineAttachButton, renderCreateTaskButton(), inlineTextarea, inlineTrailingActions] })) }));
246
+ return (_jsxs("div", { ref: inlineRootRef, "data-chat-composer": "true", "data-inline-layout": isInlineMultiline ? "stacked" : "single-line", className: isInlineMultiline
247
+ ? `flex min-h-[64px] flex-col gap-1 rounded-[22px] border border-border/35 bg-card/45 px-1.5 py-1.5 ${chatComposerFocusResetClass}`
248
+ : `flex min-h-[40px] items-center gap-1 rounded-full border border-border/35 bg-card/45 px-1 py-1 ${chatComposerFocusResetClass}`, children: [_jsx("textarea", { ref: inlineMeasureRef, "aria-hidden": "true", className: inlineMeasureTextareaClass, "data-chat-composer-measure": "true", readOnly: true, rows: 1, tabIndex: -1, value: chatInput }), isInlineMultiline ? (_jsxs(_Fragment, { children: [inlineTextarea, _jsxs("div", { className: "flex min-w-0 items-center gap-1", children: [inlineAttachButton, renderCreateTaskButton(), _jsx("div", { className: "min-w-0 flex-1" }), inlineTrailingActions] })] })) : (_jsxs(_Fragment, { children: [inlineAttachButton, renderCreateTaskButton(), inlineTextarea, inlineTrailingActions] }))] }));
167
249
  }
168
- return (_jsxs("div", { className: isGameModal
169
- ? "relative flex w-full items-end gap-2 transition-all max-[380px]:gap-1.5"
170
- : "flex items-center gap-1.5 sm:gap-2", children: [!isGameModal && !hideAttachButton ? (_jsx(Button, { variant: "ghost", size: "icon", className: isInline
250
+ return (_jsxs("div", { "data-chat-composer": "true", className: isGameModal
251
+ ? `relative flex w-full items-end gap-2 transition-all max-[380px]:gap-1.5 ${chatComposerFocusResetClass}`
252
+ : `flex items-center gap-1.5 sm:gap-2 ${chatComposerFocusResetClass}`, children: [!isGameModal && !hideAttachButton ? (_jsx(Button, { variant: "ghost", size: "icon", className: isInline
171
253
  ? `h-8 w-8 shrink-0 rounded-full bg-bg/60 p-0 text-muted shadow-none transition-colors hover:bg-bg/60 hover:text-txt focus-visible:ring-0 focus-visible:ring-offset-0 ${chatPendingImagesCount > 0
172
254
  ? "text-accent hover:text-accent"
173
255
  : ""}`
@@ -1 +1 @@
1
- {"version":3,"file":"page-layout-mobile-drawer.d.ts","sourceRoot":"","sources":["../../../../../../src/layouts/page-layout/page-layout-mobile-drawer.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAEvE,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,yBAAyB,EACzB,OAAO,GACR,EAAE,2BAA2B,kDAsD7B"}
1
+ {"version":3,"file":"page-layout-mobile-drawer.d.ts","sourceRoot":"","sources":["../../../../../../src/layouts/page-layout/page-layout-mobile-drawer.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAEvE,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,yBAAyB,EACzB,OAAO,GACR,EAAE,2BAA2B,kDAsE7B"}
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { PanelLeftOpen } from "lucide-react";
3
3
  import * as React from "react";
4
4
  import { Button } from "../../components/ui/button";
5
- import { DrawerSheet, DrawerSheetContent, DrawerSheetHeader, DrawerSheetTitle, } from "../../components/ui/drawer-sheet";
6
5
  import { cn } from "../../lib/utils";
6
+ import { useWorkspaceMobileSidebarControls } from "../workspace-layout/workspace-mobile-sidebar-controls";
7
7
  export function PageLayoutMobileDrawer({ isDesktop, mobileSidebarLabel, mobileSidebarOpen, mobileSidebarTriggerClassName, onMobileSidebarOpenChange, sidebar, }) {
8
- if (isDesktop)
9
- return null;
8
+ const controls = useWorkspaceMobileSidebarControls();
9
+ const sidebarId = React.useId();
10
10
  const mobileSidebarElement = React.cloneElement(sidebar, {
11
11
  className: cn("!mt-0 !h-full !w-full !min-w-0", sidebar.props.className),
12
12
  collapsible: false,
@@ -14,5 +14,24 @@ export function PageLayoutMobileDrawer({ isDesktop, mobileSidebarLabel, mobileSi
14
14
  onMobileClose: () => onMobileSidebarOpenChange(false),
15
15
  });
16
16
  const drawerLabel = sidebar.props.mobileTitle ?? mobileSidebarLabel ?? "Browse";
17
- return (_jsxs(_Fragment, { children: [!mobileSidebarOpen ? (_jsx("div", { className: "pointer-events-none fixed left-2 z-40 md:hidden", style: { top: "var(--safe-area-top, 0px)" }, children: _jsx("div", { className: "pointer-events-auto", children: _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: cn("h-[2.375rem] max-w-[min(11rem,calc(100vw-5.5rem))] rounded-full border-border/40 bg-card/92 px-3 text-sm font-semibold text-txt shadow-sm backdrop-blur-md", mobileSidebarTriggerClassName), onClick: () => onMobileSidebarOpenChange(true), children: [_jsx(PanelLeftOpen, { className: "h-4 w-4 shrink-0" }), _jsx("span", { className: "truncate", children: drawerLabel })] }) }) })) : null, _jsx(DrawerSheet, { open: mobileSidebarOpen, onOpenChange: onMobileSidebarOpenChange, children: _jsxs(DrawerSheetContent, { "aria-describedby": undefined, className: "h-[min(calc(100dvh-1rem-var(--safe-area-top,0px)-var(--safe-area-bottom,0px)),46rem)] p-0", showCloseButton: false, children: [_jsx(DrawerSheetHeader, { className: "sr-only", children: _jsx(DrawerSheetTitle, { children: drawerLabel }) }), mobileSidebarElement] }) })] }));
17
+ React.useEffect(() => {
18
+ if (!controls || isDesktop)
19
+ return undefined;
20
+ return controls.register({
21
+ id: sidebarId,
22
+ label: drawerLabel,
23
+ open: mobileSidebarOpen,
24
+ setOpen: onMobileSidebarOpenChange,
25
+ });
26
+ }, [
27
+ controls,
28
+ drawerLabel,
29
+ isDesktop,
30
+ mobileSidebarOpen,
31
+ onMobileSidebarOpenChange,
32
+ sidebarId,
33
+ ]);
34
+ if (isDesktop)
35
+ return null;
36
+ return (_jsxs(_Fragment, { children: [!mobileSidebarOpen && !controls ? (_jsx("div", { className: "pointer-events-none fixed left-2 z-40 md:hidden", style: { top: "calc(var(--safe-area-top, 0px) + 2.75rem)" }, children: _jsx("div", { className: "pointer-events-auto", children: _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: cn("h-[2.375rem] max-w-[min(11rem,calc(100vw-5.5rem))] rounded-full border-border/40 bg-card/92 px-3 text-sm font-semibold text-txt shadow-sm backdrop-blur-md", mobileSidebarTriggerClassName), "data-testid": "page-layout-mobile-sidebar-trigger", onClick: () => onMobileSidebarOpenChange(true), children: [_jsx(PanelLeftOpen, { className: "h-4 w-4 shrink-0" }), _jsx("span", { className: "truncate", children: drawerLabel })] }) }) })) : null, mobileSidebarOpen ? (_jsx("section", { className: "flex min-h-0 w-full flex-1 overflow-hidden", "data-testid": "page-layout-mobile-sidebar-drawer", "aria-label": typeof drawerLabel === "string" ? drawerLabel : undefined, children: mobileSidebarElement })) : null] }));
18
37
  }
@@ -1,3 +1,4 @@
1
1
  export * from "./workspace-layout";
2
2
  export * from "./workspace-layout-types";
3
+ export * from "./workspace-mobile-sidebar-controls";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/layouts/workspace-layout/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/layouts/workspace-layout/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qCAAqC,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export * from "./workspace-layout";
2
2
  export * from "./workspace-layout-types";
3
+ export * from "./workspace-mobile-sidebar-controls";
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-layout.d.ts","sourceRoot":"","sources":["../../../../../../src/layouts/workspace-layout/workspace-layout.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAiDrE,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,sBAAsB,EACtB,qBAAqB,EACrB,cAAqB,EACrB,UAAU,EACV,MAAM,EACN,eAAe,EACf,eAA2B,EAC3B,kBAAkB,EAClB,6BAA6B,EAC7B,OAAO,EACP,kBAAyB,EACzB,GAAG,KAAK,EACT,EAAE,oBAAoB,2CA8FtB"}
1
+ {"version":3,"file":"workspace-layout.d.ts","sourceRoot":"","sources":["../../../../../../src/layouts/workspace-layout/workspace-layout.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAiDrE,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,sBAAsB,EACtB,qBAAqB,EACrB,cAAqB,EACrB,UAAU,EACV,MAAM,EACN,eAAe,EACf,eAA2B,EAC3B,kBAAkB,EAClB,6BAA6B,EAC7B,OAAO,EACP,kBAAyB,EACzB,GAAG,KAAK,EACT,EAAE,oBAAoB,2CAwGtB"}
@@ -41,6 +41,7 @@ function useWorkspaceLayoutDesktopMode() {
41
41
  export function WorkspaceLayout({ children, className, contentClassName, contentHeader, contentHeaderClassName, contentInnerClassName, contentPadding = true, contentRef, footer, footerClassName, headerPlacement = "outside", mobileSidebarLabel, mobileSidebarTriggerClassName, sidebar, sidebarCollapsible = true, ...props }) {
42
42
  const isDesktop = useWorkspaceLayoutDesktopMode();
43
43
  const [mobileSidebarOpen, setMobileSidebarOpen] = React.useState(false);
44
+ const showMobileSidebarPane = Boolean(sidebar && !isDesktop && mobileSidebarOpen);
44
45
  React.useEffect(() => {
45
46
  if (isDesktop) {
46
47
  setMobileSidebarOpen(false);
@@ -54,6 +55,11 @@ export function WorkspaceLayout({ children, className, contentClassName, content
54
55
  })
55
56
  : null;
56
57
  const headerElement = contentHeader ? (_jsx(PageLayoutHeader, { className: contentHeaderClassName, children: contentHeader })) : null;
57
- return (_jsxs("div", { className: cn("flex w-full min-h-0 min-w-0 flex-1 flex-col overflow-hidden", className), ...props, children: [contentHeader && headerPlacement === "outside" ? (_jsx("div", { className: cn("shrink-0", contentPadding && "px-4 pt-2 sm:px-6 sm:pt-3 lg:px-7 lg:pt-4"), children: headerElement })) : null, _jsxs("div", { className: cn("flex w-full min-h-0 min-w-0 flex-1 flex-col", sidebar && "md:flex-row"), children: [desktopSidebarElement ? (_jsx("div", { className: cn("hidden min-h-0 w-full shrink-0 items-stretch px-0 pb-0 md:flex md:w-auto", contentPadding && "pt-2 sm:pt-3 lg:pt-4"), children: desktopSidebarElement })) : null, _jsxs("main", { ref: (node) => assignRef(contentRef, node), className: cn("chat-native-scrollbar relative flex min-w-0 flex-1 flex-col overflow-y-auto bg-transparent", contentPadding &&
58
- "px-4 pb-4 pt-2 sm:px-6 sm:pb-6 sm:pt-3 lg:px-7 lg:pb-7 lg:pt-4", contentClassName), children: [sidebar ? (_jsx(PageLayoutMobileDrawer, { isDesktop: isDesktop, mobileSidebarLabel: mobileSidebarLabel, mobileSidebarOpen: mobileSidebarOpen, mobileSidebarTriggerClassName: mobileSidebarTriggerClassName, onMobileSidebarOpenChange: setMobileSidebarOpen, sidebar: sidebar })) : null, contentHeader && headerPlacement === "inside" ? headerElement : null, _jsx("div", { className: cn("flex w-full min-h-0 flex-1 flex-col", contentInnerClassName), children: children })] })] })] }));
58
+ return (_jsxs("div", { className: cn("flex w-full min-h-0 min-w-0 flex-1 flex-col overflow-hidden", className), ...props, children: [contentHeader && headerPlacement === "outside" ? (_jsx("div", { className: cn("shrink-0", contentPadding && "px-4 pt-2 sm:px-6 sm:pt-3 lg:px-7 lg:pt-4"), children: headerElement })) : null, _jsxs("div", { className: cn("flex w-full min-h-0 min-w-0 flex-1 flex-col", sidebar && "md:flex-row"), children: [desktopSidebarElement ? (_jsx("div", { className: cn("hidden min-h-0 w-full shrink-0 items-stretch px-0 pb-0 md:flex md:w-auto", contentPadding && "pt-2 sm:pt-3 lg:pt-4"), children: desktopSidebarElement })) : null, _jsxs("main", { ref: (node) => assignRef(contentRef, node), className: cn("chat-native-scrollbar relative flex min-w-0 flex-1 flex-col bg-transparent", showMobileSidebarPane ? "overflow-hidden" : "overflow-y-auto", contentPadding &&
59
+ !showMobileSidebarPane &&
60
+ "px-4 pb-4 pt-2 sm:px-6 sm:pb-6 sm:pt-3 lg:px-7 lg:pb-7 lg:pt-4", !showMobileSidebarPane && contentClassName), children: [sidebar ? (_jsx(PageLayoutMobileDrawer, { isDesktop: isDesktop, mobileSidebarLabel: mobileSidebarLabel, mobileSidebarOpen: mobileSidebarOpen, mobileSidebarTriggerClassName: mobileSidebarTriggerClassName, onMobileSidebarOpenChange: setMobileSidebarOpen, sidebar: sidebar })) : null, contentHeader &&
61
+ headerPlacement === "inside" &&
62
+ !showMobileSidebarPane
63
+ ? headerElement
64
+ : null, _jsx("div", { className: cn("flex w-full min-h-0 flex-1 flex-col", contentInnerClassName, showMobileSidebarPane && "hidden"), children: children })] })] })] }));
59
65
  }
@@ -0,0 +1,13 @@
1
+ import * as React from "react";
2
+ export interface WorkspaceMobileSidebarControl {
3
+ id: string;
4
+ label?: React.ReactNode;
5
+ open: boolean;
6
+ setOpen: (open: boolean) => void;
7
+ }
8
+ export interface WorkspaceMobileSidebarControls {
9
+ register: (control: WorkspaceMobileSidebarControl) => () => void;
10
+ }
11
+ export declare const WorkspaceMobileSidebarControlsContext: React.Context<WorkspaceMobileSidebarControls | null>;
12
+ export declare function useWorkspaceMobileSidebarControls(): WorkspaceMobileSidebarControls | null;
13
+ //# sourceMappingURL=workspace-mobile-sidebar-controls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-mobile-sidebar-controls.d.ts","sourceRoot":"","sources":["../../../../../../src/layouts/workspace-layout/workspace-mobile-sidebar-controls.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,WAAW,6BAA6B;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,MAAM,IAAI,CAAC;CAClE;AAED,eAAO,MAAM,qCAAqC,sDACgB,CAAC;AAEnE,wBAAgB,iCAAiC,IAAI,8BAA8B,GAAG,IAAI,CAEzF"}
@@ -0,0 +1,5 @@
1
+ import * as React from "react";
2
+ export const WorkspaceMobileSidebarControlsContext = React.createContext(null);
3
+ export function useWorkspaceMobileSidebarControls() {
4
+ return React.useContext(WorkspaceMobileSidebarControlsContext);
5
+ }