@elizaos/ui 2.0.3-beta.4 → 2.0.3-beta.5

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 (82) hide show
  1. package/app-navigate-view.d.ts.map +1 -1
  2. package/app-navigate-view.js +1 -1
  3. package/cloud/api-keys/ApiKeysView.d.ts +6 -3
  4. package/cloud/api-keys/ApiKeysView.d.ts.map +1 -1
  5. package/cloud/api-keys/ApiKeysView.js +21 -29
  6. package/cloud/api-keys/copy-api-key.d.ts +1 -8
  7. package/cloud/api-keys/copy-api-key.d.ts.map +1 -1
  8. package/cloud/api-keys/copy-api-key.js +1 -10
  9. package/cloud/api-keys/index.d.ts +1 -1
  10. package/cloud/api-keys/index.d.ts.map +1 -1
  11. package/cloud/api-keys/index.js +1 -1
  12. package/cloud/shell/CloudRouterShell.d.ts +12 -0
  13. package/cloud/shell/CloudRouterShell.d.ts.map +1 -1
  14. package/cloud/shell/CloudRouterShell.js +38 -2
  15. package/cloud-ui/components/data-list/api-keys-table.d.ts +1 -2
  16. package/cloud-ui/components/data-list/api-keys-table.d.ts.map +1 -1
  17. package/cloud-ui/components/data-list/api-keys-table.js +3 -9
  18. package/cloud-ui/components/docs/api-route-explorer-client.d.ts.map +1 -1
  19. package/cloud-ui/components/docs/api-route-explorer-client.js +2 -1
  20. package/cloud-ui/components/layout/dashboard-route-page.d.ts.map +1 -1
  21. package/cloud-ui/components/layout/dashboard-route-page.js +3 -1
  22. package/components/config-ui/config-field.js +1 -1
  23. package/components/pages/Springboard.d.ts.map +1 -1
  24. package/components/pages/Springboard.js +34 -45
  25. package/components/pages/SpringboardSurface.d.ts.map +1 -1
  26. package/components/pages/SpringboardSurface.js +116 -6
  27. package/components/shell/ContinuousChatOverlay.d.ts.map +1 -1
  28. package/components/shell/ContinuousChatOverlay.js +207 -146
  29. package/components/shell/HomeSpringboardSurface.d.ts.map +1 -1
  30. package/components/shell/HomeSpringboardSurface.js +31 -76
  31. package/components/shell/use-pull-gesture.d.ts +6 -0
  32. package/components/shell/use-pull-gesture.d.ts.map +1 -1
  33. package/components/shell/use-pull-gesture.js +66 -27
  34. package/components/shell/useShellController.d.ts.map +1 -1
  35. package/components/shell/useShellController.js +13 -3
  36. package/components/views/ViewTileImage.d.ts +8 -8
  37. package/components/views/ViewTileImage.d.ts.map +1 -1
  38. package/components/views/ViewTileImage.js +38 -9
  39. package/hooks/useHorizontalPager.d.ts +33 -0
  40. package/hooks/useHorizontalPager.d.ts.map +1 -0
  41. package/hooks/useHorizontalPager.js +226 -0
  42. package/hooks/useLayoutShiftMonitor.d.ts +2 -0
  43. package/hooks/useLayoutShiftMonitor.d.ts.map +1 -1
  44. package/hooks/useLayoutShiftMonitor.js +23 -0
  45. package/hooks/view-catalog.d.ts +3 -4
  46. package/hooks/view-catalog.d.ts.map +1 -1
  47. package/hooks/view-catalog.js +4 -6
  48. package/package.json +10 -10
  49. package/state/startup-telemetry.d.ts +6 -0
  50. package/state/startup-telemetry.d.ts.map +1 -1
  51. package/state/startup-telemetry.js +23 -2
  52. package/styles/base.css +6 -6
  53. package/styles/brand-gold.css +6 -5
  54. package/testing/layout-stability.d.ts +11 -3
  55. package/testing/layout-stability.d.ts.map +1 -1
  56. package/testing/layout-stability.js +29 -4
  57. package/testing/run-animation-frames-immediately.d.ts +2 -0
  58. package/testing/run-animation-frames-immediately.d.ts.map +1 -0
  59. package/testing/run-animation-frames-immediately.js +8 -0
  60. package/themes/presets.js +14 -14
  61. package/utils/cloud-agent-base.d.ts.map +1 -1
  62. package/utils/cloud-agent-base.js +6 -0
  63. package/widgets/registry.d.ts.map +1 -1
  64. package/widgets/registry.js +7 -0
  65. package/components/pages/automation-conversations.d.ts +0 -16
  66. package/components/pages/automation-conversations.d.ts.map +0 -1
  67. package/components/pages/automation-conversations.js +0 -204
  68. package/components/pages/automations-missing-creds.d.ts +0 -25
  69. package/components/pages/automations-missing-creds.d.ts.map +0 -1
  70. package/components/pages/automations-missing-creds.js +0 -39
  71. package/components/settings/desktop-workspace-audit-config.d.ts +0 -3
  72. package/components/settings/desktop-workspace-audit-config.d.ts.map +0 -1
  73. package/components/settings/desktop-workspace-audit-config.js +0 -171
  74. package/components/shell/first-run-theme.d.ts +0 -6
  75. package/components/shell/first-run-theme.d.ts.map +0 -1
  76. package/components/shell/first-run-theme.js +0 -31
  77. package/genui/use-json-render-message.d.ts +0 -20
  78. package/genui/use-json-render-message.d.ts.map +0 -1
  79. package/genui/use-json-render-message.js +0 -38
  80. package/state/first-run-restart.d.ts +0 -8
  81. package/state/first-run-restart.d.ts.map +0 -1
  82. package/state/first-run-restart.js +0 -8
@@ -1 +1 @@
1
- {"version":3,"file":"HomeSpringboardSurface.d.ts","sourceRoot":"","sources":["../../../../../../src/components/shell/HomeSpringboardSurface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAarE,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,WAAW,EAAE,KAAK,CAAC,YAAY,CAAC;QAAE,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAC;IACzE,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,WAAW,EACX,WAAoB,EACpB,SAAS,GACV,EAAE,2BAA2B,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAqMjD"}
1
+ {"version":3,"file":"HomeSpringboardSurface.d.ts","sourceRoot":"","sources":["../../../../../../src/components/shell/HomeSpringboardSurface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAU/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,WAAW,EAAE,KAAK,CAAC,YAAY,CAAC;QAAE,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAC;IACzE,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,WAAW,EACX,WAAoB,EACpB,SAAS,GACV,EAAE,2BAA2B,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAyIjD"}
@@ -1,11 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
+ import { useHorizontalPager } from "../../hooks/useHorizontalPager.js";
3
4
  import { cn } from "../../lib/utils.js";
4
5
  import { goHome, goSpringboard, setShellSurfacePage, setSpringboardPage, useShellSurface, } from "../../state/shell-surface-store.js";
5
- /** Horizontal travel (px) needed to commit a rail flick (home ↔ springboard). */
6
- const RAIL_FLICK_THRESHOLD = 72;
7
- /** Horizontal travel must beat vertical by this ratio so a scroll never flips. */
8
- const RAIL_FLICK_ANGLE_RATIO = 1.25;
9
6
  /**
10
7
  * The home ↔ springboard rail. It owns NO local navigation state — `page` is
11
8
  * read from (and every transition is dispatched to) the single shell-surface
@@ -23,77 +20,35 @@ export function HomeSpringboardSurface({ home, springboard, initialPage = "home"
23
20
  React.useEffect(() => {
24
21
  setShellSurfacePage(initialPage);
25
22
  }, [initialPage]);
26
- const homeFlick = React.useRef({
27
- startX: 0,
28
- startY: 0,
29
- tracking: false,
30
- });
31
- const springboardFlick = React.useRef({
32
- startX: 0,
33
- startY: 0,
34
- tracking: false,
35
- });
36
23
  // A committed flick must swallow the click that the browser synthesizes from
37
24
  // the same press, so the flick doesn't also tap-launch the tile underneath.
38
- const suppressHomeClickRef = React.useRef(false);
39
- const suppressSpringboardClickRef = React.useRef(false);
40
- // One flick detector, parameterized by the direction that commits: the home
41
- // half commits a LEFT flick (open springboard); the springboard half commits a
42
- // RIGHT flick (return home) the back gesture the old surface lacked, and the
43
- // one escape that works even while the springboard is in edit mode.
44
- const makeFlickHandlers = (flick, suppress, direction, onCommit) => {
45
- const committed = (dx, dy) => Math.abs(dx) > Math.abs(dy) * RAIL_FLICK_ANGLE_RATIO &&
46
- (direction === "left"
47
- ? dx < -RAIL_FLICK_THRESHOLD
48
- : dx > RAIL_FLICK_THRESHOLD);
49
- return {
50
- onPointerDown: (event) => {
51
- if (!event.isPrimary)
52
- return;
53
- flick.current = {
54
- startX: event.clientX,
55
- startY: event.clientY,
56
- tracking: true,
57
- };
58
- },
59
- onPointerUp: (event) => {
60
- const state = flick.current;
61
- if (!state.tracking)
62
- return;
63
- state.tracking = false;
64
- if (!committed(event.clientX - state.startX, event.clientY - state.startY)) {
65
- return;
66
- }
67
- suppress.current = true;
68
- onCommit();
69
- window.setTimeout(() => {
70
- suppress.current = false;
71
- }, 0);
72
- },
73
- onPointerCancel: () => {
74
- flick.current.tracking = false;
75
- },
76
- onClickCapture: (event) => {
77
- if (!suppress.current)
78
- return;
79
- suppress.current = false;
80
- event.preventDefault();
81
- event.stopPropagation();
82
- },
83
- };
84
- };
85
- const homeHandlers = makeFlickHandlers(homeFlick, suppressHomeClickRef, "left", goSpringboard);
86
- const springboardHandlers = makeFlickHandlers(springboardFlick, suppressSpringboardClickRef, "right", () => {
87
- // A right-flick returns home only from the FIRST springboard page (iOS
88
- // back); on deeper pages the inner pager steps back one page instead, so
89
- // the two gestures never both fire. While editing it is always the escape
90
- // hatch out of jiggle mode (the inner pager is disabled then).
91
- if (springboardPage === 0 || springboardEditing)
92
- goHome();
25
+ const suppressClickRef = React.useRef(false);
26
+ const pager = useHorizontalPager({
27
+ page: page === "springboard" ? 1 : 0,
28
+ pageCount: 2,
29
+ // Let the inner Springboard own app-page swipes after page 1. On the first
30
+ // app page, or while editing, the parent owns the right-swipe home gesture.
31
+ enabled: page === "home" || springboardPage === 0 || springboardEditing,
32
+ onPageChange: (nextPage) => {
33
+ suppressClickRef.current = true;
34
+ window.setTimeout(() => {
35
+ suppressClickRef.current = false;
36
+ }, 0);
37
+ if (nextPage === 0) {
38
+ goHome();
39
+ }
40
+ else {
41
+ goSpringboard();
42
+ }
43
+ },
93
44
  });
94
- const railStyle = React.useMemo(() => ({
95
- transform: page === "springboard" ? "translate3d(-50%,0,0)" : "translate3d(0,0,0)",
96
- }), [page]);
45
+ const suppressCommittedSwipeClick = React.useCallback((event) => {
46
+ if (!suppressClickRef.current)
47
+ return;
48
+ suppressClickRef.current = false;
49
+ event.preventDefault();
50
+ event.stopPropagation();
51
+ }, []);
97
52
  // ONE indicator for the whole launcher: a home dot followed by one dot per
98
53
  // springboard page. Active index is derived from the store, so the doubled
99
54
  // (stacked) dot strips are gone — there is exactly one. Tapping a dot is a
@@ -108,21 +63,21 @@ export function HomeSpringboardSurface({ home, springboard, initialPage = "home"
108
63
  goSpringboard();
109
64
  setSpringboardPage(index - 1);
110
65
  }, []);
111
- return (_jsxs("section", { "data-testid": "home-springboard-surface", "data-page": page,
66
+ return (_jsxs("section", { ref: pager.viewportRef, "data-testid": "home-springboard-surface", "data-page": page,
112
67
  // `select-none`: this is a swipeable launcher (home ↔ springboard), so a
113
68
  // horizontal drag must pan the rail, never text-select the tile labels /
114
69
  // widget text underneath. (Vertical scroll of the home widget list is
115
70
  // untouched.)
116
- className: cn("absolute inset-0 z-[1] select-none overflow-hidden", className), children: [_jsxs("div", { "data-testid": "home-springboard-rail", className: cn("absolute inset-0 flex w-[200%]", "transition-transform duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none"), style: railStyle, children: [_jsx("div", { "data-testid": "home-springboard-home-page", "aria-hidden": page !== "home",
71
+ className: cn("absolute inset-0 z-[1] select-none overflow-hidden", className), children: [_jsxs("div", { ref: pager.railRef, "data-testid": "home-springboard-rail", className: "absolute inset-0 flex w-[200%] motion-reduce:transition-none", children: [_jsx("div", { "data-testid": "home-springboard-home-page", "aria-hidden": page !== "home",
117
72
  // `touch-pan-y`: reserve vertical panning for the browser (the home
118
73
  // widget list scrolls) but claim every horizontal gesture for the
119
74
  // rail flick. Without it a touch device hands a horizontal drag to the
120
75
  // browser's own scroll/back gesture, which fires `pointercancel`
121
76
  // instead of `pointerup` — the flick silently never commits.
122
- className: "relative h-full w-1/2 shrink-0 touch-pan-y", onPointerDown: homeHandlers.onPointerDown, onPointerUp: homeHandlers.onPointerUp, onPointerCancel: homeHandlers.onPointerCancel, onClickCapture: homeHandlers.onClickCapture, children: home }), _jsx("div", { "data-testid": "home-springboard-springboard-page", "aria-hidden": page !== "springboard",
77
+ className: "relative h-full w-1/2 shrink-0 touch-pan-y", onPointerDown: pager.handlers.onPointerDown, onPointerMove: pager.handlers.onPointerMove, onPointerUp: pager.handlers.onPointerUp, onPointerCancel: pager.handlers.onPointerCancel, onLostPointerCapture: pager.handlers.onLostPointerCapture, onClickCapture: suppressCommittedSwipeClick, children: home }), _jsx("div", { "data-testid": "home-springboard-springboard-page", "aria-hidden": page !== "springboard",
123
78
  // Same as the home half: vertical scroll (the tile grid) stays with
124
79
  // the browser, horizontal flicks (right → back home) are ours.
125
- className: "relative h-full w-1/2 shrink-0 touch-pan-y", onPointerDown: springboardHandlers.onPointerDown, onPointerUp: springboardHandlers.onPointerUp, onPointerCancel: springboardHandlers.onPointerCancel, onClickCapture: springboardHandlers.onClickCapture, children: React.cloneElement(springboard, {
80
+ className: "relative h-full w-1/2 shrink-0 touch-pan-y", onPointerDown: pager.handlers.onPointerDown, onPointerMove: pager.handlers.onPointerMove, onPointerUp: pager.handlers.onPointerUp, onPointerCancel: pager.handlers.onPointerCancel, onLostPointerCapture: pager.handlers.onLostPointerCapture, onClickCapture: suppressCommittedSwipeClick, children: React.cloneElement(springboard, {
126
81
  onNavigateHomeFromEdge: goHome,
127
82
  }) })] }), _jsx("div", { "data-testid": "home-springboard-indicator",
128
83
  // Sit ABOVE the floating chat composer (its clearance), with a gap, so
@@ -23,6 +23,8 @@ export interface PullGestureOptions {
23
23
  onPullDown?: () => void;
24
24
  /** Live vertical drag offset while pressed, in px. Positive = dragging up. */
25
25
  onDrag?: (offset: number) => void;
26
+ /** Reset/cancel live vertical drag visuals without marking a new drag active. */
27
+ onDragReset?: () => void;
26
28
  /** Released after a horizontal swipe LEFT past threshold. */
27
29
  onSwipeLeft?: () => void;
28
30
  /** Released after a horizontal swipe RIGHT past threshold. */
@@ -37,6 +39,10 @@ export interface PullGestureOptions {
37
39
  * (the consumer keeps the live offset) instead of snapping back.
38
40
  */
39
41
  onSettleFree?: (direction: "up" | "down") => void;
42
+ /** Gesture was interrupted by pointercancel/lost capture. */
43
+ onCancel?: () => void;
44
+ /** Enable horizontal swipe recognition. Defaults to true when swipe handlers exist. */
45
+ swipeEnabled?: boolean;
40
46
  /** Minimum vertical travel (px) to count as a pull. Default 56. */
41
47
  distanceThreshold?: number;
42
48
  /** Minimum vertical speed (px/ms) to count as a flick. Default 0.5. */
@@ -1 +1 @@
1
- {"version":3,"file":"use-pull-gesture.d.ts","sourceRoot":"","sources":["../../../../../../src/components/shell/use-pull-gesture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,kFAAkF;IAClF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IAClD,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAOD,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;IACnD,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;IACnD,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;IACrD;;sFAEkF;IAClF,oBAAoB,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;CAC3D;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,MAAM,EACzB,iBAAiB,EAAE,MAAM,GACxB,IAAI,GAAG,MAAM,GAAG,IAAI,CAMtB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,kBAAkB,EAAE,MAAM,EAC1B,kBAAkB,EAAE,MAAM,GACzB,MAAM,GAAG,OAAO,GAAG,IAAI,CAQzB;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,kBAAkB,GAC1B,kBAAkB,CAiNpB"}
1
+ {"version":3,"file":"use-pull-gesture.d.ts","sourceRoot":"","sources":["../../../../../../src/components/shell/use-pull-gesture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,kFAAkF;IAClF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IAClD,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,uFAAuF;IACvF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAOD,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;IACnD,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;IACnD,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;IACrD;;sFAEkF;IAClF,oBAAoB,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;CAC3D;AAID,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,MAAM,EACzB,iBAAiB,EAAE,MAAM,GACxB,IAAI,GAAG,MAAM,GAAG,IAAI,CAMtB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,kBAAkB,EAAE,MAAM,EAC1B,kBAAkB,EAAE,MAAM,GACzB,MAAM,GAAG,OAAO,GAAG,IAAI,CAQzB;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,kBAAkB,GAC1B,kBAAkB,CAoQpB"}
@@ -28,8 +28,9 @@ export function resolveSwipe(deltaLeft, velocityLeft, deltaUp, distanceThreshold
28
28
  return deltaLeft > 0 ? "left" : "right";
29
29
  }
30
30
  export function usePullGesture(options) {
31
- const { onPullUp, onPullDown, onDrag, onSwipeLeft, onSwipeRight, onDragX, onTap, onSettleFree, distanceThreshold = 56, velocityThreshold = 0.5, distanceThresholdX = 64, velocityThresholdX = 0.4, } = options;
32
- const hasSwipe = Boolean(onSwipeLeft || onSwipeRight || onDragX);
31
+ const { onPullUp, onPullDown, onDrag, onDragReset, onSwipeLeft, onSwipeRight, onDragX, onTap, onSettleFree, onCancel, swipeEnabled = true, distanceThreshold = 56, velocityThreshold = 0.5, distanceThresholdX = 64, velocityThresholdX = 0.4, } = options;
32
+ const hasSwipe = swipeEnabled && Boolean(onSwipeLeft || onSwipeRight || onDragX);
33
+ const hasVerticalPull = Boolean(onDrag || onPullUp || onPullDown || onSettleFree);
33
34
  const start = React.useRef(null);
34
35
  // Which axis the gesture committed to, once it crossed AXIS_COMMIT_SLOP.
35
36
  const axis = React.useRef(null);
@@ -70,17 +71,27 @@ export function usePullGesture(options) {
70
71
  dragRaf.current = 0;
71
72
  pendingDrag.current = null;
72
73
  }, []);
74
+ const flushPendingDrag = React.useCallback(() => {
75
+ if (dragRaf.current !== 0 && typeof cancelAnimationFrame === "function") {
76
+ cancelAnimationFrame(dragRaf.current);
77
+ }
78
+ flushDrag();
79
+ }, [flushDrag]);
73
80
  const onPointerDown = React.useCallback((event) => {
81
+ if (start.current && start.current.pointerId !== event.pointerId)
82
+ return;
74
83
  start.current = {
75
84
  x: event.clientX,
76
85
  y: event.clientY,
77
86
  t: performance.now(),
87
+ pointerId: event.pointerId,
78
88
  };
79
89
  axis.current = null;
80
- // When horizontal swipes are possible we DEFER capture until the gesture
81
- // commits to an axis, so a vertical scroll inside the panel still scrolls
82
- // natively. Pure-vertical consumers (the drag handle) capture immediately.
83
- if (!hasSwipe) {
90
+ // Pure horizontal swipe surfaces defer capture until axis commit so native
91
+ // vertical scrolling still works. A vertical pull handle captures
92
+ // immediately even when it also supports horizontal swipes; otherwise a
93
+ // mouse/finger can leave the small handle before the first committed move.
94
+ if (!hasSwipe || hasVerticalPull) {
84
95
  try {
85
96
  event.currentTarget.setPointerCapture(event.pointerId);
86
97
  }
@@ -88,10 +99,10 @@ export function usePullGesture(options) {
88
99
  // Detached node mid-gesture — capture is best-effort.
89
100
  }
90
101
  }
91
- }, [hasSwipe]);
102
+ }, [hasSwipe, hasVerticalPull]);
92
103
  const onPointerMove = React.useCallback((event) => {
93
104
  const s = start.current;
94
- if (!s)
105
+ if (!s || s.pointerId !== event.pointerId)
95
106
  return;
96
107
  const dy = s.y - event.clientY; // up positive
97
108
  const dx = s.x - event.clientX; // left positive
@@ -99,9 +110,9 @@ export function usePullGesture(options) {
99
110
  const ax = Math.abs(dx);
100
111
  const ay = Math.abs(dy);
101
112
  if (Math.max(ax, ay) >= AXIS_COMMIT_SLOP) {
102
- axis.current = hasSwipe && ax > ay ? "x" : "y";
113
+ axis.current = ax > ay ? "x" : "y";
103
114
  // Take over the pointer now that intent is clear (deferred-capture path).
104
- if (hasSwipe) {
115
+ if (hasSwipe && !hasVerticalPull) {
105
116
  try {
106
117
  event.currentTarget.setPointerCapture(event.pointerId);
107
118
  }
@@ -113,24 +124,41 @@ export function usePullGesture(options) {
113
124
  // the visual. Drop any pending pre-commit frame first so it can't
114
125
  // override the reset on the next tick.
115
126
  cancelDrag();
116
- if (axis.current === "x")
117
- onDrag?.(0);
118
- else
127
+ if (axis.current === "x") {
128
+ onDragReset?.();
129
+ if (!hasSwipe) {
130
+ try {
131
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
132
+ }
133
+ catch {
134
+ // best-effort
135
+ }
136
+ }
137
+ }
138
+ else {
119
139
  onDragX?.(0);
140
+ }
120
141
  }
121
142
  }
122
- if (axis.current === "x")
123
- scheduleDrag("x", dx);
124
- else if (axis.current === "y")
143
+ if (axis.current === "x") {
144
+ if (hasSwipe)
145
+ scheduleDrag("x", dx);
146
+ }
147
+ else if (axis.current === "y") {
125
148
  scheduleDrag("y", dy);
126
- else
149
+ }
150
+ else {
127
151
  scheduleDrag("y", dy); // pre-commit: drive the vertical sheet
128
- }, [hasSwipe, onDrag, onDragX, scheduleDrag, cancelDrag]);
152
+ }
153
+ }, [hasSwipe, hasVerticalPull, onDragReset, onDragX, scheduleDrag, cancelDrag]);
129
154
  const finish = React.useCallback((event) => {
130
- // Drop any pending coalesced drag frame so a stale value can't fire after
131
- // the settle below and fight the snap.
132
- cancelDrag();
133
155
  const s = start.current;
156
+ if (!s || s.pointerId !== event.pointerId)
157
+ return;
158
+ // Apply the latest coalesced drag before deciding the release. Consumers
159
+ // read that live value to choose the nearest detent, and the canceled rAF
160
+ // cannot replay stale motion after the settle below.
161
+ flushPendingDrag();
134
162
  const committedAxis = axis.current;
135
163
  start.current = null;
136
164
  axis.current = null;
@@ -147,7 +175,7 @@ export function usePullGesture(options) {
147
175
  const isFlickX = Math.abs(velocityLeft) >= velocityThresholdX;
148
176
  // A near-stationary release (both axes) is a tap, not a drag/swipe.
149
177
  if (movedX < TAP_SLOP && movedY < TAP_SLOP && !isFlickY && !isFlickX) {
150
- onDrag?.(0);
178
+ onDragReset?.();
151
179
  onDragX?.(0);
152
180
  onTap?.();
153
181
  return;
@@ -181,11 +209,11 @@ export function usePullGesture(options) {
181
209
  onPullDown?.();
182
210
  }
183
211
  else {
184
- onDrag?.(0); // sub-threshold, no free-settle consumer → snap back
212
+ onDragReset?.(); // sub-threshold, no free-settle consumer → snap back
185
213
  }
186
214
  }, [
187
- cancelDrag,
188
- onDrag,
215
+ flushPendingDrag,
216
+ onDragReset,
189
217
  onDragX,
190
218
  onPullUp,
191
219
  onPullDown,
@@ -198,13 +226,24 @@ export function usePullGesture(options) {
198
226
  distanceThresholdX,
199
227
  velocityThresholdX,
200
228
  ]);
229
+ const cancel = React.useCallback((event) => {
230
+ const s = start.current;
231
+ if (!s || s.pointerId !== event.pointerId)
232
+ return;
233
+ cancelDrag();
234
+ start.current = null;
235
+ axis.current = null;
236
+ onDragReset?.();
237
+ onDragX?.(0);
238
+ onCancel?.();
239
+ }, [cancelDrag, onDragReset, onDragX, onCancel]);
201
240
  // Cancel any in-flight coalesced frame if the consumer unmounts mid-gesture.
202
241
  React.useEffect(() => cancelDrag, [cancelDrag]);
203
242
  return {
204
243
  onPointerDown,
205
244
  onPointerMove,
206
245
  onPointerUp: finish,
207
- onPointerCancel: finish,
208
- onLostPointerCapture: finish,
246
+ onPointerCancel: cancel,
247
+ onLostPointerCapture: cancel,
209
248
  };
210
249
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useShellController.d.ts","sourceRoot":"","sources":["../../../../../../src/components/shell/useShellController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useShellController.d.ts","sourceRoot":"","sources":["../../../../../../src/components/shell/useShellController.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { VOICE_CONTROL_EVENT, } from "../../events/index.js";
3
- import { useChatTurnStatus, useConversationMessages } from "../../state/index.js";
3
+ import { useChatComposer, useChatTurnStatus, useConversationMessages, } from "../../state/index.js";
4
4
  import { useAppSelectorShallow } from "../../state/app-store.js";
5
5
  import { loadContinuousChatMode, loadVadAutoStop, saveContinuousChatMode, } from "../../state/persistence.js";
6
6
  import { deriveAgentReady } from "../../state/types.js";
@@ -70,7 +70,6 @@ function sameStringList(a, b) {
70
70
  // below but not selected here is a compile error, so this stays value-equivalent.
71
71
  const selectShellController = (s) => ({
72
72
  tab: s.tab,
73
- chatSending: s.chatSending,
74
73
  chatFirstTokenReceived: s.chatFirstTokenReceived,
75
74
  sendChatText: s.sendChatText,
76
75
  agentStatus: s.agentStatus,
@@ -84,10 +83,13 @@ const selectShellController = (s) => ({
84
83
  handleChatStop: s.handleChatStop,
85
84
  });
86
85
  export function useShellController() {
87
- const { tab, chatSending, chatFirstTokenReceived, sendChatText, agentStatus, uiLanguage, elizaCloudVoiceProxyAvailable, handleNewConversation, handleSelectConversation, activeConversationId, conversations, setTab, handleChatStop, } = useAppSelectorShallow(selectShellController);
86
+ const { tab, chatFirstTokenReceived, sendChatText, agentStatus, uiLanguage, elizaCloudVoiceProxyAvailable, handleNewConversation, handleSelectConversation, activeConversationId, conversations, setTab, handleChatStop, } = useAppSelectorShallow(selectShellController);
88
87
  // Read per-token streaming messages from the isolated context so token updates
89
88
  // don't depend on the giant AppContext value identity.
90
89
  const { conversationMessages } = useConversationMessages();
90
+ // chatSending lives in ChatComposerContext; the AppContext copy is intentionally
91
+ // stale so send/typing churn does not fan out through the whole app.
92
+ const { chatSending } = useChatComposer();
91
93
  // Live server-reported phase of the in-flight turn (from the chat-send SSE),
92
94
  // read from its dedicated context so status events re-render only chat surfaces.
93
95
  const { serverTurnStatus } = useChatTurnStatus();
@@ -864,6 +866,14 @@ export function useShellController() {
864
866
  currentTab: tab,
865
867
  stop: stopTurn,
866
868
  conversationNav,
869
+ // Revealability is driven by the EXPLICIT, sequence-guarded loading flag
870
+ // (set by runWithConversationLoading on clear/select/new and cleared in its
871
+ // finally) — never by `messages.length === 0`. A bare message-count heuristic
872
+ // is a STEADY-STATE condition, not a transient one: it latches true forever
873
+ // for a genuinely-empty active conversation (greeting generation failed
874
+ // silently, or an existing zero-message conversation was selected), which
875
+ // pinned a perpetual loading spinner and let the grabber/pill open the sheet
876
+ // into a never-resolving loader.
867
877
  conversationLoading,
868
878
  };
869
879
  }
@@ -1,15 +1,15 @@
1
1
  import type { ViewEntry } from "../../hooks/view-catalog.js";
2
2
  /**
3
- * The shared visual core for a launcher tile: render the view's hero
4
- * (`entry.imageUrl`, which the agent serves as a real image or a deterministic
5
- * branded SVG) and fall back to the Lucide glyph if the image is absent OR fails
6
- * to load so a tile is never blank. This is the single hero-resolution path
7
- * used by both the Springboard tile and the catalog "Get" card; callers supply
8
- * only the container/glyph styling that genuinely differs between surfaces.
3
+ * The shared visual core for view launch surfaces.
4
+ *
5
+ * Springboard tiles are app icons: deterministic colored glyph tiles that stay
6
+ * readable at 64px and never look like cropped preview cards. Catalog cards are
7
+ * previews: render the concrete hero or generated branded fallback, then fall
8
+ * back to a glyph if every image source fails.
9
9
  *
10
10
  * A load failure emits a `hero-image-error` interaction event (best-effort,
11
- * client-only) so broken hero endpoints are observable instead of silently
12
- * swallowed by the glyph fallback.
11
+ * client-only) from preview surfaces so broken hero endpoints are observable
12
+ * instead of silently swallowed by the glyph fallback.
13
13
  */
14
14
  export declare function ViewTileImage({ entry, source, containerClassName, glyphClassName, imageTestId, }: {
15
15
  entry: ViewEntry;
@@ -1 +1 @@
1
- {"version":3,"file":"ViewTileImage.d.ts","sourceRoot":"","sources":["../../../../../../src/components/views/ViewTileImage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAqB1D;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,MAAM,EACN,kBAAkB,EAClB,cAA0B,EAC1B,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,wEAAwE;IACxE,MAAM,EAAE,aAAa,GAAG,cAAc,CAAC;IACvC,+EAA+E;IAC/E,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,2CA2CA"}
1
+ {"version":3,"file":"ViewTileImage.d.ts","sourceRoot":"","sources":["../../../../../../src/components/views/ViewTileImage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAyD1D;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,MAAM,EACN,kBAAkB,EAClB,cAA0B,EAC1B,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,wEAAwE;IACxE,MAAM,EAAE,aAAa,GAAG,cAAc,CAAC;IACvC,+EAA+E;IAC/E,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,2CAwEA"}
@@ -1,8 +1,34 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
+ import { cn } from "../../lib/utils.js";
3
4
  import { resolveApiUrl } from "../../utils/asset-url.js";
4
5
  import { emitViewInteraction } from "../../view-telemetry.js";
5
6
  import { ViewIcon } from "./ViewIcon.js";
7
+ const SPRINGBOARD_ICON_PALETTES = [
8
+ { from: "#ff7a1a", to: "#f2c14e", foreground: "#fff7ed" },
9
+ { from: "#0f766e", to: "#5eead4", foreground: "#ecfeff" },
10
+ { from: "#1d4ed8", to: "#93c5fd", foreground: "#eff6ff" },
11
+ { from: "#7c2d12", to: "#fb923c", foreground: "#fff7ed" },
12
+ { from: "#334155", to: "#94a3b8", foreground: "#f8fafc" },
13
+ { from: "#be123c", to: "#fda4af", foreground: "#fff1f2" },
14
+ { from: "#166534", to: "#86efac", foreground: "#f0fdf4" },
15
+ { from: "#6d28d9", to: "#c4b5fd", foreground: "#f5f3ff" },
16
+ ];
17
+ function hashText(value) {
18
+ let hash = 0x811c9dc5;
19
+ for (let i = 0; i < value.length; i++) {
20
+ hash ^= value.charCodeAt(i);
21
+ hash = Math.imul(hash, 0x01000193);
22
+ }
23
+ return hash >>> 0;
24
+ }
25
+ function springboardIconStyle(entry) {
26
+ const palette = SPRINGBOARD_ICON_PALETTES[hashText(`${entry.id}:${entry.label}`) % SPRINGBOARD_ICON_PALETTES.length];
27
+ return {
28
+ background: `linear-gradient(145deg, ${palette.from} 0%, ${palette.to} 100%)`,
29
+ color: palette.foreground,
30
+ };
31
+ }
6
32
  /**
7
33
  * Resolve a tile hero URL into one reachable from the renderer. The hero source
8
34
  * is a root-relative API path (`/api/views/<id>/hero`) on built-in views, which
@@ -21,19 +47,22 @@ function resolveTileImageUrl(url) {
21
47
  return resolveApiUrl(url);
22
48
  }
23
49
  /**
24
- * The shared visual core for a launcher tile: render the view's hero
25
- * (`entry.imageUrl`, which the agent serves as a real image or a deterministic
26
- * branded SVG) and fall back to the Lucide glyph if the image is absent OR fails
27
- * to load so a tile is never blank. This is the single hero-resolution path
28
- * used by both the Springboard tile and the catalog "Get" card; callers supply
29
- * only the container/glyph styling that genuinely differs between surfaces.
50
+ * The shared visual core for view launch surfaces.
51
+ *
52
+ * Springboard tiles are app icons: deterministic colored glyph tiles that stay
53
+ * readable at 64px and never look like cropped preview cards. Catalog cards are
54
+ * previews: render the concrete hero or generated branded fallback, then fall
55
+ * back to a glyph if every image source fails.
30
56
  *
31
57
  * A load failure emits a `hero-image-error` interaction event (best-effort,
32
- * client-only) so broken hero endpoints are observable instead of silently
33
- * swallowed by the glyph fallback.
58
+ * client-only) from preview surfaces so broken hero endpoints are observable
59
+ * instead of silently swallowed by the glyph fallback.
34
60
  */
35
61
  export function ViewTileImage({ entry, source, containerClassName, glyphClassName = "h-6 w-6", imageTestId, }) {
36
62
  const [failure, setFailure] = useState("none");
63
+ if (source === "springboard") {
64
+ return (_jsxs("div", { className: cn(containerClassName, "relative overflow-hidden"), "data-view-visual": entry.id, style: springboardIconStyle(entry), children: [_jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute -right-4 -top-5 h-14 w-14 rounded-full bg-white/25" }), _jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 bg-[linear-gradient(160deg,rgba(255,255,255,0.36)_0%,rgba(255,255,255,0.08)_42%,rgba(0,0,0,0.2)_100%)]" }), _jsx(ViewIcon, { icon: entry.icon, label: entry.label, id: entry.id, className: cn(glyphClassName, "relative z-10 drop-shadow-[0_1px_3px_rgba(0,0,0,0.35)]") })] }));
65
+ }
37
66
  const primaryUrl = failure === "none" ? resolveTileImageUrl(entry.imageUrl) : undefined;
38
67
  const fallbackUrl = failure !== "all" ? resolveTileImageUrl(entry.fallbackImageUrl) : undefined;
39
68
  const url = primaryUrl ?? fallbackUrl;
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+ export interface UseHorizontalPagerOptions {
3
+ page: number;
4
+ pageCount: number;
5
+ enabled?: boolean;
6
+ /**
7
+ * Allows a right swipe from page 0 to call `onEdgeSwipeRight`. Keep this off
8
+ * for nested pagers so the parent rail can own its back gesture.
9
+ */
10
+ edgeSwipeRightEnabled?: boolean;
11
+ onPageChange: (page: number) => void;
12
+ onEdgeSwipeRight?: () => void;
13
+ }
14
+ export interface HorizontalPagerBinding<TViewport extends HTMLElement = HTMLDivElement> {
15
+ viewportRef: React.RefObject<TViewport | null>;
16
+ railRef: React.RefObject<HTMLDivElement | null>;
17
+ handlers: {
18
+ onPointerDown: React.PointerEventHandler<HTMLDivElement>;
19
+ onPointerMove: React.PointerEventHandler<HTMLDivElement>;
20
+ onPointerUp: React.PointerEventHandler<HTMLDivElement>;
21
+ onPointerCancel: React.PointerEventHandler<HTMLDivElement>;
22
+ onLostPointerCapture: React.PointerEventHandler<HTMLDivElement>;
23
+ };
24
+ }
25
+ /**
26
+ * Native-feeling horizontal pager for launcher surfaces.
27
+ *
28
+ * Pointer movement writes directly to the rail transform, paced by rAF, so a
29
+ * drag never waits on React render scheduling. React state is used only for the
30
+ * settled page index after release.
31
+ */
32
+ export declare function useHorizontalPager<TViewport extends HTMLElement = HTMLDivElement>({ page, pageCount, enabled, edgeSwipeRightEnabled, onPageChange, onEdgeSwipeRight, }: UseHorizontalPagerOptions): HorizontalPagerBinding<TViewport>;
33
+ //# sourceMappingURL=useHorizontalPager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHorizontalPager.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/useHorizontalPager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAuB/B,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,sBAAsB,CACrC,SAAS,SAAS,WAAW,GAAG,cAAc;IAE9C,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC/C,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAChD,QAAQ,EAAE;QACR,aAAa,EAAE,KAAK,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC;QACzD,aAAa,EAAE,KAAK,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC;QACzD,WAAW,EAAE,KAAK,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC;QACvD,eAAe,EAAE,KAAK,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC;QAC3D,oBAAoB,EAAE,KAAK,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC;KACjE,CAAC;CACH;AAkBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,SAAS,WAAW,GAAG,cAAc,EAC9C,EACA,IAAI,EACJ,SAAS,EACT,OAAc,EACd,qBAA6B,EAC7B,YAAY,EACZ,gBAAgB,GACjB,EAAE,yBAAyB,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAyP/D"}