framepexls-ui-lib 2.2.7 → 2.2.11

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 (50) hide show
  1. package/dist/AccessibilityFab.js +2 -0
  2. package/dist/AccessibilityFab.mjs +2 -0
  3. package/dist/AvatarSquare.d.mts +4 -1
  4. package/dist/AvatarSquare.d.ts +4 -1
  5. package/dist/AvatarSquare.js +7 -1
  6. package/dist/AvatarSquare.mjs +7 -1
  7. package/dist/Checkbox.js +2 -2
  8. package/dist/Checkbox.mjs +2 -2
  9. package/dist/ComboSelect.js +4 -3
  10. package/dist/ComboSelect.mjs +4 -3
  11. package/dist/DateTimeField.js +3 -2
  12. package/dist/DateTimeField.mjs +3 -2
  13. package/dist/Dropdown.js +3 -0
  14. package/dist/Dropdown.mjs +3 -0
  15. package/dist/HeliipLoader.js +77 -5
  16. package/dist/HeliipLoader.mjs +77 -5
  17. package/dist/MarkdownEditor.d.mts +71 -3
  18. package/dist/MarkdownEditor.d.ts +71 -3
  19. package/dist/MarkdownEditor.js +2370 -65
  20. package/dist/MarkdownEditor.mjs +2388 -66
  21. package/dist/MediaSelector.d.mts +4 -1
  22. package/dist/MediaSelector.d.ts +4 -1
  23. package/dist/MediaSelector.js +134 -23
  24. package/dist/MediaSelector.mjs +135 -24
  25. package/dist/Select.js +2 -0
  26. package/dist/Select.mjs +2 -0
  27. package/dist/Sidebar.d.mts +2 -1
  28. package/dist/Sidebar.d.ts +2 -1
  29. package/dist/Sidebar.js +82 -19
  30. package/dist/Sidebar.mjs +82 -19
  31. package/dist/SupportChatWidget.js +88 -42
  32. package/dist/SupportChatWidget.mjs +89 -42
  33. package/dist/TimePanel.js +2 -1
  34. package/dist/TimePanel.mjs +2 -1
  35. package/dist/TimePopover.js +4 -3
  36. package/dist/TimePopover.mjs +4 -3
  37. package/dist/TimeRangeField.js +3 -2
  38. package/dist/TimeRangeField.mjs +3 -2
  39. package/dist/UploadCard.js +7 -7
  40. package/dist/UploadCard.mjs +7 -7
  41. package/dist/index.d.mts +1 -1
  42. package/dist/index.d.ts +1 -1
  43. package/dist/index.js +4 -0
  44. package/dist/index.mjs +3 -1
  45. package/dist/theme/FontSizeController.js +1 -1
  46. package/dist/theme/FontSizeController.mjs +1 -1
  47. package/dist/theme/ThemeController.js +2 -1
  48. package/dist/theme/ThemeController.mjs +2 -1
  49. package/dist/theme.css +47 -0
  50. package/package.json +8 -8
package/dist/Sidebar.js CHANGED
@@ -64,7 +64,24 @@ function groupItems(items) {
64
64
  }
65
65
  return Array.from(byGroup.entries());
66
66
  }
67
- function GroupHeader({ title }) {
67
+ function GroupHeader({ collapsed, onToggle, title }) {
68
+ if (onToggle) {
69
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
70
+ import_Button.default,
71
+ {
72
+ unstyled: true,
73
+ type: "button",
74
+ "aria-expanded": !collapsed,
75
+ onClick: onToggle,
76
+ className: "mb-3 flex w-full items-center gap-3 rounded-xl px-2 py-1 text-left transition-colors duration-200 hover:bg-[color-mix(in_oklab,var(--foreground)_5%,transparent)] focus:outline-none focus-visible:ring-1 focus-visible:ring-[var(--primary)]",
77
+ children: [
78
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[0.6875rem] font-semibold uppercase tracking-[0.18em] text-[var(--muted)]", children: title }),
79
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "h-px flex-1 bg-[linear-gradient(90deg,color-mix(in_oklab,var(--border)_72%,transparent),transparent)]" }),
80
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_iconos.ChevronDownIcon, { "aria-hidden": true, className: cx("h-3.5 w-3.5 shrink-0 text-[var(--muted)] transition-transform duration-300 ease-[cubic-bezier(0.22,1,0.36,1)]", collapsed ? "-rotate-90" : "rotate-0") })
81
+ ]
82
+ }
83
+ );
84
+ }
68
85
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-3 flex items-center gap-3 px-2 select-none", children: [
69
86
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-[0.6875rem] font-semibold uppercase tracking-[0.18em] text-[var(--muted)] text-left", children: title }),
70
87
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-px flex-1 bg-[linear-gradient(90deg,color-mix(in_oklab,var(--border)_72%,transparent),transparent)]" })
@@ -275,6 +292,7 @@ function Sidebar({
275
292
  onBrandClick,
276
293
  showBrand = true,
277
294
  collapsedKey = "ga:sidebar-collapsed",
295
+ groupCollapsePersistKey,
278
296
  defaultCollapsed,
279
297
  onCollapsedChange,
280
298
  brandLogoSrc,
@@ -319,6 +337,8 @@ function Sidebar({
319
337
  const [navQuery, setNavQuery] = import_react.default.useState("");
320
338
  const [navDrag, setNavDrag] = import_react.default.useState(null);
321
339
  const [navDrop, setNavDrop] = import_react.default.useState(null);
340
+ const resolvedGroupCollapsePersistKey = groupCollapsePersistKey != null ? groupCollapsePersistKey : `${collapsedKey}:groups`;
341
+ const [collapsedGroups, setCollapsedGroups] = import_react.default.useState({});
322
342
  (0, import_react.useLayoutEffect)(() => {
323
343
  if (!(workspaces == null ? void 0 : workspaces.length)) return;
324
344
  if (activeWorkspaceId !== void 0) return;
@@ -349,6 +369,16 @@ function Sidebar({
349
369
  (0, import_react.useEffect)(() => {
350
370
  setMotionEnabled(true);
351
371
  }, []);
372
+ (0, import_react.useLayoutEffect)(() => {
373
+ if (!resolvedGroupCollapsePersistKey) return;
374
+ try {
375
+ const raw = localStorage.getItem(resolvedGroupCollapsePersistKey);
376
+ const parsed = raw ? JSON.parse(raw) : null;
377
+ setCollapsedGroups(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
378
+ } catch {
379
+ setCollapsedGroups({});
380
+ }
381
+ }, [resolvedGroupCollapsePersistKey]);
352
382
  (0, import_react.useLayoutEffect)(() => {
353
383
  if (!navEnabled) return;
354
384
  try {
@@ -375,9 +405,20 @@ function Sidebar({
375
405
  }
376
406
  onCollapsedChange == null ? void 0 : onCollapsedChange(collapsed);
377
407
  }, [collapsed, collapsedKey, motionEnabled, onCollapsedChange]);
408
+ (0, import_react.useEffect)(() => {
409
+ if (!motionEnabled) return;
410
+ if (!resolvedGroupCollapsePersistKey) return;
411
+ try {
412
+ localStorage.setItem(resolvedGroupCollapsePersistKey, JSON.stringify(collapsedGroups));
413
+ } catch {
414
+ }
415
+ }, [collapsedGroups, motionEnabled, resolvedGroupCollapsePersistKey]);
378
416
  const toggleCollapsed = () => {
379
417
  setCollapsed((c) => !c);
380
418
  };
419
+ const toggleGroupCollapsed = import_react.default.useCallback((groupName) => {
420
+ setCollapsedGroups((current) => ({ ...current, [groupName]: !current[groupName] }));
421
+ }, []);
381
422
  const sidebarWidth = collapsed ? 112 : 288;
382
423
  const sidebarWidthTransition = motionEnabled ? {
383
424
  type: "tween",
@@ -630,8 +671,10 @@ function Sidebar({
630
671
  SidebarInner,
631
672
  {
632
673
  groups,
674
+ collapsedGroups,
633
675
  collapsed,
634
676
  toggleCollapsed,
677
+ onToggleGroup: toggleGroupCollapsed,
635
678
  activeKey,
636
679
  go,
637
680
  navEditable: navEnabled,
@@ -725,9 +768,11 @@ function Sidebar({
725
768
  SidebarInner,
726
769
  {
727
770
  groups,
771
+ collapsedGroups,
728
772
  mobile: true,
729
773
  activeKey,
730
774
  toggleCollapsed,
775
+ onToggleGroup: toggleGroupCollapsed,
731
776
  go,
732
777
  navEditable: navEnabled,
733
778
  navCustomizeLabel: navCustomizeButtonLabel,
@@ -1787,8 +1832,10 @@ function WorkspaceSwitcher({
1787
1832
  }
1788
1833
  function SidebarInner({
1789
1834
  groups,
1835
+ collapsedGroups,
1790
1836
  collapsed,
1791
1837
  toggleCollapsed,
1838
+ onToggleGroup,
1792
1839
  mobile,
1793
1840
  activeKey,
1794
1841
  go,
@@ -1909,6 +1956,11 @@ function SidebarInner({
1909
1956
  const calmFadeInitial = { opacity: 0, y: 4, filter: "blur(6px)" };
1910
1957
  const calmFadeAnimate = { opacity: 1, y: 0, filter: "blur(0px)" };
1911
1958
  const calmFadeExit = { opacity: 0, y: 2, filter: "blur(6px)" };
1959
+ const groupCollapseTransition = { duration: 0.12, ease: "easeOut" };
1960
+ const groupHasActiveItem = import_react.default.useCallback((items) => items.some((item) => {
1961
+ var _a2;
1962
+ return item.key === activeKey || ((_a2 = item.children) != null ? _a2 : []).some((child) => child.key === activeKey);
1963
+ }), [activeKey]);
1912
1964
  const QuickIcon = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "grid h-9 w-9 place-items-center rounded-2xl text-[var(--muted)] transition-all duration-300 group-hover:scale-[1.04] group-hover:text-[var(--foreground)]", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[var(--foreground)]", children }) });
1913
1965
  const QuickActionsSection = () => {
1914
1966
  if (!hasQuickActions) return null;
@@ -2425,35 +2477,46 @@ function SidebarInner({
2425
2477
  return ((_a3 = i.children) == null ? void 0 : _a3.length) ? i.children.some((c) => c) : true;
2426
2478
  });
2427
2479
  if (visibles.length === 0) return null;
2480
+ const groupCollapsed = !groupHasActiveItem(visibles) && Boolean(collapsedGroups == null ? void 0 : collapsedGroups[groupName]);
2428
2481
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2429
2482
  import_framer_motion.motion.div,
2430
2483
  {
2431
- layout: true,
2432
2484
  initial: calmFadeInitial,
2433
2485
  animate: calmFadeAnimate,
2434
2486
  transition: { duration: 0.24, delay: groupIndex * 0.03, ease: calmFadeEase },
2435
2487
  children: [
2436
- !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GroupHeader, { title: groupName }) : null,
2437
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-2", children: visibles.map((item, itemIndex) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2488
+ !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GroupHeader, { collapsed: groupCollapsed, title: groupName, onToggle: () => onToggleGroup == null ? void 0 : onToggleGroup(groupName) }) : null,
2489
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_framer_motion.AnimatePresence, { initial: false, children: !groupCollapsed || collapsed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2438
2490
  import_framer_motion.motion.div,
2439
2491
  {
2440
- layout: true,
2441
- initial: { opacity: 0, filter: "blur(6px)" },
2442
- animate: { opacity: 1, filter: "blur(0px)" },
2443
- transition: { duration: 0.2, delay: itemIndex * 0.02, ease: calmFadeEase },
2444
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2445
- RenderItem,
2492
+ initial: { opacity: 0 },
2493
+ animate: { opacity: 1 },
2494
+ exit: { opacity: 0 },
2495
+ transition: groupCollapseTransition,
2496
+ className: "space-y-2",
2497
+ style: { willChange: "opacity" },
2498
+ children: visibles.map((item, itemIndex) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2499
+ import_framer_motion.motion.div,
2446
2500
  {
2447
- item,
2448
- collapsed: collapsed != null ? collapsed : false,
2449
- activeKey,
2450
- go,
2451
- color
2452
- }
2453
- )
2501
+ initial: { opacity: 0 },
2502
+ animate: { opacity: 1 },
2503
+ transition: { duration: 0.1, ease: "easeOut" },
2504
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2505
+ RenderItem,
2506
+ {
2507
+ item,
2508
+ collapsed: collapsed != null ? collapsed : false,
2509
+ activeKey,
2510
+ go,
2511
+ color
2512
+ }
2513
+ )
2514
+ },
2515
+ item.key
2516
+ ))
2454
2517
  },
2455
- item.key
2456
- )) }),
2518
+ `${groupName}-items`
2519
+ ) : null }),
2457
2520
  !inserted && quick && firstGroupNameWithItems === groupName ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.default.Fragment, { children: (() => {
2458
2521
  inserted = true;
2459
2522
  return quick;
package/dist/Sidebar.mjs CHANGED
@@ -43,7 +43,24 @@ function groupItems(items) {
43
43
  }
44
44
  return Array.from(byGroup.entries());
45
45
  }
46
- function GroupHeader({ title }) {
46
+ function GroupHeader({ collapsed, onToggle, title }) {
47
+ if (onToggle) {
48
+ return /* @__PURE__ */ jsxs(
49
+ Button,
50
+ {
51
+ unstyled: true,
52
+ type: "button",
53
+ "aria-expanded": !collapsed,
54
+ onClick: onToggle,
55
+ className: "mb-3 flex w-full items-center gap-3 rounded-xl px-2 py-1 text-left transition-colors duration-200 hover:bg-[color-mix(in_oklab,var(--foreground)_5%,transparent)] focus:outline-none focus-visible:ring-1 focus-visible:ring-[var(--primary)]",
56
+ children: [
57
+ /* @__PURE__ */ jsx("span", { className: "text-[0.6875rem] font-semibold uppercase tracking-[0.18em] text-[var(--muted)]", children: title }),
58
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-[linear-gradient(90deg,color-mix(in_oklab,var(--border)_72%,transparent),transparent)]" }),
59
+ /* @__PURE__ */ jsx(ChevronDownIcon, { "aria-hidden": true, className: cx("h-3.5 w-3.5 shrink-0 text-[var(--muted)] transition-transform duration-300 ease-[cubic-bezier(0.22,1,0.36,1)]", collapsed ? "-rotate-90" : "rotate-0") })
60
+ ]
61
+ }
62
+ );
63
+ }
47
64
  return /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center gap-3 px-2 select-none", children: [
48
65
  /* @__PURE__ */ jsx("div", { className: "text-[0.6875rem] font-semibold uppercase tracking-[0.18em] text-[var(--muted)] text-left", children: title }),
49
66
  /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-[linear-gradient(90deg,color-mix(in_oklab,var(--border)_72%,transparent),transparent)]" })
@@ -254,6 +271,7 @@ function Sidebar({
254
271
  onBrandClick,
255
272
  showBrand = true,
256
273
  collapsedKey = "ga:sidebar-collapsed",
274
+ groupCollapsePersistKey,
257
275
  defaultCollapsed,
258
276
  onCollapsedChange,
259
277
  brandLogoSrc,
@@ -298,6 +316,8 @@ function Sidebar({
298
316
  const [navQuery, setNavQuery] = React.useState("");
299
317
  const [navDrag, setNavDrag] = React.useState(null);
300
318
  const [navDrop, setNavDrop] = React.useState(null);
319
+ const resolvedGroupCollapsePersistKey = groupCollapsePersistKey != null ? groupCollapsePersistKey : `${collapsedKey}:groups`;
320
+ const [collapsedGroups, setCollapsedGroups] = React.useState({});
301
321
  useLayoutEffect(() => {
302
322
  if (!(workspaces == null ? void 0 : workspaces.length)) return;
303
323
  if (activeWorkspaceId !== void 0) return;
@@ -328,6 +348,16 @@ function Sidebar({
328
348
  useEffect(() => {
329
349
  setMotionEnabled(true);
330
350
  }, []);
351
+ useLayoutEffect(() => {
352
+ if (!resolvedGroupCollapsePersistKey) return;
353
+ try {
354
+ const raw = localStorage.getItem(resolvedGroupCollapsePersistKey);
355
+ const parsed = raw ? JSON.parse(raw) : null;
356
+ setCollapsedGroups(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
357
+ } catch {
358
+ setCollapsedGroups({});
359
+ }
360
+ }, [resolvedGroupCollapsePersistKey]);
331
361
  useLayoutEffect(() => {
332
362
  if (!navEnabled) return;
333
363
  try {
@@ -354,9 +384,20 @@ function Sidebar({
354
384
  }
355
385
  onCollapsedChange == null ? void 0 : onCollapsedChange(collapsed);
356
386
  }, [collapsed, collapsedKey, motionEnabled, onCollapsedChange]);
387
+ useEffect(() => {
388
+ if (!motionEnabled) return;
389
+ if (!resolvedGroupCollapsePersistKey) return;
390
+ try {
391
+ localStorage.setItem(resolvedGroupCollapsePersistKey, JSON.stringify(collapsedGroups));
392
+ } catch {
393
+ }
394
+ }, [collapsedGroups, motionEnabled, resolvedGroupCollapsePersistKey]);
357
395
  const toggleCollapsed = () => {
358
396
  setCollapsed((c) => !c);
359
397
  };
398
+ const toggleGroupCollapsed = React.useCallback((groupName) => {
399
+ setCollapsedGroups((current) => ({ ...current, [groupName]: !current[groupName] }));
400
+ }, []);
360
401
  const sidebarWidth = collapsed ? 112 : 288;
361
402
  const sidebarWidthTransition = motionEnabled ? {
362
403
  type: "tween",
@@ -609,8 +650,10 @@ function Sidebar({
609
650
  SidebarInner,
610
651
  {
611
652
  groups,
653
+ collapsedGroups,
612
654
  collapsed,
613
655
  toggleCollapsed,
656
+ onToggleGroup: toggleGroupCollapsed,
614
657
  activeKey,
615
658
  go,
616
659
  navEditable: navEnabled,
@@ -704,9 +747,11 @@ function Sidebar({
704
747
  SidebarInner,
705
748
  {
706
749
  groups,
750
+ collapsedGroups,
707
751
  mobile: true,
708
752
  activeKey,
709
753
  toggleCollapsed,
754
+ onToggleGroup: toggleGroupCollapsed,
710
755
  go,
711
756
  navEditable: navEnabled,
712
757
  navCustomizeLabel: navCustomizeButtonLabel,
@@ -1766,8 +1811,10 @@ function WorkspaceSwitcher({
1766
1811
  }
1767
1812
  function SidebarInner({
1768
1813
  groups,
1814
+ collapsedGroups,
1769
1815
  collapsed,
1770
1816
  toggleCollapsed,
1817
+ onToggleGroup,
1771
1818
  mobile,
1772
1819
  activeKey,
1773
1820
  go,
@@ -1888,6 +1935,11 @@ function SidebarInner({
1888
1935
  const calmFadeInitial = { opacity: 0, y: 4, filter: "blur(6px)" };
1889
1936
  const calmFadeAnimate = { opacity: 1, y: 0, filter: "blur(0px)" };
1890
1937
  const calmFadeExit = { opacity: 0, y: 2, filter: "blur(6px)" };
1938
+ const groupCollapseTransition = { duration: 0.12, ease: "easeOut" };
1939
+ const groupHasActiveItem = React.useCallback((items) => items.some((item) => {
1940
+ var _a2;
1941
+ return item.key === activeKey || ((_a2 = item.children) != null ? _a2 : []).some((child) => child.key === activeKey);
1942
+ }), [activeKey]);
1891
1943
  const QuickIcon = ({ children }) => /* @__PURE__ */ jsx("span", { className: "grid h-9 w-9 place-items-center rounded-2xl text-[var(--muted)] transition-all duration-300 group-hover:scale-[1.04] group-hover:text-[var(--foreground)]", children: /* @__PURE__ */ jsx("span", { className: "text-[var(--foreground)]", children }) });
1892
1944
  const QuickActionsSection = () => {
1893
1945
  if (!hasQuickActions) return null;
@@ -2404,35 +2456,46 @@ function SidebarInner({
2404
2456
  return ((_a3 = i.children) == null ? void 0 : _a3.length) ? i.children.some((c) => c) : true;
2405
2457
  });
2406
2458
  if (visibles.length === 0) return null;
2459
+ const groupCollapsed = !groupHasActiveItem(visibles) && Boolean(collapsedGroups == null ? void 0 : collapsedGroups[groupName]);
2407
2460
  return /* @__PURE__ */ jsxs(
2408
2461
  motion.div,
2409
2462
  {
2410
- layout: true,
2411
2463
  initial: calmFadeInitial,
2412
2464
  animate: calmFadeAnimate,
2413
2465
  transition: { duration: 0.24, delay: groupIndex * 0.03, ease: calmFadeEase },
2414
2466
  children: [
2415
- !collapsed ? /* @__PURE__ */ jsx(GroupHeader, { title: groupName }) : null,
2416
- /* @__PURE__ */ jsx("div", { className: "space-y-2", children: visibles.map((item, itemIndex) => /* @__PURE__ */ jsx(
2467
+ !collapsed ? /* @__PURE__ */ jsx(GroupHeader, { collapsed: groupCollapsed, title: groupName, onToggle: () => onToggleGroup == null ? void 0 : onToggleGroup(groupName) }) : null,
2468
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: !groupCollapsed || collapsed ? /* @__PURE__ */ jsx(
2417
2469
  motion.div,
2418
2470
  {
2419
- layout: true,
2420
- initial: { opacity: 0, filter: "blur(6px)" },
2421
- animate: { opacity: 1, filter: "blur(0px)" },
2422
- transition: { duration: 0.2, delay: itemIndex * 0.02, ease: calmFadeEase },
2423
- children: /* @__PURE__ */ jsx(
2424
- RenderItem,
2471
+ initial: { opacity: 0 },
2472
+ animate: { opacity: 1 },
2473
+ exit: { opacity: 0 },
2474
+ transition: groupCollapseTransition,
2475
+ className: "space-y-2",
2476
+ style: { willChange: "opacity" },
2477
+ children: visibles.map((item, itemIndex) => /* @__PURE__ */ jsx(
2478
+ motion.div,
2425
2479
  {
2426
- item,
2427
- collapsed: collapsed != null ? collapsed : false,
2428
- activeKey,
2429
- go,
2430
- color
2431
- }
2432
- )
2480
+ initial: { opacity: 0 },
2481
+ animate: { opacity: 1 },
2482
+ transition: { duration: 0.1, ease: "easeOut" },
2483
+ children: /* @__PURE__ */ jsx(
2484
+ RenderItem,
2485
+ {
2486
+ item,
2487
+ collapsed: collapsed != null ? collapsed : false,
2488
+ activeKey,
2489
+ go,
2490
+ color
2491
+ }
2492
+ )
2493
+ },
2494
+ item.key
2495
+ ))
2433
2496
  },
2434
- item.key
2435
- )) }),
2497
+ `${groupName}-items`
2498
+ ) : null }),
2436
2499
  !inserted && quick && firstGroupNameWithItems === groupName ? /* @__PURE__ */ jsx(React.Fragment, { children: (() => {
2437
2500
  inserted = true;
2438
2501
  return quick;
@@ -215,14 +215,34 @@ function SupportChatWidget({
215
215
  const open = openProp != null ? openProp : openState;
216
216
  const setOpen = (next) => {
217
217
  if (openProp === void 0) setOpenState(next);
218
+ if (next) setUnseenReplyCount(0);
218
219
  onOpenChange == null ? void 0 : onOpenChange(next);
219
220
  };
220
221
  const [messagesState, setMessagesState] = import_react.default.useState(() => defaultMessages != null ? defaultMessages : []);
221
222
  const messages = messagesProp != null ? messagesProp : messagesState;
222
223
  const messagesRef = import_react.default.useRef(messages);
224
+ const knownMessageIdsRef = import_react.default.useRef(new Set(messages.map((message) => message.id)));
225
+ const panelRef = import_react.default.useRef(null);
226
+ const triggerRef = import_react.default.useRef(null);
227
+ const [unseenReplyCount, setUnseenReplyCount] = import_react.default.useState(0);
223
228
  import_react.default.useEffect(() => {
224
229
  messagesRef.current = messages;
225
230
  }, [messages]);
231
+ import_react.default.useEffect(() => {
232
+ const knownIds = knownMessageIdsRef.current;
233
+ const newReplies = messages.filter((message) => {
234
+ const isNew = !knownIds.has(message.id);
235
+ return isNew && (message.role === "bot" || message.role === "agent");
236
+ });
237
+ messages.forEach((message) => knownIds.add(message.id));
238
+ if (open) {
239
+ setUnseenReplyCount(0);
240
+ return;
241
+ }
242
+ if (newReplies.length) {
243
+ setUnseenReplyCount((current) => Math.min(99, current + newReplies.length));
244
+ }
245
+ }, [messages, open]);
226
246
  const setMessages = (next) => {
227
247
  if (typeof next === "function") {
228
248
  const fn = next;
@@ -299,6 +319,18 @@ function SupportChatWidget({
299
319
  if (!open) return;
300
320
  (_a2 = endRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "end" });
301
321
  }, [open, messages.length, sending]);
322
+ import_react.default.useEffect(() => {
323
+ if (!open || position === "inline") return;
324
+ const onPointerDown = (event) => {
325
+ var _a2, _b2;
326
+ const target = event.target;
327
+ if (!target) return;
328
+ if (((_a2 = panelRef.current) == null ? void 0 : _a2.contains(target)) || ((_b2 = triggerRef.current) == null ? void 0 : _b2.contains(target))) return;
329
+ setOpen(false);
330
+ };
331
+ document.addEventListener("pointerdown", onPointerDown);
332
+ return () => document.removeEventListener("pointerdown", onPointerDown);
333
+ }, [open, position]);
302
334
  const appendBotResult = (result) => {
303
335
  if (!result) return;
304
336
  if (typeof result === "string") {
@@ -404,19 +436,22 @@ function SupportChatWidget({
404
436
  await ((_d2 = config.onSave) == null ? void 0 : _d2.call(config, payload));
405
437
  downloadFile(fileName, content, mimeType);
406
438
  };
407
- const trigger = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_Tooltip.default, { content: labelTrigger, placement: position === "bottom-left" ? "right" : "left", offset: 10, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cx(positionClass, className), style: position === "inline" ? void 0 : { zIndex }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
439
+ const trigger = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_Tooltip.default, { content: labelTrigger, placement: position === "bottom-left" ? "right" : "left", offset: 10, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: triggerRef, className: cx(positionClass, className), style: position === "inline" ? void 0 : { zIndex }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
408
440
  "button",
409
441
  {
410
442
  type: "button",
411
443
  "aria-label": labelTrigger,
412
444
  onClick: () => setOpen(true),
413
445
  className: cx(
414
- "relative grid h-14 w-14 place-items-center rounded-2xl border border-[color-mix(in_oklab,var(--ring)_28%,var(--border))]",
415
- "bg-[var(--primary)] text-[var(--primary-foreground)] shadow-xl transition hover:brightness-95 active:scale-[0.98]"
446
+ "group relative grid size-14 place-items-center overflow-hidden rounded-2xl border border-[var(--border)]",
447
+ "bg-[color-mix(in_oklab,var(--card)_94%,transparent)] text-[var(--primary)] shadow-[0_20px_48px_rgba(6,19,22,0.13)] backdrop-blur-xl",
448
+ "transition duration-200 hover:-translate-y-0.5 hover:border-[color-mix(in_oklab,var(--primary)_38%,var(--border))] hover:bg-[var(--surface)] hover:text-[var(--foreground)] hover:shadow-[0_24px_58px_rgba(6,19,22,0.18)] active:scale-[0.98]",
449
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color-mix(in_oklab,var(--primary)_42%,transparent)] dark:shadow-[0_20px_48px_rgba(0,0,0,0.28)] dark:hover:shadow-[0_24px_58px_rgba(0,0,0,0.36)]"
416
450
  ),
417
451
  children: [
418
- mode === "live" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_iconos.HeadsetIcon, { "aria-hidden": true, className: "h-6 w-6" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_iconos.ChatCenteredDotsIcon, { "aria-hidden": true, className: "h-6 w-6" }),
419
- unreadCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute -right-1.5 -top-1.5 grid h-5 min-w-5 place-items-center rounded-full bg-[var(--danger)] px-1 text-[0.65rem] font-semibold text-white shadow ring-2 ring-[var(--card)]", children: unreadCount > 99 ? "99+" : unreadCount }) : null
452
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute inset-0 bg-[radial-gradient(circle_at_30%_20%,color-mix(in_oklab,var(--primary)_18%,transparent),transparent_38%)] opacity-80 transition group-hover:opacity-100" }),
453
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "relative grid size-9 place-items-center rounded-xl bg-[color-mix(in_oklab,var(--primary)_12%,transparent)] ring-1 ring-[color-mix(in_oklab,var(--primary)_18%,transparent)]", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_iconos.ChatCircleTextIcon, { "aria-hidden": true, className: "h-5 w-5" }) }),
454
+ Math.max(unreadCount, unseenReplyCount) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute -right-1.5 -top-1.5 grid h-5 min-w-5 animate-[fx-chat-badge_280ms_ease-out] place-items-center rounded-full bg-[var(--danger)] px-1 text-[0.65rem] font-semibold text-white shadow ring-2 ring-[var(--card)]", children: Math.max(unreadCount, unseenReplyCount) > 99 ? "99+" : Math.max(unreadCount, unseenReplyCount) }) : null
420
455
  ]
421
456
  }
422
457
  ) }) });
@@ -508,43 +543,53 @@ function SupportChatWidget({
508
543
  const prev = messages[index - 1];
509
544
  const showAvatar = !mine && !system && (prev == null ? void 0 : prev.role) !== message.role;
510
545
  const bubbleClass = system ? "mx-auto max-w-[92%] border-[color-mix(in_oklab,var(--warning)_28%,var(--border))] bg-[color-mix(in_oklab,var(--warning)_10%,transparent)] text-center text-[var(--foreground)]" : mine ? "border-[color-mix(in_oklab,var(--ring)_35%,var(--border))] bg-[color-mix(in_oklab,var(--primary)_14%,transparent)] text-[var(--foreground)]" : "border-[var(--border)] bg-[color-mix(in_oklab,var(--card)_94%,transparent)] text-[var(--foreground)]";
511
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("flex items-end gap-2", mine ? "justify-end" : system ? "justify-center" : "justify-start"), children: [
512
- !mine && !system ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cx("shrink-0", showAvatar ? "" : "opacity-0"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
513
- import_AvatarSquare.default,
514
- {
515
- size: 28,
516
- src: (_b2 = actor == null ? void 0 : actor.avatarUrl) != null ? _b2 : void 0,
517
- alt: (_c2 = actor == null ? void 0 : actor.name) != null ? _c2 : brandName,
518
- initials: actor == null ? void 0 : actor.initials,
519
- color: actor == null ? void 0 : actor.color,
520
- radiusClass: "rounded-lg",
521
- className: "ring-0"
522
- }
523
- ) }) : null,
524
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("max-w-[82%]", mine ? "items-end" : "items-start"), children: [
525
- !mine && !system && showAvatar ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mb-1 px-2 text-[0.6875rem] font-semibold text-[var(--muted)]", children: (_d2 = actor == null ? void 0 : actor.name) != null ? _d2 : brandName }) : null,
526
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("rounded-2xl border px-3.5 py-2.5 text-sm leading-6 shadow-sm", bubbleClass, message.state === "error" ? "border-[color-mix(in_oklab,var(--danger)_35%,var(--border))]" : ""), children: [
527
- message.state === "typing" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dots, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "whitespace-pre-wrap", children: message.content }),
528
- ((_e2 = message.suggestedReplies) == null ? void 0 : _e2.length) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-3 flex flex-wrap gap-2", children: message.suggestedReplies.slice(0, 4).map((reply) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
529
- "button",
546
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
547
+ "div",
548
+ {
549
+ className: cx(
550
+ "flex animate-[fx-chat-message_260ms_cubic-bezier(.2,.8,.2,1)_both] items-end gap-2",
551
+ mine ? "justify-end [--fx-chat-x:10px]" : system ? "justify-center [--fx-chat-x:0px]" : "justify-start [--fx-chat-x:-10px]"
552
+ ),
553
+ children: [
554
+ !mine && !system ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cx("shrink-0", showAvatar ? "" : "opacity-0"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
555
+ import_AvatarSquare.default,
530
556
  {
531
- type: "button",
532
- onClick: () => {
533
- onQuickReply == null ? void 0 : onQuickReply(reply);
534
- void send(reply);
535
- },
536
- className: "rounded-full border border-[var(--border)] bg-[var(--card)] px-3 py-1.5 text-xs font-semibold text-[var(--foreground)] shadow-sm transition hover:bg-[color-mix(in_oklab,var(--surface)_72%,transparent)]",
537
- children: reply
538
- },
539
- `${message.id}:${reply}`
540
- )) }) : null,
541
- ((_f2 = message.serviceSuggestions) == null ? void 0 : _f2.length) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-3 space-y-2", children: message.serviceSuggestions.slice(0, 3).map(renderService) }) : null
542
- ] }),
543
- message.createdAt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cx("mt-1 px-2 text-[0.6875rem] text-[var(--muted)]", mine ? "text-right" : "text-left"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TimeAgo.default, { iso: message.createdAt }) }) : null
544
- ] })
545
- ] }, message.id);
557
+ size: 28,
558
+ src: (_b2 = actor == null ? void 0 : actor.avatarUrl) != null ? _b2 : void 0,
559
+ alt: (_c2 = actor == null ? void 0 : actor.name) != null ? _c2 : brandName,
560
+ initials: actor == null ? void 0 : actor.initials,
561
+ color: actor == null ? void 0 : actor.color,
562
+ radiusClass: "rounded-lg",
563
+ className: "ring-0"
564
+ }
565
+ ) }) : null,
566
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("max-w-[82%]", mine ? "items-end" : "items-start"), children: [
567
+ !mine && !system && showAvatar ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mb-1 px-2 text-[0.6875rem] font-semibold text-[var(--muted)]", children: (_d2 = actor == null ? void 0 : actor.name) != null ? _d2 : brandName }) : null,
568
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("rounded-2xl border px-3.5 py-2.5 text-sm leading-6 shadow-sm transition-[background,border-color,box-shadow,transform] duration-200", bubbleClass, message.state === "error" ? "border-[color-mix(in_oklab,var(--danger)_35%,var(--border))]" : ""), children: [
569
+ message.state === "typing" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dots, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "whitespace-pre-wrap", children: message.content }),
570
+ ((_e2 = message.suggestedReplies) == null ? void 0 : _e2.length) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-3 flex flex-wrap gap-2", children: message.suggestedReplies.slice(0, 4).map((reply) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
571
+ "button",
572
+ {
573
+ type: "button",
574
+ onClick: () => {
575
+ onQuickReply == null ? void 0 : onQuickReply(reply);
576
+ void send(reply);
577
+ },
578
+ className: "rounded-full border border-[var(--border)] bg-[var(--card)] px-3 py-1.5 text-xs font-semibold text-[var(--foreground)] shadow-sm transition hover:bg-[color-mix(in_oklab,var(--surface)_72%,transparent)]",
579
+ children: reply
580
+ },
581
+ `${message.id}:${reply}`
582
+ )) }) : null,
583
+ ((_f2 = message.serviceSuggestions) == null ? void 0 : _f2.length) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-3 space-y-2", children: message.serviceSuggestions.slice(0, 3).map(renderService) }) : null
584
+ ] }),
585
+ message.createdAt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cx("mt-1 px-2 text-[0.6875rem] text-[var(--muted)]", mine ? "text-right" : "text-left"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TimeAgo.default, { iso: message.createdAt }) }) : null
586
+ ] })
587
+ ]
588
+ },
589
+ message.id
590
+ );
546
591
  }),
547
- sending ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-end gap-2", children: [
592
+ sending ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex animate-[fx-chat-message_260ms_cubic-bezier(.2,.8,.2,1)_both] items-end gap-2 [--fx-chat-x:-10px]", children: [
548
593
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
549
594
  import_AvatarSquare.default,
550
595
  {
@@ -564,16 +609,17 @@ function SupportChatWidget({
564
609
  const panel = open ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
565
610
  "div",
566
611
  {
612
+ ref: panelRef,
567
613
  className: cx(
568
614
  panelPositionClass,
569
- "flex h-[min(680px,calc(100vh-7rem))] w-[min(400px,calc(100vw-2rem))] flex-col overflow-hidden rounded-2xl border border-[var(--border)] bg-[var(--card)] text-[var(--foreground)] shadow-2xl",
615
+ "flex h-[min(680px,calc(100vh-7rem))] w-[min(400px,calc(100vw-2rem))] animate-[fx-chat-panel_180ms_cubic-bezier(.2,.8,.2,1)_both] flex-col overflow-hidden rounded-2xl border border-[var(--border)] bg-[color-mix(in_oklab,var(--card)_96%,transparent)] text-[var(--foreground)] shadow-[0_28px_80px_rgba(6,19,22,0.18)] backdrop-blur-xl dark:shadow-[0_28px_80px_rgba(0,0,0,0.38)]",
570
616
  panelClassName
571
617
  ),
572
618
  style: position === "inline" ? void 0 : { zIndex },
573
619
  role: "dialog",
574
620
  "aria-label": labelTitle,
575
621
  children: [
576
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-b border-[var(--border)] bg-[color-mix(in_oklab,var(--card)_96%,transparent)] px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between gap-3", children: [
622
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-b border-[var(--border)] bg-[linear-gradient(135deg,color-mix(in_oklab,var(--card)_98%,transparent),color-mix(in_oklab,var(--primary)_8%,var(--surface)))] px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between gap-3", children: [
577
623
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex min-w-0 items-center gap-3", children: [
578
624
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
579
625
  import_AvatarSquare.default,