@helpai/elements 0.6.0 → 0.7.1

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, L as Link, S as ServerConfig, b as SiteConfig, c as StartSessionResponse, W as WidgetConfig, d as WidgetConfigPartial, e as WidgetSettings, f as WidgetSettingsPartial } from './deployment-DKyrRSGL.js';
1
+ export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, L as Link, S as ServerConfig, b as SiteConfig, c as StartSessionResponse, W as WidgetConfig, d as WidgetConfigPartial, e as WidgetSettings, f as WidgetSettingsPartial } from './deployment-DhWwzofY.js';
2
2
  import 'zod';
3
3
 
4
4
  /**
package/index.mjs CHANGED
@@ -884,10 +884,11 @@ function pickInitialPanelSize(mode, size, viewportWidth) {
884
884
  }
885
885
  return "normal";
886
886
  }
887
- function resolveInitialPanelState(options, viewportWidth, persistedPanelOpen) {
887
+ function resolveInitialPanelState(options, viewportWidth, persistedPanelOpen, persistedPanelSize = null) {
888
888
  const isInlineLike = options.mode === "inline" || options.mode === "standalone" || options.mode === "page";
889
889
  const panelOpen = isInlineLike || (persistedPanelOpen ?? !options.startMinimized);
890
- const panelSize = pickInitialPanelSize(options.mode, options.size, viewportWidth);
890
+ const honorsPersisted = options.mode !== "standalone" && options.mode !== "page" && options.mode !== "inline";
891
+ const panelSize = honorsPersisted && persistedPanelSize ? persistedPanelSize : pickInitialPanelSize(options.mode, options.size, viewportWidth);
891
892
  return { panelOpen, panelSize };
892
893
  }
893
894
  function currentViewportWidth() {
@@ -1810,6 +1811,7 @@ function createPersistence(widgetId, storage = defaultStorage) {
1810
1811
  const KEY_CHAT = `${prefix}.sessionId`;
1811
1812
  const KEY_USER_PREFS = `${prefix}.userPrefs`;
1812
1813
  const KEY_PANEL_OPEN = `${prefix}.panelOpen`;
1814
+ const KEY_PANEL_SIZE = `${prefix}.panelSize`;
1813
1815
  const KEY_CALLOUT_DISMISSED = `${prefix}.calloutDismissed`;
1814
1816
  const KEY_SIDEBAR_COLLAPSED = `${prefix}.sidebarCollapsed`;
1815
1817
  const KEY_ACTIVE_MODULE = `${prefix}.activeModule`;
@@ -1864,6 +1866,13 @@ function createPersistence(widgetId, storage = defaultStorage) {
1864
1866
  savePanelOpen(open) {
1865
1867
  storage.set(KEY_PANEL_OPEN, open ? "1" : "0");
1866
1868
  },
1869
+ loadPanelSize() {
1870
+ const raw = storage.get(KEY_PANEL_SIZE);
1871
+ return raw === "normal" || raw === "expanded" || raw === "fullscreen" ? raw : null;
1872
+ },
1873
+ savePanelSize(size) {
1874
+ storage.set(KEY_PANEL_SIZE, size);
1875
+ },
1867
1876
  loadCalloutDismissed(currentText) {
1868
1877
  if (!currentText) return false;
1869
1878
  const dismissedText = storage.get(KEY_CALLOUT_DISMISSED);
@@ -2169,6 +2178,12 @@ var FeedbackBus = class {
2169
2178
  }
2170
2179
  };
2171
2180
 
2181
+ // src/ui/error-message.ts
2182
+ function errorMessageFor(error, strings) {
2183
+ if (error instanceof StreamError && error.status === 429) return strings.errorRateLimited;
2184
+ return strings.errorGeneric;
2185
+ }
2186
+
2172
2187
  // src/ui/launcher.tsx
2173
2188
  import { useEffect, useState } from "preact/hooks";
2174
2189
 
@@ -4585,6 +4600,7 @@ function ArticleRow({ article, nav }) {
4585
4600
  function HelpRoot({ transport, strings, config, nav, panelProps }) {
4586
4601
  const tags = config.contentTags;
4587
4602
  const [state, setState] = useState6("loading");
4603
+ const [errorMsg, setErrorMsg] = useState6(strings.errorGeneric);
4588
4604
  const [items, setItems] = useState6([]);
4589
4605
  const [query, setQuery] = useState6("");
4590
4606
  const [reloadKey, setReloadKey] = useState6(0);
@@ -4598,6 +4614,7 @@ function HelpRoot({ transport, strings, config, nav, panelProps }) {
4598
4614
  }).catch((err) => {
4599
4615
  if (cancelled) return;
4600
4616
  log12.warn("listContent (help) failed", { err });
4617
+ setErrorMsg(errorMessageFor(err, strings));
4601
4618
  setState("error");
4602
4619
  });
4603
4620
  return () => {
@@ -4612,15 +4629,7 @@ function HelpRoot({ transport, strings, config, nav, panelProps }) {
4612
4629
  }
4613
4630
  if (state === "loading") return /* @__PURE__ */ jsx25(ModuleState, { message: strings.helpLoading, strings });
4614
4631
  if (state === "error") {
4615
- return /* @__PURE__ */ jsx25(
4616
- ModuleState,
4617
- {
4618
- tone: "error",
4619
- message: strings.errorGeneric,
4620
- onRetry: () => setReloadKey((k) => k + 1),
4621
- strings
4622
- }
4623
- );
4632
+ return /* @__PURE__ */ jsx25(ModuleState, { tone: "error", message: errorMsg, onRetry: () => setReloadKey((k) => k + 1), strings });
4624
4633
  }
4625
4634
  if (items.length === 0) return /* @__PURE__ */ jsx25(ModuleState, { message: strings.helpEmpty, strings });
4626
4635
  return groupByCategory(items).map(([category, rows]) => /* @__PURE__ */ jsxs20("section", { class: `${p18}-help-group`, children: [
@@ -4770,6 +4779,7 @@ var log14 = logger.scope("news");
4770
4779
  function NewsRoot({ transport, strings, config, nav, panelProps }) {
4771
4780
  const tags = config.contentTags;
4772
4781
  const [state, setState] = useState8("loading");
4782
+ const [errorMsg, setErrorMsg] = useState8(strings.errorGeneric);
4773
4783
  const [items, setItems] = useState8([]);
4774
4784
  const [reloadKey, setReloadKey] = useState8(0);
4775
4785
  useEffect13(() => {
@@ -4782,6 +4792,7 @@ function NewsRoot({ transport, strings, config, nav, panelProps }) {
4782
4792
  }).catch((err) => {
4783
4793
  if (cancelled) return;
4784
4794
  log14.warn("listContent (news) failed", { err });
4795
+ setErrorMsg(errorMessageFor(err, strings));
4785
4796
  setState("error");
4786
4797
  });
4787
4798
  return () => {
@@ -4791,15 +4802,7 @@ function NewsRoot({ transport, strings, config, nav, panelProps }) {
4791
4802
  function renderBody() {
4792
4803
  if (state === "loading") return /* @__PURE__ */ jsx28(ModuleState, { message: strings.newsLoading, strings });
4793
4804
  if (state === "error") {
4794
- return /* @__PURE__ */ jsx28(
4795
- ModuleState,
4796
- {
4797
- tone: "error",
4798
- message: strings.errorGeneric,
4799
- onRetry: () => setReloadKey((k) => k + 1),
4800
- strings
4801
- }
4802
- );
4805
+ return /* @__PURE__ */ jsx28(ModuleState, { tone: "error", message: errorMsg, onRetry: () => setReloadKey((k) => k + 1), strings });
4803
4806
  }
4804
4807
  if (items.length === 0) return /* @__PURE__ */ jsx28(ModuleState, { message: strings.newsEmpty, strings });
4805
4808
  return /* @__PURE__ */ jsx28("div", { class: `${p21}-news-list`, children: items.map((item) => /* @__PURE__ */ jsxs22(
@@ -5224,7 +5227,7 @@ function App({ options, hostElement, bus }) {
5224
5227
  const [sessionReady, setSessionReady] = useState11(false);
5225
5228
  const isInlineLike = options.mode === "standalone" || options.mode === "inline";
5226
5229
  const initialPanelRef = useRef8(
5227
- resolveInitialPanelState(options, currentViewportWidth(), persistence.loadPanelOpen())
5230
+ resolveInitialPanelState(options, currentViewportWidth(), persistence.loadPanelOpen(), persistence.loadPanelSize())
5228
5231
  );
5229
5232
  const [isOpen, setIsOpen] = useState11(initialPanelRef.current.panelOpen);
5230
5233
  const initialPanelApplied = useRef8(false);
@@ -5295,13 +5298,19 @@ function App({ options, hostElement, bus }) {
5295
5298
  }, [feedback, patchAndSync]);
5296
5299
  useEffect17(() => {
5297
5300
  if (initialSizeApplied.current || !options.size.initialSize) return;
5298
- setPanelSize(pickInitialPanelSize(options.mode, options.size, currentViewportWidth()));
5299
5301
  initialSizeApplied.current = true;
5300
- }, [options.mode, options.size]);
5302
+ if (persistence.loadPanelSize()) return;
5303
+ setPanelSize(pickInitialPanelSize(options.mode, options.size, currentViewportWidth()));
5304
+ }, [options.mode, options.size, persistence]);
5301
5305
  useEffect17(() => {
5302
5306
  if (!sessionReady || initialPanelApplied.current) return;
5303
5307
  initialPanelApplied.current = true;
5304
- const state = resolveInitialPanelState(options, currentViewportWidth(), persistence.loadPanelOpen());
5308
+ const state = resolveInitialPanelState(
5309
+ options,
5310
+ currentViewportWidth(),
5311
+ persistence.loadPanelOpen(),
5312
+ persistence.loadPanelSize()
5313
+ );
5305
5314
  setIsOpen(state.panelOpen);
5306
5315
  setPanelSize(state.panelSize);
5307
5316
  }, [sessionReady, options, persistence]);
@@ -5506,7 +5515,7 @@ function App({ options, hostElement, bus }) {
5506
5515
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
5507
5516
  } catch (error) {
5508
5517
  assistantMsg.status = "error";
5509
- assistantMsg.errorText = error instanceof StreamError && error.status === 429 ? options.strings.errorRateLimited : options.strings.errorGeneric;
5518
+ assistantMsg.errorText = errorMessageFor(error, options.strings);
5510
5519
  feedback.play("error");
5511
5520
  bus.emit("error", error);
5512
5521
  options.onError?.(error);
@@ -5597,17 +5606,19 @@ function App({ options, hostElement, bus }) {
5597
5606
  if (chatId) homeNav.switchTab(chatId);
5598
5607
  }, [handleClear, homeNav, options]);
5599
5608
  const handleExpand = useCallback8(() => {
5600
- const next = panelSize !== "expanded";
5601
- log16.info("expand", { from: panelSize, expanded: next });
5602
- setPanelSize((s) => s === "expanded" ? "normal" : "expanded");
5603
- bus.emit("expand", next);
5604
- }, [bus, panelSize]);
5609
+ const nextSize = panelSize === "expanded" ? "normal" : "expanded";
5610
+ log16.info("expand", { from: panelSize, expanded: nextSize === "expanded" });
5611
+ setPanelSize(nextSize);
5612
+ persistence.savePanelSize(nextSize);
5613
+ bus.emit("expand", nextSize === "expanded");
5614
+ }, [bus, panelSize, persistence]);
5605
5615
  const handleFullscreen = useCallback8(() => {
5606
- const next = panelSize !== "fullscreen";
5607
- log16.info("fullscreen", { from: panelSize, fullscreen: next });
5608
- setPanelSize((s) => s === "fullscreen" ? "normal" : "fullscreen");
5609
- bus.emit("fullscreen", next);
5610
- }, [bus, panelSize]);
5616
+ const nextSize = panelSize === "fullscreen" ? "normal" : "fullscreen";
5617
+ log16.info("fullscreen", { from: panelSize, fullscreen: nextSize === "fullscreen" });
5618
+ setPanelSize(nextSize);
5619
+ persistence.savePanelSize(nextSize);
5620
+ bus.emit("fullscreen", nextSize === "fullscreen");
5621
+ }, [bus, panelSize, persistence]);
5611
5622
  const handlePopOut = useCallback8(() => {
5612
5623
  if (!options.popOutUrl) return;
5613
5624
  const url = new URL(options.popOutUrl);
@@ -6174,7 +6185,8 @@ function resolveInitialHostMode(options) {
6174
6185
  const { panelOpen, panelSize } = resolveInitialPanelState(
6175
6186
  options,
6176
6187
  currentViewportWidth(),
6177
- persistence.loadPanelOpen()
6188
+ persistence.loadPanelOpen(),
6189
+ persistence.loadPanelSize()
6178
6190
  );
6179
6191
  return computeHostMode(options.mode, panelSize, panelOpen);
6180
6192
  }
package/package.json CHANGED
@@ -80,5 +80,5 @@
80
80
  ],
81
81
  "type": "module",
82
82
  "types": "./index.d.ts",
83
- "version": "0.6.0"
83
+ "version": "0.7.1"
84
84
  }
package/schema.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, E as Endpoints, L as Link, P as PAGE_AREA_SUGGESTIONS, g as PageContext, S as ServerConfig, b as SiteConfig, c as StartSessionResponse, U as UserContext, W as WidgetConfig, d as WidgetConfigPartial, e as WidgetSettings, f as WidgetSettingsPartial, h as assetSchema, i as blocksConfigSchema, j as connectionConfigPartialSchema, k as connectionConfigSchema, l as cssColorSchema, m as cssLengthSchema, n as endpointsSchema, o as linkSchema, p as localeSchema, q as pageContextSchema, s as serverConfigSchema, r as siteConfigSchema, t as startSessionResponseSchema, u as userContextSchema, v as uuid7Schema, w as widgetConfigPartialSchema, x as widgetConfigSchema, y as widgetSettingsPartialSchema, z as widgetSettingsSchema } from './deployment-DKyrRSGL.js';
1
+ export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, E as Endpoints, L as Link, P as PAGE_AREA_SUGGESTIONS, g as PageContext, S as ServerConfig, b as SiteConfig, c as StartSessionResponse, U as UserContext, W as WidgetConfig, d as WidgetConfigPartial, e as WidgetSettings, f as WidgetSettingsPartial, h as assetSchema, i as blocksConfigSchema, j as connectionConfigPartialSchema, k as connectionConfigSchema, l as cssColorSchema, m as cssLengthSchema, n as endpointsSchema, o as linkSchema, p as localeSchema, q as pageContextSchema, s as serverConfigSchema, r as siteConfigSchema, t as startSessionResponseSchema, u as userContextSchema, v as uuid7Schema, w as widgetConfigPartialSchema, x as widgetConfigSchema, y as widgetSettingsPartialSchema, z as widgetSettingsSchema } from './deployment-DhWwzofY.js';
2
2
  import { z } from 'zod';
3
3
 
4
4
  /**
@@ -56,9 +56,9 @@ declare const presentationSchema: z.ZodObject<{
56
56
  inset: z.ZodOptional<z.ZodString>;
57
57
  initialSize: z.ZodDefault<z.ZodEnum<{
58
58
  fullscreen: "fullscreen";
59
+ expanded: "expanded";
59
60
  auto: "auto";
60
61
  normal: "normal";
61
- expanded: "expanded";
62
62
  }>>;
63
63
  autoSizeBreakpoint: z.ZodDefault<z.ZodNumber>;
64
64
  }, z.core.$loose>>;
@@ -148,9 +148,9 @@ declare const launcherSizeSchema: z.ZodEnum<{
148
148
  }>;
149
149
  type LauncherSize = z.infer<typeof launcherSizeSchema>;
150
150
  declare const calloutShapeSchema: z.ZodEnum<{
151
+ callout: "callout";
151
152
  pill: "pill";
152
153
  bubble: "bubble";
153
- callout: "callout";
154
154
  }>;
155
155
  type CalloutShape = z.infer<typeof calloutShapeSchema>;
156
156
  declare const calloutPositionSchema: z.ZodEnum<{
@@ -162,9 +162,9 @@ type CalloutPosition = z.infer<typeof calloutPositionSchema>;
162
162
  declare const launcherCalloutSchema: z.ZodObject<{
163
163
  text: z.ZodDefault<z.ZodString>;
164
164
  shape: z.ZodDefault<z.ZodEnum<{
165
+ callout: "callout";
165
166
  pill: "pill";
166
167
  bubble: "bubble";
167
- callout: "callout";
168
168
  }>>;
169
169
  position: z.ZodDefault<z.ZodEnum<{
170
170
  auto: "auto";
@@ -195,9 +195,9 @@ declare const launcherOptionsSchema: z.ZodObject<{
195
195
  callout: z.ZodOptional<z.ZodObject<{
196
196
  text: z.ZodDefault<z.ZodString>;
197
197
  shape: z.ZodDefault<z.ZodEnum<{
198
+ callout: "callout";
198
199
  pill: "pill";
199
200
  bubble: "bubble";
200
- callout: "callout";
201
201
  }>>;
202
202
  position: z.ZodDefault<z.ZodEnum<{
203
203
  auto: "auto";
@@ -240,9 +240,9 @@ type LauncherOptions = z.infer<typeof launcherOptionsSchema>;
240
240
 
241
241
  declare const initialSizeSchema: z.ZodEnum<{
242
242
  fullscreen: "fullscreen";
243
+ expanded: "expanded";
243
244
  auto: "auto";
244
245
  normal: "normal";
245
- expanded: "expanded";
246
246
  }>;
247
247
  declare const resizeOptionsSchema: z.ZodObject<{
248
248
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -269,9 +269,9 @@ declare const sizeOptionsSchema: z.ZodObject<{
269
269
  inset: z.ZodOptional<z.ZodString>;
270
270
  initialSize: z.ZodDefault<z.ZodEnum<{
271
271
  fullscreen: "fullscreen";
272
+ expanded: "expanded";
272
273
  auto: "auto";
273
274
  normal: "normal";
274
- expanded: "expanded";
275
275
  }>>;
276
276
  autoSizeBreakpoint: z.ZodDefault<z.ZodNumber>;
277
277
  }, z.core.$loose>;
@@ -321,38 +321,38 @@ type FeatureFlags = z.infer<typeof featureFlagsSchema>;
321
321
  */
322
322
 
323
323
  declare const actionNameSchema: z.ZodEnum<{
324
+ close: "close";
324
325
  expand: "expand";
325
326
  fullscreen: "fullscreen";
326
327
  popOut: "popOut";
327
- close: "close";
328
- language: "language";
328
+ clear: "clear";
329
329
  theme: "theme";
330
+ language: "language";
330
331
  history: "history";
331
- clear: "clear";
332
332
  sound: "sound";
333
333
  }>;
334
334
  type ActionName = z.infer<typeof actionNameSchema>;
335
335
  declare const headerActionsSchema: z.ZodObject<{
336
336
  main: z.ZodDefault<z.ZodArray<z.ZodEnum<{
337
+ close: "close";
337
338
  expand: "expand";
338
339
  fullscreen: "fullscreen";
339
340
  popOut: "popOut";
340
- close: "close";
341
- language: "language";
341
+ clear: "clear";
342
342
  theme: "theme";
343
+ language: "language";
343
344
  history: "history";
344
- clear: "clear";
345
345
  sound: "sound";
346
346
  }>>>;
347
347
  overflow: z.ZodDefault<z.ZodArray<z.ZodEnum<{
348
+ close: "close";
348
349
  expand: "expand";
349
350
  fullscreen: "fullscreen";
350
351
  popOut: "popOut";
351
- close: "close";
352
- language: "language";
352
+ clear: "clear";
353
353
  theme: "theme";
354
+ language: "language";
354
355
  history: "history";
355
- clear: "clear";
356
356
  sound: "sound";
357
357
  }>>>;
358
358
  }, z.core.$loose>;
@@ -361,25 +361,25 @@ type HeaderActions = z.infer<typeof headerActionsSchema>;
361
361
  declare const headerSchema: z.ZodObject<{
362
362
  actions: z.ZodOptional<z.ZodObject<{
363
363
  main: z.ZodDefault<z.ZodArray<z.ZodEnum<{
364
+ close: "close";
364
365
  expand: "expand";
365
366
  fullscreen: "fullscreen";
366
367
  popOut: "popOut";
367
- close: "close";
368
- language: "language";
368
+ clear: "clear";
369
369
  theme: "theme";
370
+ language: "language";
370
371
  history: "history";
371
- clear: "clear";
372
372
  sound: "sound";
373
373
  }>>>;
374
374
  overflow: z.ZodDefault<z.ZodArray<z.ZodEnum<{
375
+ close: "close";
375
376
  expand: "expand";
376
377
  fullscreen: "fullscreen";
377
378
  popOut: "popOut";
378
- close: "close";
379
- language: "language";
379
+ clear: "clear";
380
380
  theme: "theme";
381
+ language: "language";
381
382
  history: "history";
382
- clear: "clear";
383
383
  sound: "sound";
384
384
  }>>>;
385
385
  }, z.core.$loose>>;
@@ -396,33 +396,33 @@ type HeaderOptions = z.infer<typeof headerSchema>;
396
396
  */
397
397
 
398
398
  declare const feedbackEventSchema: z.ZodEnum<{
399
+ voiceStart: "voiceStart";
400
+ voiceStop: "voiceStop";
399
401
  error: "error";
400
402
  messageReceived: "messageReceived";
401
403
  messageSent: "messageSent";
402
- voiceStart: "voiceStart";
403
- voiceStop: "voiceStop";
404
404
  }>;
405
405
  type FeedbackEvent = z.infer<typeof feedbackEventSchema>;
406
406
  declare const soundOptionsSchema: z.ZodObject<{
407
407
  enabled: z.ZodDefault<z.ZodBoolean>;
408
408
  volume: z.ZodDefault<z.ZodNumber>;
409
409
  events: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
410
+ voiceStart: "voiceStart";
411
+ voiceStop: "voiceStop";
410
412
  error: "error";
411
413
  messageReceived: "messageReceived";
412
414
  messageSent: "messageSent";
413
- voiceStart: "voiceStart";
414
- voiceStop: "voiceStop";
415
415
  }> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>>;
416
416
  }, z.core.$loose>;
417
417
  type SoundOptions = z.infer<typeof soundOptionsSchema>;
418
418
  declare const hapticsOptionsSchema: z.ZodObject<{
419
419
  enabled: z.ZodDefault<z.ZodBoolean>;
420
420
  events: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
421
+ voiceStart: "voiceStart";
422
+ voiceStop: "voiceStop";
421
423
  error: "error";
422
424
  messageReceived: "messageReceived";
423
425
  messageSent: "messageSent";
424
- voiceStart: "voiceStart";
425
- voiceStop: "voiceStop";
426
426
  }> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodNumber, z.ZodArray<z.ZodNumber>]>>>;
427
427
  }, z.core.$loose>;
428
428
  type HapticsOptions = z.infer<typeof hapticsOptionsSchema>;
@@ -431,21 +431,21 @@ declare const feedbackSchema: z.ZodObject<{
431
431
  enabled: z.ZodDefault<z.ZodBoolean>;
432
432
  volume: z.ZodDefault<z.ZodNumber>;
433
433
  events: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
434
+ voiceStart: "voiceStart";
435
+ voiceStop: "voiceStop";
434
436
  error: "error";
435
437
  messageReceived: "messageReceived";
436
438
  messageSent: "messageSent";
437
- voiceStart: "voiceStart";
438
- voiceStop: "voiceStop";
439
439
  }> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>>;
440
440
  }, z.core.$loose>>;
441
441
  haptics: z.ZodOptional<z.ZodObject<{
442
442
  enabled: z.ZodDefault<z.ZodBoolean>;
443
443
  events: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
444
+ voiceStart: "voiceStart";
445
+ voiceStop: "voiceStop";
444
446
  error: "error";
445
447
  messageReceived: "messageReceived";
446
448
  messageSent: "messageSent";
447
- voiceStart: "voiceStart";
448
- voiceStop: "voiceStop";
449
449
  }> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodNumber, z.ZodArray<z.ZodNumber>]>>>;
450
450
  }, z.core.$loose>>;
451
451
  }, z.core.$loose>;
@@ -607,18 +607,18 @@ type I18nOptions = z.infer<typeof i18nSchema>;
607
607
  */
608
608
 
609
609
  declare const moduleLayoutSchema: z.ZodEnum<{
610
+ home: "home";
610
611
  chat: "chat";
611
612
  help: "help";
612
- home: "home";
613
613
  news: "news";
614
614
  }>;
615
615
  type ModuleLayout = z.infer<typeof moduleLayoutSchema>;
616
616
  declare const moduleSchema: z.ZodObject<{
617
617
  label: z.ZodString;
618
618
  layout: z.ZodEnum<{
619
+ home: "home";
619
620
  chat: "chat";
620
621
  help: "help";
621
- home: "home";
622
622
  news: "news";
623
623
  }>;
624
624
  contentTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -644,9 +644,9 @@ type ModuleOptions = z.infer<typeof moduleSchema>;
644
644
  declare const modulesSchema: z.ZodArray<z.ZodObject<{
645
645
  label: z.ZodString;
646
646
  layout: z.ZodEnum<{
647
+ home: "home";
647
648
  chat: "chat";
648
649
  help: "help";
649
- home: "home";
650
650
  news: "news";
651
651
  }>;
652
652
  contentTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
package/web-component.mjs CHANGED
@@ -948,10 +948,11 @@ function pickInitialPanelSize(mode, size, viewportWidth) {
948
948
  }
949
949
  return "normal";
950
950
  }
951
- function resolveInitialPanelState(options, viewportWidth, persistedPanelOpen) {
951
+ function resolveInitialPanelState(options, viewportWidth, persistedPanelOpen, persistedPanelSize = null) {
952
952
  const isInlineLike = options.mode === "inline" || options.mode === "standalone" || options.mode === "page";
953
953
  const panelOpen = isInlineLike || (persistedPanelOpen ?? !options.startMinimized);
954
- const panelSize = pickInitialPanelSize(options.mode, options.size, viewportWidth);
954
+ const honorsPersisted = options.mode !== "standalone" && options.mode !== "page" && options.mode !== "inline";
955
+ const panelSize = honorsPersisted && persistedPanelSize ? persistedPanelSize : pickInitialPanelSize(options.mode, options.size, viewportWidth);
955
956
  return { panelOpen, panelSize };
956
957
  }
957
958
  function currentViewportWidth() {
@@ -1874,6 +1875,7 @@ function createPersistence(widgetId, storage = defaultStorage) {
1874
1875
  const KEY_CHAT = `${prefix}.sessionId`;
1875
1876
  const KEY_USER_PREFS = `${prefix}.userPrefs`;
1876
1877
  const KEY_PANEL_OPEN = `${prefix}.panelOpen`;
1878
+ const KEY_PANEL_SIZE = `${prefix}.panelSize`;
1877
1879
  const KEY_CALLOUT_DISMISSED = `${prefix}.calloutDismissed`;
1878
1880
  const KEY_SIDEBAR_COLLAPSED = `${prefix}.sidebarCollapsed`;
1879
1881
  const KEY_ACTIVE_MODULE = `${prefix}.activeModule`;
@@ -1928,6 +1930,13 @@ function createPersistence(widgetId, storage = defaultStorage) {
1928
1930
  savePanelOpen(open) {
1929
1931
  storage.set(KEY_PANEL_OPEN, open ? "1" : "0");
1930
1932
  },
1933
+ loadPanelSize() {
1934
+ const raw = storage.get(KEY_PANEL_SIZE);
1935
+ return raw === "normal" || raw === "expanded" || raw === "fullscreen" ? raw : null;
1936
+ },
1937
+ savePanelSize(size) {
1938
+ storage.set(KEY_PANEL_SIZE, size);
1939
+ },
1931
1940
  loadCalloutDismissed(currentText) {
1932
1941
  if (!currentText) return false;
1933
1942
  const dismissedText = storage.get(KEY_CALLOUT_DISMISSED);
@@ -2233,6 +2242,12 @@ var FeedbackBus = class {
2233
2242
  }
2234
2243
  };
2235
2244
 
2245
+ // src/ui/error-message.ts
2246
+ function errorMessageFor(error, strings) {
2247
+ if (error instanceof StreamError && error.status === 429) return strings.errorRateLimited;
2248
+ return strings.errorGeneric;
2249
+ }
2250
+
2236
2251
  // src/ui/launcher.tsx
2237
2252
  import { useEffect, useState } from "preact/hooks";
2238
2253
 
@@ -4649,6 +4664,7 @@ function ArticleRow({ article, nav }) {
4649
4664
  function HelpRoot({ transport, strings, config, nav, panelProps }) {
4650
4665
  const tags = config.contentTags;
4651
4666
  const [state, setState] = useState6("loading");
4667
+ const [errorMsg, setErrorMsg] = useState6(strings.errorGeneric);
4652
4668
  const [items, setItems] = useState6([]);
4653
4669
  const [query, setQuery] = useState6("");
4654
4670
  const [reloadKey, setReloadKey] = useState6(0);
@@ -4662,6 +4678,7 @@ function HelpRoot({ transport, strings, config, nav, panelProps }) {
4662
4678
  }).catch((err) => {
4663
4679
  if (cancelled) return;
4664
4680
  log12.warn("listContent (help) failed", { err });
4681
+ setErrorMsg(errorMessageFor(err, strings));
4665
4682
  setState("error");
4666
4683
  });
4667
4684
  return () => {
@@ -4676,15 +4693,7 @@ function HelpRoot({ transport, strings, config, nav, panelProps }) {
4676
4693
  }
4677
4694
  if (state === "loading") return /* @__PURE__ */ jsx25(ModuleState, { message: strings.helpLoading, strings });
4678
4695
  if (state === "error") {
4679
- return /* @__PURE__ */ jsx25(
4680
- ModuleState,
4681
- {
4682
- tone: "error",
4683
- message: strings.errorGeneric,
4684
- onRetry: () => setReloadKey((k) => k + 1),
4685
- strings
4686
- }
4687
- );
4696
+ return /* @__PURE__ */ jsx25(ModuleState, { tone: "error", message: errorMsg, onRetry: () => setReloadKey((k) => k + 1), strings });
4688
4697
  }
4689
4698
  if (items.length === 0) return /* @__PURE__ */ jsx25(ModuleState, { message: strings.helpEmpty, strings });
4690
4699
  return groupByCategory(items).map(([category, rows]) => /* @__PURE__ */ jsxs20("section", { class: `${p18}-help-group`, children: [
@@ -4834,6 +4843,7 @@ var log14 = logger.scope("news");
4834
4843
  function NewsRoot({ transport, strings, config, nav, panelProps }) {
4835
4844
  const tags = config.contentTags;
4836
4845
  const [state, setState] = useState8("loading");
4846
+ const [errorMsg, setErrorMsg] = useState8(strings.errorGeneric);
4837
4847
  const [items, setItems] = useState8([]);
4838
4848
  const [reloadKey, setReloadKey] = useState8(0);
4839
4849
  useEffect13(() => {
@@ -4846,6 +4856,7 @@ function NewsRoot({ transport, strings, config, nav, panelProps }) {
4846
4856
  }).catch((err) => {
4847
4857
  if (cancelled) return;
4848
4858
  log14.warn("listContent (news) failed", { err });
4859
+ setErrorMsg(errorMessageFor(err, strings));
4849
4860
  setState("error");
4850
4861
  });
4851
4862
  return () => {
@@ -4855,15 +4866,7 @@ function NewsRoot({ transport, strings, config, nav, panelProps }) {
4855
4866
  function renderBody() {
4856
4867
  if (state === "loading") return /* @__PURE__ */ jsx28(ModuleState, { message: strings.newsLoading, strings });
4857
4868
  if (state === "error") {
4858
- return /* @__PURE__ */ jsx28(
4859
- ModuleState,
4860
- {
4861
- tone: "error",
4862
- message: strings.errorGeneric,
4863
- onRetry: () => setReloadKey((k) => k + 1),
4864
- strings
4865
- }
4866
- );
4869
+ return /* @__PURE__ */ jsx28(ModuleState, { tone: "error", message: errorMsg, onRetry: () => setReloadKey((k) => k + 1), strings });
4867
4870
  }
4868
4871
  if (items.length === 0) return /* @__PURE__ */ jsx28(ModuleState, { message: strings.newsEmpty, strings });
4869
4872
  return /* @__PURE__ */ jsx28("div", { class: `${p21}-news-list`, children: items.map((item) => /* @__PURE__ */ jsxs22(
@@ -5288,7 +5291,7 @@ function App({ options, hostElement, bus }) {
5288
5291
  const [sessionReady, setSessionReady] = useState11(false);
5289
5292
  const isInlineLike = options.mode === "standalone" || options.mode === "inline";
5290
5293
  const initialPanelRef = useRef8(
5291
- resolveInitialPanelState(options, currentViewportWidth(), persistence.loadPanelOpen())
5294
+ resolveInitialPanelState(options, currentViewportWidth(), persistence.loadPanelOpen(), persistence.loadPanelSize())
5292
5295
  );
5293
5296
  const [isOpen, setIsOpen] = useState11(initialPanelRef.current.panelOpen);
5294
5297
  const initialPanelApplied = useRef8(false);
@@ -5359,13 +5362,19 @@ function App({ options, hostElement, bus }) {
5359
5362
  }, [feedback, patchAndSync]);
5360
5363
  useEffect17(() => {
5361
5364
  if (initialSizeApplied.current || !options.size.initialSize) return;
5362
- setPanelSize(pickInitialPanelSize(options.mode, options.size, currentViewportWidth()));
5363
5365
  initialSizeApplied.current = true;
5364
- }, [options.mode, options.size]);
5366
+ if (persistence.loadPanelSize()) return;
5367
+ setPanelSize(pickInitialPanelSize(options.mode, options.size, currentViewportWidth()));
5368
+ }, [options.mode, options.size, persistence]);
5365
5369
  useEffect17(() => {
5366
5370
  if (!sessionReady || initialPanelApplied.current) return;
5367
5371
  initialPanelApplied.current = true;
5368
- const state = resolveInitialPanelState(options, currentViewportWidth(), persistence.loadPanelOpen());
5372
+ const state = resolveInitialPanelState(
5373
+ options,
5374
+ currentViewportWidth(),
5375
+ persistence.loadPanelOpen(),
5376
+ persistence.loadPanelSize()
5377
+ );
5369
5378
  setIsOpen(state.panelOpen);
5370
5379
  setPanelSize(state.panelSize);
5371
5380
  }, [sessionReady, options, persistence]);
@@ -5570,7 +5579,7 @@ function App({ options, hostElement, bus }) {
5570
5579
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
5571
5580
  } catch (error) {
5572
5581
  assistantMsg.status = "error";
5573
- assistantMsg.errorText = error instanceof StreamError && error.status === 429 ? options.strings.errorRateLimited : options.strings.errorGeneric;
5582
+ assistantMsg.errorText = errorMessageFor(error, options.strings);
5574
5583
  feedback.play("error");
5575
5584
  bus.emit("error", error);
5576
5585
  options.onError?.(error);
@@ -5661,17 +5670,19 @@ function App({ options, hostElement, bus }) {
5661
5670
  if (chatId) homeNav.switchTab(chatId);
5662
5671
  }, [handleClear, homeNav, options]);
5663
5672
  const handleExpand = useCallback8(() => {
5664
- const next = panelSize !== "expanded";
5665
- log16.info("expand", { from: panelSize, expanded: next });
5666
- setPanelSize((s) => s === "expanded" ? "normal" : "expanded");
5667
- bus.emit("expand", next);
5668
- }, [bus, panelSize]);
5673
+ const nextSize = panelSize === "expanded" ? "normal" : "expanded";
5674
+ log16.info("expand", { from: panelSize, expanded: nextSize === "expanded" });
5675
+ setPanelSize(nextSize);
5676
+ persistence.savePanelSize(nextSize);
5677
+ bus.emit("expand", nextSize === "expanded");
5678
+ }, [bus, panelSize, persistence]);
5669
5679
  const handleFullscreen = useCallback8(() => {
5670
- const next = panelSize !== "fullscreen";
5671
- log16.info("fullscreen", { from: panelSize, fullscreen: next });
5672
- setPanelSize((s) => s === "fullscreen" ? "normal" : "fullscreen");
5673
- bus.emit("fullscreen", next);
5674
- }, [bus, panelSize]);
5680
+ const nextSize = panelSize === "fullscreen" ? "normal" : "fullscreen";
5681
+ log16.info("fullscreen", { from: panelSize, fullscreen: nextSize === "fullscreen" });
5682
+ setPanelSize(nextSize);
5683
+ persistence.savePanelSize(nextSize);
5684
+ bus.emit("fullscreen", nextSize === "fullscreen");
5685
+ }, [bus, panelSize, persistence]);
5675
5686
  const handlePopOut = useCallback8(() => {
5676
5687
  if (!options.popOutUrl) return;
5677
5688
  const url = new URL(options.popOutUrl);
@@ -5961,7 +5972,8 @@ function resolveInitialHostMode(options) {
5961
5972
  const { panelOpen, panelSize } = resolveInitialPanelState(
5962
5973
  options,
5963
5974
  currentViewportWidth(),
5964
- persistence.loadPanelOpen()
5975
+ persistence.loadPanelOpen(),
5976
+ persistence.loadPanelSize()
5965
5977
  );
5966
5978
  return computeHostMode(options.mode, panelSize, panelOpen);
5967
5979
  }