@djangocfg/ui-tools 2.1.377 → 2.1.379

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/index.cjs CHANGED
@@ -7,7 +7,7 @@ var chunkKNDLV4PI_cjs = require('./chunk-KNDLV4PI.cjs');
7
7
  var chunk5I5QNGUG_cjs = require('./chunk-5I5QNGUG.cjs');
8
8
  var chunkYW5IVWHQ_cjs = require('./chunk-YW5IVWHQ.cjs');
9
9
  var chunk76NNDZH6_cjs = require('./chunk-76NNDZH6.cjs');
10
- var chunkTUZZROQU_cjs = require('./chunk-TUZZROQU.cjs');
10
+ var chunkSI5RD2GD_cjs = require('./chunk-SI5RD2GD.cjs');
11
11
  var chunkYXZ6GU7H_cjs = require('./chunk-YXZ6GU7H.cjs');
12
12
  var chunkFVVF7VCD_cjs = require('./chunk-FVVF7VCD.cjs');
13
13
  var chunk7EYHNP3E_cjs = require('./chunk-7EYHNP3E.cjs');
@@ -374,7 +374,7 @@ var LazyTree = createLazyComponent(
374
374
  }
375
375
  );
376
376
  var LazyChat = createLazyComponent(
377
- () => import('./ChatRoot-AWNBBBH7.cjs').then((m) => ({ default: m.ChatRoot })),
377
+ () => import('./ChatRoot-EJC5Y2YM.cjs').then((m) => ({ default: m.ChatRoot })),
378
378
  {
379
379
  displayName: "LazyChat",
380
380
  fallback: /* @__PURE__ */ jsxRuntime.jsx(LoadingFallback, { minHeight: 320, text: "Loading chat\u2026" })
@@ -411,7 +411,7 @@ async function* parseSSE(response, options = {}) {
411
411
  throw new Error("SSE response has no body");
412
412
  }
413
413
  const map = options.map ?? DEFAULT_MAP;
414
- const idleMs = options.idleTimeoutMs ?? chunkTUZZROQU_cjs.LIMITS.sseIdleMs;
414
+ const idleMs = options.idleTimeoutMs ?? chunkSI5RD2GD_cjs.LIMITS.sseIdleMs;
415
415
  const reader = response.body.getReader();
416
416
  const decoder = new TextDecoder();
417
417
  let buffer = "";
@@ -614,7 +614,7 @@ function createMockTransport(opts = {}) {
614
614
  async createSession(_opts) {
615
615
  await sleep(latency);
616
616
  return {
617
- sessionId: chunkTUZZROQU_cjs.createId("s"),
617
+ sessionId: chunkSI5RD2GD_cjs.createId("s"),
618
618
  messages: history.length ? [...history] : void 0,
619
619
  hasMore: false,
620
620
  cursor: null,
@@ -631,12 +631,12 @@ function createMockTransport(opts = {}) {
631
631
  throw new Error("mock transport scripted failure");
632
632
  }
633
633
  history.push({
634
- id: chunkTUZZROQU_cjs.createId("u"),
634
+ id: chunkSI5RD2GD_cjs.createId("u"),
635
635
  role: "user",
636
636
  content,
637
637
  createdAt: Date.now()
638
638
  });
639
- const messageId = chunkTUZZROQU_cjs.createId("a");
639
+ const messageId = chunkSI5RD2GD_cjs.createId("a");
640
640
  yield { type: "message_start", messageId, sessionId: _sid };
641
641
  const reply = replies[turn % replies.length];
642
642
  turn += 1;
@@ -665,7 +665,7 @@ function createMockTransport(opts = {}) {
665
665
  turn += 1;
666
666
  const text = typeof reply === "string" ? reply : reply.filter((e) => e.type === "chunk").map((e) => e.delta).join("");
667
667
  return {
668
- id: chunkTUZZROQU_cjs.createId("a"),
668
+ id: chunkSI5RD2GD_cjs.createId("a"),
669
669
  role: "assistant",
670
670
  content: text || DEFAULT_REPLY,
671
671
  createdAt: Date.now()
@@ -821,7 +821,7 @@ function useChatLightbox() {
821
821
  chunkOLISEQHS_cjs.__name(useChatLightbox, "useChatLightbox");
822
822
  function useAutoFocusOnStreamEnd(options = {}) {
823
823
  const { isStreaming: isStreamingProp, targetRef, enabled = true, delayMs = 0 } = options;
824
- const ctx = chunkTUZZROQU_cjs.useChatContextOptional();
824
+ const ctx = chunkSI5RD2GD_cjs.useChatContextOptional();
825
825
  const isStreaming = isStreamingProp ?? ctx?.isStreaming ?? false;
826
826
  const composerHandleRef = React.useRef(null);
827
827
  composerHandleRef.current = ctx?.composer ?? null;
@@ -846,7 +846,7 @@ function useAutoFocusOnStreamEnd(options = {}) {
846
846
  }
847
847
  chunkOLISEQHS_cjs.__name(useAutoFocusOnStreamEnd, "useAutoFocusOnStreamEnd");
848
848
  function useRegisterComposer(focus) {
849
- const ctx = chunkTUZZROQU_cjs.useChatContextOptional();
849
+ const ctx = chunkSI5RD2GD_cjs.useChatContextOptional();
850
850
  const register = ctx?.registerComposer;
851
851
  React.useEffect(() => {
852
852
  if (!register) return;
@@ -901,9 +901,9 @@ function AudioToggle({
901
901
  alwaysShow = false,
902
902
  className
903
903
  }) {
904
- const muted = chunkTUZZROQU_cjs.useChatAudioPrefs((s) => s.muted);
905
- const setMuted = chunkTUZZROQU_cjs.useChatAudioPrefs((s) => s.setMuted);
906
- const ctx = chunkTUZZROQU_cjs.useChatContextOptional();
904
+ const muted = chunkSI5RD2GD_cjs.useChatAudioPrefs((s) => s.muted);
905
+ const setMuted = chunkSI5RD2GD_cjs.useChatAudioPrefs((s) => s.setMuted);
906
+ const ctx = chunkSI5RD2GD_cjs.useChatContextOptional();
907
907
  if (ctx && !ctx.hasAudio && !alwaysShow) return null;
908
908
  const Icon = muted ? lucideReact.VolumeX : lucideReact.Volume2;
909
909
  const label = muted ? "Unmute chat sounds" : "Mute chat sounds";
@@ -2259,159 +2259,159 @@ Object.defineProperty(exports, "useCronWeekDays", {
2259
2259
  });
2260
2260
  Object.defineProperty(exports, "Attachments", {
2261
2261
  enumerable: true,
2262
- get: function () { return chunkTUZZROQU_cjs.Attachments; }
2262
+ get: function () { return chunkSI5RD2GD_cjs.Attachments; }
2263
2263
  });
2264
2264
  Object.defineProperty(exports, "AttachmentsGrid", {
2265
2265
  enumerable: true,
2266
- get: function () { return chunkTUZZROQU_cjs.AttachmentsGrid; }
2266
+ get: function () { return chunkSI5RD2GD_cjs.AttachmentsGrid; }
2267
2267
  });
2268
2268
  Object.defineProperty(exports, "AttachmentsList", {
2269
2269
  enumerable: true,
2270
- get: function () { return chunkTUZZROQU_cjs.AttachmentsList; }
2270
+ get: function () { return chunkSI5RD2GD_cjs.AttachmentsList; }
2271
2271
  });
2272
2272
  Object.defineProperty(exports, "CHAT_EVENT_NAME", {
2273
2273
  enumerable: true,
2274
- get: function () { return chunkTUZZROQU_cjs.CHAT_EVENT_NAME; }
2274
+ get: function () { return chunkSI5RD2GD_cjs.CHAT_EVENT_NAME; }
2275
2275
  });
2276
2276
  Object.defineProperty(exports, "CSS_VARS", {
2277
2277
  enumerable: true,
2278
- get: function () { return chunkTUZZROQU_cjs.CSS_VARS; }
2278
+ get: function () { return chunkSI5RD2GD_cjs.CSS_VARS; }
2279
2279
  });
2280
2280
  Object.defineProperty(exports, "ChatProvider", {
2281
2281
  enumerable: true,
2282
- get: function () { return chunkTUZZROQU_cjs.ChatProvider; }
2282
+ get: function () { return chunkSI5RD2GD_cjs.ChatProvider; }
2283
2283
  });
2284
2284
  Object.defineProperty(exports, "ChatRoot", {
2285
2285
  enumerable: true,
2286
- get: function () { return chunkTUZZROQU_cjs.ChatRoot; }
2286
+ get: function () { return chunkSI5RD2GD_cjs.ChatRoot; }
2287
2287
  });
2288
2288
  Object.defineProperty(exports, "Composer", {
2289
2289
  enumerable: true,
2290
- get: function () { return chunkTUZZROQU_cjs.Composer; }
2290
+ get: function () { return chunkSI5RD2GD_cjs.Composer; }
2291
2291
  });
2292
2292
  Object.defineProperty(exports, "DEFAULT_LABELS", {
2293
2293
  enumerable: true,
2294
- get: function () { return chunkTUZZROQU_cjs.DEFAULT_LABELS; }
2294
+ get: function () { return chunkSI5RD2GD_cjs.DEFAULT_LABELS; }
2295
2295
  });
2296
2296
  Object.defineProperty(exports, "DEFAULT_SIDEBAR", {
2297
2297
  enumerable: true,
2298
- get: function () { return chunkTUZZROQU_cjs.DEFAULT_SIDEBAR; }
2298
+ get: function () { return chunkSI5RD2GD_cjs.DEFAULT_SIDEBAR; }
2299
2299
  });
2300
2300
  Object.defineProperty(exports, "DEFAULT_Z_INDEX", {
2301
2301
  enumerable: true,
2302
- get: function () { return chunkTUZZROQU_cjs.DEFAULT_Z_INDEX; }
2302
+ get: function () { return chunkSI5RD2GD_cjs.DEFAULT_Z_INDEX; }
2303
2303
  });
2304
2304
  Object.defineProperty(exports, "EmptyState", {
2305
2305
  enumerable: true,
2306
- get: function () { return chunkTUZZROQU_cjs.EmptyState; }
2306
+ get: function () { return chunkSI5RD2GD_cjs.EmptyState; }
2307
2307
  });
2308
2308
  Object.defineProperty(exports, "ErrorBanner", {
2309
2309
  enumerable: true,
2310
- get: function () { return chunkTUZZROQU_cjs.ErrorBanner; }
2310
+ get: function () { return chunkSI5RD2GD_cjs.ErrorBanner; }
2311
2311
  });
2312
2312
  Object.defineProperty(exports, "HOTKEYS", {
2313
2313
  enumerable: true,
2314
- get: function () { return chunkTUZZROQU_cjs.HOTKEYS; }
2314
+ get: function () { return chunkSI5RD2GD_cjs.HOTKEYS; }
2315
2315
  });
2316
2316
  Object.defineProperty(exports, "JumpToLatest", {
2317
2317
  enumerable: true,
2318
- get: function () { return chunkTUZZROQU_cjs.JumpToLatest; }
2318
+ get: function () { return chunkSI5RD2GD_cjs.JumpToLatest; }
2319
2319
  });
2320
2320
  Object.defineProperty(exports, "LIMITS", {
2321
2321
  enumerable: true,
2322
- get: function () { return chunkTUZZROQU_cjs.LIMITS; }
2322
+ get: function () { return chunkSI5RD2GD_cjs.LIMITS; }
2323
2323
  });
2324
2324
  Object.defineProperty(exports, "MessageActions", {
2325
2325
  enumerable: true,
2326
- get: function () { return chunkTUZZROQU_cjs.MessageActions; }
2326
+ get: function () { return chunkSI5RD2GD_cjs.MessageActions; }
2327
2327
  });
2328
2328
  Object.defineProperty(exports, "MessageBubble", {
2329
2329
  enumerable: true,
2330
- get: function () { return chunkTUZZROQU_cjs.MessageBubble; }
2330
+ get: function () { return chunkSI5RD2GD_cjs.MessageBubble; }
2331
2331
  });
2332
2332
  Object.defineProperty(exports, "MessageList", {
2333
2333
  enumerable: true,
2334
- get: function () { return chunkTUZZROQU_cjs.MessageList; }
2334
+ get: function () { return chunkSI5RD2GD_cjs.MessageList; }
2335
2335
  });
2336
2336
  Object.defineProperty(exports, "STORAGE_KEYS", {
2337
2337
  enumerable: true,
2338
- get: function () { return chunkTUZZROQU_cjs.STORAGE_KEYS; }
2338
+ get: function () { return chunkSI5RD2GD_cjs.STORAGE_KEYS; }
2339
2339
  });
2340
2340
  Object.defineProperty(exports, "Sources", {
2341
2341
  enumerable: true,
2342
- get: function () { return chunkTUZZROQU_cjs.Sources; }
2342
+ get: function () { return chunkSI5RD2GD_cjs.Sources; }
2343
2343
  });
2344
2344
  Object.defineProperty(exports, "StreamingIndicator", {
2345
2345
  enumerable: true,
2346
- get: function () { return chunkTUZZROQU_cjs.StreamingIndicator; }
2346
+ get: function () { return chunkSI5RD2GD_cjs.StreamingIndicator; }
2347
2347
  });
2348
2348
  Object.defineProperty(exports, "ToolCalls", {
2349
2349
  enumerable: true,
2350
- get: function () { return chunkTUZZROQU_cjs.ToolCalls; }
2350
+ get: function () { return chunkSI5RD2GD_cjs.ToolCalls; }
2351
2351
  });
2352
2352
  Object.defineProperty(exports, "createId", {
2353
2353
  enumerable: true,
2354
- get: function () { return chunkTUZZROQU_cjs.createId; }
2354
+ get: function () { return chunkSI5RD2GD_cjs.createId; }
2355
2355
  });
2356
2356
  Object.defineProperty(exports, "createTokenBuffer", {
2357
2357
  enumerable: true,
2358
- get: function () { return chunkTUZZROQU_cjs.createTokenBuffer; }
2358
+ get: function () { return chunkSI5RD2GD_cjs.createTokenBuffer; }
2359
2359
  });
2360
2360
  Object.defineProperty(exports, "deriveInitials", {
2361
2361
  enumerable: true,
2362
- get: function () { return chunkTUZZROQU_cjs.deriveInitials; }
2362
+ get: function () { return chunkSI5RD2GD_cjs.deriveInitials; }
2363
2363
  });
2364
2364
  Object.defineProperty(exports, "getChatLogger", {
2365
2365
  enumerable: true,
2366
- get: function () { return chunkTUZZROQU_cjs.getChatLogger; }
2366
+ get: function () { return chunkSI5RD2GD_cjs.getChatLogger; }
2367
2367
  });
2368
2368
  Object.defineProperty(exports, "initialState", {
2369
2369
  enumerable: true,
2370
- get: function () { return chunkTUZZROQU_cjs.initialState; }
2370
+ get: function () { return chunkSI5RD2GD_cjs.initialState; }
2371
2371
  });
2372
2372
  Object.defineProperty(exports, "isSubmittableDraft", {
2373
2373
  enumerable: true,
2374
- get: function () { return chunkTUZZROQU_cjs.isSubmittableDraft; }
2374
+ get: function () { return chunkSI5RD2GD_cjs.isSubmittableDraft; }
2375
2375
  });
2376
2376
  Object.defineProperty(exports, "reducer", {
2377
2377
  enumerable: true,
2378
- get: function () { return chunkTUZZROQU_cjs.reducer; }
2378
+ get: function () { return chunkSI5RD2GD_cjs.reducer; }
2379
2379
  });
2380
2380
  Object.defineProperty(exports, "resolvePersona", {
2381
2381
  enumerable: true,
2382
- get: function () { return chunkTUZZROQU_cjs.resolvePersona; }
2382
+ get: function () { return chunkSI5RD2GD_cjs.resolvePersona; }
2383
2383
  });
2384
2384
  Object.defineProperty(exports, "sanitizeDraft", {
2385
2385
  enumerable: true,
2386
- get: function () { return chunkTUZZROQU_cjs.sanitizeDraft; }
2386
+ get: function () { return chunkSI5RD2GD_cjs.sanitizeDraft; }
2387
2387
  });
2388
2388
  Object.defineProperty(exports, "useChat", {
2389
2389
  enumerable: true,
2390
- get: function () { return chunkTUZZROQU_cjs.useChat; }
2390
+ get: function () { return chunkSI5RD2GD_cjs.useChat; }
2391
2391
  });
2392
2392
  Object.defineProperty(exports, "useChatAudio", {
2393
2393
  enumerable: true,
2394
- get: function () { return chunkTUZZROQU_cjs.useChatAudio; }
2394
+ get: function () { return chunkSI5RD2GD_cjs.useChatAudio; }
2395
2395
  });
2396
2396
  Object.defineProperty(exports, "useChatAudioPrefs", {
2397
2397
  enumerable: true,
2398
- get: function () { return chunkTUZZROQU_cjs.useChatAudioPrefs; }
2398
+ get: function () { return chunkSI5RD2GD_cjs.useChatAudioPrefs; }
2399
2399
  });
2400
2400
  Object.defineProperty(exports, "useChatComposer", {
2401
2401
  enumerable: true,
2402
- get: function () { return chunkTUZZROQU_cjs.useChatComposer; }
2402
+ get: function () { return chunkSI5RD2GD_cjs.useChatComposer; }
2403
2403
  });
2404
2404
  Object.defineProperty(exports, "useChatContext", {
2405
2405
  enumerable: true,
2406
- get: function () { return chunkTUZZROQU_cjs.useChatContext; }
2406
+ get: function () { return chunkSI5RD2GD_cjs.useChatContext; }
2407
2407
  });
2408
2408
  Object.defineProperty(exports, "useChatContextOptional", {
2409
2409
  enumerable: true,
2410
- get: function () { return chunkTUZZROQU_cjs.useChatContextOptional; }
2410
+ get: function () { return chunkSI5RD2GD_cjs.useChatContextOptional; }
2411
2411
  });
2412
2412
  Object.defineProperty(exports, "useChatLayout", {
2413
2413
  enumerable: true,
2414
- get: function () { return chunkTUZZROQU_cjs.useChatLayout; }
2414
+ get: function () { return chunkSI5RD2GD_cjs.useChatLayout; }
2415
2415
  });
2416
2416
  Object.defineProperty(exports, "TreeError", {
2417
2417
  enumerable: true,
package/dist/index.d.cts CHANGED
@@ -2042,9 +2042,28 @@ interface ToolCallsProps {
2042
2042
  renderStreaming?: (text: string, call: ChatToolCall) => ReactNode;
2043
2043
  /** Single override for all three; specific renderers above take precedence. */
2044
2044
  renderPayload?: (value: unknown, kind: ToolPayloadKind, call: ChatToolCall) => ReactNode;
2045
+ /**
2046
+ * Rendered once **after** all tool-call panels — always visible, outside
2047
+ * the collapsible panels. Use for rich UI derived from tool outputs (e.g.
2048
+ * vehicle cards, map pins, tax breakdowns). Receives the full calls array
2049
+ * so the renderer can aggregate across multiple tool calls.
2050
+ */
2051
+ renderAfterCalls?: (calls: ChatToolCall[]) => ReactNode;
2052
+ /**
2053
+ * Custom renderer for each individual tool-call panel. When provided,
2054
+ * replaces the default collapsible `<ToolCallItem>`. Return `null` to
2055
+ * suppress a specific call while still letting others render.
2056
+ */
2057
+ renderToolCall?: (call: ChatToolCall) => ReactNode;
2058
+ /**
2059
+ * When `true`, the collapsible tool-call panels are not rendered at all.
2060
+ * `renderAfterCalls` still runs — use together to show only rich UI with
2061
+ * no raw accordion panels visible.
2062
+ */
2063
+ hideToolCalls?: boolean;
2045
2064
  className?: string;
2046
2065
  }
2047
- declare function ToolCalls({ calls, defaultExpanded, expandWhileStreaming, renderInput, renderOutput, renderStreaming, renderPayload, className, }: ToolCallsProps): react_jsx_runtime.JSX.Element;
2066
+ declare function ToolCalls({ calls, defaultExpanded, expandWhileStreaming, renderInput, renderOutput, renderStreaming, renderPayload, renderAfterCalls, renderToolCall, hideToolCalls, className, }: ToolCallsProps): react_jsx_runtime.JSX.Element;
2048
2067
 
2049
2068
  interface ChatRootProps {
2050
2069
  transport: ChatTransport;
package/dist/index.d.ts CHANGED
@@ -2042,9 +2042,28 @@ interface ToolCallsProps {
2042
2042
  renderStreaming?: (text: string, call: ChatToolCall) => ReactNode;
2043
2043
  /** Single override for all three; specific renderers above take precedence. */
2044
2044
  renderPayload?: (value: unknown, kind: ToolPayloadKind, call: ChatToolCall) => ReactNode;
2045
+ /**
2046
+ * Rendered once **after** all tool-call panels — always visible, outside
2047
+ * the collapsible panels. Use for rich UI derived from tool outputs (e.g.
2048
+ * vehicle cards, map pins, tax breakdowns). Receives the full calls array
2049
+ * so the renderer can aggregate across multiple tool calls.
2050
+ */
2051
+ renderAfterCalls?: (calls: ChatToolCall[]) => ReactNode;
2052
+ /**
2053
+ * Custom renderer for each individual tool-call panel. When provided,
2054
+ * replaces the default collapsible `<ToolCallItem>`. Return `null` to
2055
+ * suppress a specific call while still letting others render.
2056
+ */
2057
+ renderToolCall?: (call: ChatToolCall) => ReactNode;
2058
+ /**
2059
+ * When `true`, the collapsible tool-call panels are not rendered at all.
2060
+ * `renderAfterCalls` still runs — use together to show only rich UI with
2061
+ * no raw accordion panels visible.
2062
+ */
2063
+ hideToolCalls?: boolean;
2045
2064
  className?: string;
2046
2065
  }
2047
- declare function ToolCalls({ calls, defaultExpanded, expandWhileStreaming, renderInput, renderOutput, renderStreaming, renderPayload, className, }: ToolCallsProps): react_jsx_runtime.JSX.Element;
2066
+ declare function ToolCalls({ calls, defaultExpanded, expandWhileStreaming, renderInput, renderOutput, renderStreaming, renderPayload, renderAfterCalls, renderToolCall, hideToolCalls, className, }: ToolCallsProps): react_jsx_runtime.JSX.Element;
2048
2067
 
2049
2068
  interface ChatRootProps {
2050
2069
  transport: ChatTransport;
package/dist/index.mjs CHANGED
@@ -5,8 +5,8 @@ export { NativeProvider, StreamProvider, VideoControls, VideoErrorFallback, Vide
5
5
  export { ImageViewer } from './chunk-OBRSGM64.mjs';
6
6
  export { generateContentKey, useAudioCache, useBlobUrlCleanup, useImageCache, useMediaCacheStore, useVideoCache, useVideoPlayerSettings } from './chunk-C6GXVH5J.mjs';
7
7
  export { CronSchedulerProvider, CustomInput, DayChips, MonthDayGrid, SchedulePreview, ScheduleTypeSelector, TimeSelector, buildCron, humanizeCron, isValidCron, parseCron, useCronCustom, useCronMonthDays, useCronPreview, useCronScheduler, useCronSchedulerContext, useCronTime, useCronType, useCronWeekDays } from './chunk-PVAX67JG.mjs';
8
- import { LIMITS, createId, useChatContextOptional, useChatAudioPrefs } from './chunk-BDWVCSM5.mjs';
9
- export { Attachments, AttachmentsGrid, AttachmentsList, CHAT_EVENT_NAME, CSS_VARS, ChatProvider, ChatRoot, Composer, DEFAULT_LABELS, DEFAULT_SIDEBAR, DEFAULT_Z_INDEX, EmptyState, ErrorBanner, HOTKEYS, JumpToLatest, LIMITS, MessageActions, MessageBubble, MessageList, STORAGE_KEYS, Sources, StreamingIndicator, ToolCalls, createId, createTokenBuffer, deriveInitials, getChatLogger, initialState, isSubmittableDraft, reducer, resolvePersona, sanitizeDraft, useChat, useChatAudio, useChatAudioPrefs, useChatComposer, useChatContext, useChatContextOptional, useChatLayout } from './chunk-BDWVCSM5.mjs';
8
+ import { LIMITS, createId, useChatContextOptional, useChatAudioPrefs } from './chunk-QLMKCSR6.mjs';
9
+ export { Attachments, AttachmentsGrid, AttachmentsList, CHAT_EVENT_NAME, CSS_VARS, ChatProvider, ChatRoot, Composer, DEFAULT_LABELS, DEFAULT_SIDEBAR, DEFAULT_Z_INDEX, EmptyState, ErrorBanner, HOTKEYS, JumpToLatest, LIMITS, MessageActions, MessageBubble, MessageList, STORAGE_KEYS, Sources, StreamingIndicator, ToolCalls, createId, createTokenBuffer, deriveInitials, getChatLogger, initialState, isSubmittableDraft, reducer, resolvePersona, sanitizeDraft, useChat, useChatAudio, useChatAudioPrefs, useChatComposer, useChatContext, useChatContextOptional, useChatLayout } from './chunk-QLMKCSR6.mjs';
10
10
  export { TreeError, TreeSkeleton, createDemoTree } from './chunk-B6IR5KSC.mjs';
11
11
  export { DEFAULT_TREE_APPEARANCE, DEFAULT_TREE_LABELS, TreeRoot as Tree, TreeChevron, TreeContent, TreeEmpty, TreeIcon, TreeIndentGuides, TreeLabel, TreeProvider, TreeRoot, TreeRow, TreeSearchInput, appearanceToStyle, clearTreeState, createChildCache, flattenTree, loadTreeState, resolveAppearance, resolveChildren, saveTreeState, useTreeActions, useTreeContext, useTreeExpansion, useTreeFocus, useTreeKeyboard, useTreeLabels, useTreeRows, useTreeSearch, useTreeSelection, useTreeTypeAhead } from './chunk-ZL7FH4NW.mjs';
12
12
  import { PlaygroundProvider } from './chunk-Y6UTOBF6.mjs';
@@ -349,7 +349,7 @@ var LazyTree = createLazyComponent(
349
349
  }
350
350
  );
351
351
  var LazyChat = createLazyComponent(
352
- () => import('./ChatRoot-VJKOAVPQ.mjs').then((m) => ({ default: m.ChatRoot })),
352
+ () => import('./ChatRoot-QOSKJPM6.mjs').then((m) => ({ default: m.ChatRoot })),
353
353
  {
354
354
  displayName: "LazyChat",
355
355
  fallback: /* @__PURE__ */ jsx(LoadingFallback, { minHeight: 320, text: "Loading chat\u2026" })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ui-tools",
3
- "version": "2.1.377",
3
+ "version": "2.1.379",
4
4
  "description": "Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps",
5
5
  "keywords": [
6
6
  "ui-tools",
@@ -156,8 +156,8 @@
156
156
  "check": "tsc --noEmit"
157
157
  },
158
158
  "peerDependencies": {
159
- "@djangocfg/i18n": "^2.1.377",
160
- "@djangocfg/ui-core": "^2.1.377",
159
+ "@djangocfg/i18n": "^2.1.379",
160
+ "@djangocfg/ui-core": "^2.1.379",
161
161
  "consola": "^3.4.2",
162
162
  "lodash-es": "^4.18.1",
163
163
  "lucide-react": "^0.545.0",
@@ -211,10 +211,10 @@
211
211
  "material-file-icons": "^2.4.0"
212
212
  },
213
213
  "devDependencies": {
214
- "@djangocfg/i18n": "^2.1.377",
214
+ "@djangocfg/i18n": "^2.1.379",
215
215
  "@djangocfg/playground": "workspace:*",
216
- "@djangocfg/typescript-config": "^2.1.377",
217
- "@djangocfg/ui-core": "^2.1.377",
216
+ "@djangocfg/typescript-config": "^2.1.379",
217
+ "@djangocfg/ui-core": "^2.1.379",
218
218
  "@types/lodash-es": "^4.17.12",
219
219
  "@types/mapbox__mapbox-gl-draw": "^1.4.8",
220
220
  "@types/node": "^24.7.2",
@@ -1283,6 +1283,107 @@ export const WailsLikeVirtualization = () => {
1283
1283
  );
1284
1284
  };
1285
1285
 
1286
+ // ---------------------------------------------------------------------------
1287
+ // 16) WithRenderAfterCalls — rich UI outside tool panels
1288
+ // Demonstrates: renderAfterCalls, hideToolCalls, renderToolCall
1289
+ // ---------------------------------------------------------------------------
1290
+
1291
+ const SEARCH_SEQUENCE: ChatStreamEvent[] = [
1292
+ { type: 'chunk', delta: 'Searching the catalog for you.\n\n' },
1293
+ {
1294
+ type: 'tool_call_start',
1295
+ toolId: 'v1',
1296
+ name: 'search_vehicles',
1297
+ input: { make: 'BMW', year_min: 2022 },
1298
+ },
1299
+ { type: 'tool_call_delta', toolId: 'v1', delta: 'querying…\n' },
1300
+ {
1301
+ type: 'tool_call_end',
1302
+ toolId: 'v1',
1303
+ output: {
1304
+ items: [
1305
+ { id: 'car-001', make: 'BMW', model: '5 Series', year: 2023, price: 45000 },
1306
+ { id: 'car-002', make: 'BMW', model: 'X5', year: 2022, price: 72000 },
1307
+ ],
1308
+ total: 2,
1309
+ },
1310
+ status: 'success',
1311
+ },
1312
+ { type: 'chunk', delta: 'Found 2 vehicles — see the cards below.' },
1313
+ { type: 'message_end' },
1314
+ ];
1315
+
1316
+ function MockVehicleCards({ calls }: { calls: import('./types').ChatToolCall[] }) {
1317
+ const items: Array<{ id: string; make: string; model: string; year: number; price: number }> = [];
1318
+ for (const call of calls) {
1319
+ if (call.status !== 'success' || call.name !== 'search_vehicles') continue;
1320
+ const out = call.output as { items?: typeof items } | null;
1321
+ for (const item of out?.items ?? []) items.push(item);
1322
+ }
1323
+ if (items.length === 0) return null;
1324
+ return (
1325
+ <div className="mt-2 space-y-1.5">
1326
+ {items.map((v) => (
1327
+ <div
1328
+ key={v.id}
1329
+ className="flex items-center gap-3 rounded-md border border-border bg-card px-3 py-2 text-xs"
1330
+ >
1331
+ <div className="size-10 shrink-0 rounded bg-muted" />
1332
+ <div className="min-w-0 flex-1">
1333
+ <p className="font-semibold">{v.make} {v.model}</p>
1334
+ <p className="text-muted-foreground">{v.year}</p>
1335
+ </div>
1336
+ <span className="font-mono text-sm font-semibold">${v.price.toLocaleString()}</span>
1337
+ </div>
1338
+ ))}
1339
+ </div>
1340
+ );
1341
+ }
1342
+
1343
+ export const WithRenderAfterCalls = () => {
1344
+ const [hide] = useBoolean('hide-panels', { defaultValue: false, label: 'hideToolCalls (hide accordion panels)' });
1345
+ const [useCustom] = useBoolean('custom-call', { defaultValue: false, label: 'renderToolCall (custom per-call renderer)' });
1346
+
1347
+ const transport = useMemo(
1348
+ () => createMockTransport({ replies: [SEARCH_SEQUENCE, SEARCH_SEQUENCE], latencyMs: 40 }),
1349
+ [],
1350
+ );
1351
+
1352
+ const toolCallsProps = useMemo(
1353
+ () => ({
1354
+ hideToolCalls: hide,
1355
+ renderAfterCalls: (calls: import('./types').ChatToolCall[]) => <MockVehicleCards calls={calls} />,
1356
+ ...(useCustom
1357
+ ? {
1358
+ renderToolCall: (call: import('./types').ChatToolCall) => (
1359
+ <div className="flex items-center gap-2 rounded border border-border bg-muted/40 px-2 py-1 text-xs">
1360
+ <span className="font-mono text-muted-foreground">{call.name}</span>
1361
+ <span className={`ml-auto rounded px-1 py-0.5 text-[10px] font-medium ${
1362
+ call.status === 'success' ? 'bg-emerald-500/10 text-emerald-600' : 'bg-amber-500/10 text-amber-600'
1363
+ }`}>{call.status}</span>
1364
+ </div>
1365
+ ),
1366
+ }
1367
+ : {}),
1368
+ }),
1369
+ [hide, useCustom],
1370
+ );
1371
+
1372
+ return (
1373
+ <Frame h={560}>
1374
+ <ChatRoot
1375
+ transport={transport}
1376
+ config={{
1377
+ greeting: 'Vehicle search demo',
1378
+ placeholder: 'Ask "find BMW vehicles"…',
1379
+ suggestions: [{ label: 'Find BMW vehicles', prompt: 'Find BMW vehicles from 2022' }],
1380
+ }}
1381
+ toolCallsProps={toolCallsProps}
1382
+ />
1383
+ </Frame>
1384
+ );
1385
+ };
1386
+
1286
1387
  // ---------------------------------------------------------------------------
1287
1388
  // AutoFocusOnStreamEnd — refocus composer the moment a reply lands
1288
1389
  // ---------------------------------------------------------------------------
@@ -168,6 +168,68 @@ import { LazyJsonTree } from '@djangocfg/ui-tools/json-tree';
168
168
 
169
169
  We don't import `LazyJsonTree` automatically — keeping the chat dep-light. The host opts in.
170
170
 
171
+ ### ToolCalls — rich UI after panels (`renderAfterCalls`)
172
+
173
+ `renderAfterCalls` renders **outside and below** all collapsible panels — always visible, regardless of whether panels are expanded or hidden. It receives the full `calls` array so you can aggregate across multiple tool calls (e.g. collect all vehicle IDs from `search_vehicles` + `get_vehicle` and render cards).
174
+
175
+ ```tsx
176
+ <ChatRoot
177
+ toolCallsProps={{
178
+ // Rich UI below all panels — always visible, never inside collapsed accordions
179
+ renderAfterCalls: (calls) => <VehicleCardList calls={calls} />,
180
+ }}
181
+ />
182
+ ```
183
+
184
+ #### hideToolCalls — show only rich UI, no raw panels
185
+
186
+ Set `hideToolCalls={true}` to suppress accordion panels entirely while `renderAfterCalls` still renders. Use when you want clean product UI without raw tool payloads visible.
187
+
188
+ ```tsx
189
+ <ChatRoot
190
+ toolCallsProps={{
191
+ hideToolCalls: true, // hides accordion panels
192
+ renderAfterCalls: (calls) => <VehicleCards calls={calls} />, // still runs
193
+ }}
194
+ />
195
+ ```
196
+
197
+ `hideToolCalls` only affects the accordion panels — `renderAfterCalls` is always independent.
198
+
199
+ #### renderToolCall — custom per-call panel renderer
200
+
201
+ Replace the default `<ToolCallItem>` accordion with your own UI. Return `null` to suppress a specific call.
202
+
203
+ ```tsx
204
+ <ChatRoot
205
+ toolCallsProps={{
206
+ renderToolCall: (call) => (
207
+ <div className="flex items-center gap-2 rounded border px-2 py-1 text-xs">
208
+ <span className="font-mono">{call.name}</span>
209
+ <span className="ml-auto">{call.status}</span>
210
+ </div>
211
+ ),
212
+ }}
213
+ />
214
+ ```
215
+
216
+ #### Full example — vehicle cards from tool output
217
+
218
+ ```tsx
219
+ import { buildVamcarToolCallsProps } from './chat/toolPayloads';
220
+
221
+ // toolPayloads.tsx:
222
+ export function buildVamcarToolCallsProps(): Omit<ToolCallsProps, 'calls'> {
223
+ return {
224
+ renderAfterCalls: (calls) => <VehicleCardsFromCalls calls={calls} />,
225
+ };
226
+ }
227
+
228
+ // In your chat component:
229
+ const toolCallsProps = useMemo(() => buildVamcarToolCallsProps(), []);
230
+ <ChatRoot transport={transport} toolCallsProps={toolCallsProps} />
231
+ ```
232
+
171
233
  ## Personas (user & assistant identity)
172
234
 
173
235
  Pass identities once on `<ChatRoot config>` — every bubble gets the right name, avatar and `aria-label`. Outgoing user messages get the `sender` field auto-stamped from `config.user`.
@@ -569,7 +631,8 @@ useChatAudioPrefs
569
631
  // Tool-payload dispatch
570
632
  dispatchToolPayload, isPlainObject, isLatLng,
571
633
  isGeoJSONFeatureCollection, isStringValue,
572
- type ToolPayloadMatcher, type ToolPayloadFallback
634
+ type ToolPayloadMatcher, type ToolPayloadFallback,
635
+ type ToolPayloadKind, type ToolCallsProps
573
636
 
574
637
  // Lightbox helpers
575
638
  collectImageAttachments
@@ -674,4 +737,5 @@ Full implementation plan and rationale lives at [`@dev/@refactoring7-chat/`](../
674
737
  - `WithPersonas` — config-level `user` + `assistant` identity (avatar, name)
675
738
  - `MultiUser` — per-message `sender` overrides (multi-user / multi-bot)
676
739
  - `WithHideComposer` — `hideComposer` + `footer` approval gate (HITL / agent-pause pattern)
740
+ - `WithRenderAfterCalls` — `renderAfterCalls` (vehicle cards outside panels), `hideToolCalls`, `renderToolCall` (custom per-call renderer) — knob-controlled
677
741
  - `Playground` — knobs (latency, streaming, suggestions)