@floegence/floe-webapp-core 0.26.0 → 0.26.2

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.
@@ -11,7 +11,7 @@ export interface ActivityAppsMainProps<TProtocol = unknown> {
11
11
  */
12
12
  views?: KeepAliveView[];
13
13
  /**
14
- * Registry-driven filter (default: sidebar.fullScreen === true).
14
+ * Registry-driven filter (default: sidebar.fullScreen === true OR sidebar.renderIn === 'main').
15
15
  * Only used when `views` is not provided.
16
16
  */
17
17
  include?: (component: FloeComponent<TProtocol>) => boolean;
@@ -4,7 +4,7 @@ import { useLayout as l } from "../context/LayoutContext.js";
4
4
  import { useComponentRegistry as v } from "../context/ComponentRegistry.js";
5
5
  import { KeepAliveStack as f } from "../components/layout/KeepAliveStack.js";
6
6
  function y(e) {
7
- return e.sidebar?.fullScreen === !0;
7
+ return e.sidebar?.fullScreen === !0 || e.sidebar?.renderIn === "main";
8
8
  }
9
9
  function A(e) {
10
10
  const i = l(), r = (() => {
@@ -16,7 +16,7 @@ function A(e) {
16
16
  })();
17
17
  if (!d(() => !!e.views) && !r)
18
18
  throw new Error("ActivityAppsMain requires ComponentRegistryProvider when `views` is not provided.");
19
- const o = () => e.activeId ? e.activeId() : i.sidebarActiveTab(), c = m(() => {
19
+ const o = () => e.activeId ? e.activeId() : i.sidebarActiveTab(), u = m(() => {
20
20
  if (!r) return [];
21
21
  const s = e.include ?? y;
22
22
  return r.sidebarItems().filter((t) => s(t)).map((t) => ({
@@ -27,10 +27,10 @@ function A(e) {
27
27
  }
28
28
  })
29
29
  }));
30
- }), u = () => e.views ?? c();
30
+ }), c = () => e.views ?? u();
31
31
  return n(f, {
32
32
  get views() {
33
- return u();
33
+ return c();
34
34
  },
35
35
  get activeId() {
36
36
  return o();
@@ -0,0 +1,28 @@
1
+ import { type JSX } from 'solid-js';
2
+ import { type LaunchpadItemData } from './Launchpad';
3
+ export interface LaunchpadModalProps {
4
+ open: boolean;
5
+ onOpenChange: (open: boolean) => void;
6
+ items: LaunchpadItemData[];
7
+ additionalItems?: LaunchpadItemData[];
8
+ itemsPerPage?: number;
9
+ columns?: number;
10
+ showSearch?: boolean;
11
+ class?: string;
12
+ style?: JSX.CSSProperties;
13
+ /** Called after the modal reacts (closes first when closeOnSelect is enabled). */
14
+ onSelect?: (item: LaunchpadItemData) => void;
15
+ /**
16
+ * Whether to close the modal when an item is selected (default: true).
17
+ * Use a function for per-item control.
18
+ */
19
+ closeOnSelect?: boolean | ((item: LaunchpadItemData) => boolean);
20
+ }
21
+ /**
22
+ * Modal wrapper for Launchpad.
23
+ *
24
+ * Guarantees "mask semantics":
25
+ * - Wheel keeps Launchpad pagination working but prevents background scroll.
26
+ * - Escape closes the modal and does not leak to underlying global shortcuts.
27
+ */
28
+ export declare function LaunchpadModal(props: LaunchpadModalProps): JSX.Element;
@@ -0,0 +1,113 @@
1
+ import { createComponent as f, Portal as P, insert as T, template as D, use as M } from "solid-js/web";
2
+ import { createMemo as s, createEffect as x, onCleanup as B, Show as I } from "solid-js";
3
+ import { lockBodyStyle as O } from "../../utils/bodyStyleLock.js";
4
+ import { deferNonBlocking as A } from "../../utils/defer.js";
5
+ import { Launchpad as F } from "./Launchpad.js";
6
+ var H = /* @__PURE__ */ D("<div role=dialog aria-modal=true tabindex=-1>");
7
+ function y(n) {
8
+ const c = ["a[href]", "button:not([disabled])", "input:not([disabled])", "select:not([disabled])", "textarea:not([disabled])", '[tabindex]:not([tabindex="-1"])', '[contenteditable="true"]'].join(",");
9
+ return Array.from(n.querySelectorAll(c)).filter((u) => u instanceof HTMLElement);
10
+ }
11
+ function N(n) {
12
+ let c;
13
+ const u = s(() => n.onOpenChange), w = s(() => n.onSelect), i = () => u()(!1), L = s(() => n.items.map((t) => ({
14
+ ...t,
15
+ onClick: void 0
16
+ }))), k = s(() => n.additionalItems?.map((t) => ({
17
+ ...t,
18
+ onClick: void 0
19
+ }))), C = (t) => {
20
+ const o = n.closeOnSelect;
21
+ return typeof o == "function" ? o(t) : o !== !1;
22
+ }, S = (t) => {
23
+ C(t) && i();
24
+ const o = w();
25
+ o && A(() => o(t));
26
+ };
27
+ return x(() => {
28
+ if (!n.open || typeof document > "u") return;
29
+ const t = document.activeElement instanceof HTMLElement ? document.activeElement : null, o = O({
30
+ overflow: "hidden"
31
+ });
32
+ setTimeout(() => {
33
+ const e = c;
34
+ if (!e) return;
35
+ const r = e.querySelector(".launchpad-search input");
36
+ if (r) {
37
+ r.focus();
38
+ return;
39
+ }
40
+ (y(e)[0] ?? e).focus();
41
+ }, 0);
42
+ const m = (e) => {
43
+ if (e.key !== "Tab") return;
44
+ const r = c;
45
+ if (!r) return;
46
+ const a = y(r);
47
+ if (!a.length) {
48
+ e.preventDefault(), r.focus();
49
+ return;
50
+ }
51
+ const d = a[0], b = a[a.length - 1], l = document.activeElement instanceof HTMLElement ? document.activeElement : null;
52
+ e.shiftKey ? (l === d || !l || !r.contains(l)) && (e.preventDefault(), b.focus()) : l === b && (e.preventDefault(), d.focus());
53
+ }, v = (e) => {
54
+ e.key === "Escape" && (e.preventDefault(), e.stopImmediatePropagation(), i());
55
+ }, h = (e) => {
56
+ e.stopPropagation();
57
+ }, p = (e) => {
58
+ e.cancelable && e.preventDefault();
59
+ }, g = (e) => {
60
+ e.stopPropagation();
61
+ }, E = (e) => {
62
+ e.cancelable && e.preventDefault();
63
+ };
64
+ document.addEventListener("keydown", m, !0), window.addEventListener("keydown", v, !0), document.addEventListener("keydown", h), document.addEventListener("wheel", p, {
65
+ capture: !0,
66
+ passive: !1
67
+ }), document.addEventListener("wheel", g), document.addEventListener("touchmove", E, {
68
+ capture: !0,
69
+ passive: !1
70
+ }), B(() => {
71
+ document.removeEventListener("keydown", m, !0), window.removeEventListener("keydown", v, !0), document.removeEventListener("keydown", h), document.removeEventListener("wheel", p, !0), document.removeEventListener("wheel", g), document.removeEventListener("touchmove", E, !0), o(), t?.focus();
72
+ });
73
+ }), f(I, {
74
+ get when() {
75
+ return n.open;
76
+ },
77
+ get children() {
78
+ return f(P, {
79
+ get children() {
80
+ var t = H(), o = c;
81
+ return typeof o == "function" ? M(o, t) : c = t, T(t, f(F, {
82
+ get items() {
83
+ return L();
84
+ },
85
+ get additionalItems() {
86
+ return k();
87
+ },
88
+ get itemsPerPage() {
89
+ return n.itemsPerPage;
90
+ },
91
+ get columns() {
92
+ return n.columns;
93
+ },
94
+ get showSearch() {
95
+ return n.showSearch;
96
+ },
97
+ get class() {
98
+ return n.class;
99
+ },
100
+ get style() {
101
+ return n.style;
102
+ },
103
+ onItemClick: S,
104
+ onClose: i
105
+ })), t;
106
+ }
107
+ });
108
+ }
109
+ });
110
+ }
111
+ export {
112
+ N as LaunchpadModal
113
+ };
@@ -1,5 +1,7 @@
1
1
  export { Launchpad } from './Launchpad';
2
2
  export type { LaunchpadProps, LaunchpadItemData } from './Launchpad';
3
+ export { LaunchpadModal } from './LaunchpadModal';
4
+ export type { LaunchpadModalProps } from './LaunchpadModal';
3
5
  export { LaunchpadItem } from './LaunchpadItem';
4
6
  export type { LaunchpadItemProps } from './LaunchpadItem';
5
7
  export { LaunchpadGrid } from './LaunchpadGrid';
@@ -1,258 +1,268 @@
1
- import { createComponent as t, Dynamic as S, insert as s, memo as C, effect as $, className as M, setStyleProperty as W, template as v, delegateEvents as E } from "solid-js/web";
2
- import { createSignal as N, createEffect as g, createMemo as h, For as y, Show as u } from "solid-js";
3
- import { useLayout as Q } from "../../context/LayoutContext.js";
4
- import { useResolvedFloeConfig as D } from "../../context/FloeConfigContext.js";
5
- import { useMediaQuery as K } from "../../hooks/useMediaQuery.js";
1
+ import { createComponent as r, Dynamic as S, insert as c, memo as C, effect as T, className as M, setStyleProperty as E, template as h, delegateEvents as N } from "solid-js/web";
2
+ import { createSignal as Q, createEffect as v, createMemo as f, For as $, Show as m } from "solid-js";
3
+ import { useLayout as D } from "../../context/LayoutContext.js";
4
+ import { useResolvedFloeConfig as K } from "../../context/FloeConfigContext.js";
5
+ import { useMediaQuery as L } from "../../hooks/useMediaQuery.js";
6
6
  import { cn as x } from "../../utils/cn.js";
7
- import { deferNonBlocking as L } from "../../utils/defer.js";
8
- import { useComponentRegistry as V } from "../../context/ComponentRegistry.js";
9
- import { Sidebar as j } from "./Sidebar.js";
10
- import { TopBar as q } from "./TopBar.js";
11
- import { TopBarIconButton as G } from "./TopBarIconButton.js";
12
- import { BottomBar as J } from "./BottomBar.js";
13
- import { MobileTabBar as U } from "./MobileTabBar.js";
14
- import { ActivityBar as X } from "./ActivityBar.js";
7
+ import { deferNonBlocking as V } from "../../utils/defer.js";
8
+ import { useComponentRegistry as j } from "../../context/ComponentRegistry.js";
9
+ import { Sidebar as q } from "./Sidebar.js";
10
+ import { TopBar as G } from "./TopBar.js";
11
+ import { TopBarIconButton as J } from "./TopBarIconButton.js";
12
+ import { BottomBar as U } from "./BottomBar.js";
13
+ import { MobileTabBar as X } from "./MobileTabBar.js";
14
+ import { ActivityBar as Y } from "./ActivityBar.js";
15
15
  import { ResizeHandle as _ } from "./ResizeHandle.js";
16
- import { resolveMobileTabActiveId as Y, resolveMobileTabSelect as Z } from "./mobileTabs.js";
17
- import { KeepAliveStack as ee } from "./KeepAliveStack.js";
18
- var k = /* @__PURE__ */ v('<div class="flex items-center gap-2">'), te = /* @__PURE__ */ v('<div class="absolute inset-0 z-40 bg-black/30 cursor-pointer">'), re = /* @__PURE__ */ v('<div><div class="h-full overflow-auto overscroll-contain">'), ie = /* @__PURE__ */ v('<div class="relative shrink-0 border-t border-border bg-terminal-background overflow-hidden">'), ne = /* @__PURE__ */ v('<div><div class="flex-1 min-h-0 flex overflow-hidden relative"><div class="flex-1 min-w-0 flex flex-col overflow-hidden"><main class="flex-1 min-h-0 overflow-auto overscroll-contain">');
19
- function Ie(o) {
20
- const r = Q(), O = D(), c = K(O.config.layout.mobileQuery), [w, b] = N(!1), m = () => o.sidebarMode === "hidden", d = (() => {
16
+ import { resolveMobileTabActiveId as Z, resolveMobileTabSelect as ee } from "./mobileTabs.js";
17
+ import { KeepAliveStack as te } from "./KeepAliveStack.js";
18
+ var k = /* @__PURE__ */ h('<div class="flex items-center gap-2">'), re = /* @__PURE__ */ h('<div class="absolute inset-0 z-40 bg-black/30 cursor-pointer">'), ie = /* @__PURE__ */ h('<div><div class="h-full overflow-auto overscroll-contain">'), ne = /* @__PURE__ */ h('<div class="relative shrink-0 border-t border-border bg-terminal-background overflow-hidden">'), oe = /* @__PURE__ */ h('<div><div class="flex-1 min-h-0 flex overflow-hidden relative"><div class="flex-1 min-w-0 flex flex-col overflow-hidden"><main class="flex-1 min-h-0 overflow-auto overscroll-contain">');
19
+ function Be(o) {
20
+ const i = D(), O = K(), d = L(O.config.layout.mobileQuery), [I, b] = Q(!1), u = () => o.sidebarMode === "hidden", a = (() => {
21
21
  try {
22
- return V();
22
+ return j();
23
23
  } catch {
24
24
  return null;
25
25
  }
26
- })(), I = (e, a) => {
27
- const l = d?.getComponent(e)?.sidebar?.fullScreen ?? !1, i = m() ? !1 : a?.openSidebar ?? !l;
28
- r.setSidebarActiveTab(e, {
29
- openSidebar: i
26
+ })(), w = (e, s) => {
27
+ const l = a?.getComponent(e)?.sidebar?.fullScreen ?? !1, t = u() ? !1 : s?.openSidebar ?? !l;
28
+ i.setSidebarActiveTab(e, {
29
+ openSidebar: t
30
30
  });
31
31
  };
32
- g(() => {
33
- m() && b(!1);
34
- }), g(() => {
35
- const e = c();
36
- r.isMobile() !== e && r.setIsMobile(e);
37
- }), g(() => {
38
- c() || b(!1);
32
+ v(() => {
33
+ u() && b(!1);
34
+ }), v(() => {
35
+ const e = d();
36
+ i.isMobile() !== e && i.setIsMobile(e);
37
+ }), v(() => {
38
+ d() || b(!1);
39
39
  });
40
- const f = h(() => o.activityItems ? o.activityItems : d ? d.sidebarItems().filter((e) => !!e.icon).filter((e) => !(c() && e.sidebar?.hiddenOnMobile)).map((e) => ({
40
+ const g = f(() => o.activityItems ? o.activityItems : a ? a.sidebarItems().filter((e) => !!e.icon).filter((e) => !(d() && e.sidebar?.hiddenOnMobile)).map((e) => ({
41
41
  id: e.id,
42
42
  icon: e.icon,
43
43
  label: e.name,
44
44
  badge: e.sidebar?.badge,
45
45
  collapseBehavior: e.sidebar?.fullScreen ? "preserve" : "toggle"
46
- })) : []), z = h(() => m() ? [] : o.sidebarContent ? [] : d ? d.sidebarItems().filter((e) => !(c() && e.sidebar?.hiddenOnMobile)).filter((e) => !e.sidebar?.fullScreen).map((e) => ({
46
+ })) : []), z = f(() => u() ? [] : o.sidebarContent ? [] : a ? a.sidebarItems().filter((e) => !(d() && e.sidebar?.hiddenOnMobile)).filter((e) => e.sidebar?.fullScreen !== !0 && e.sidebar?.renderIn !== "main").map((e) => ({
47
47
  id: e.id,
48
- render: () => t(S, {
48
+ render: () => r(S, {
49
49
  get component() {
50
50
  return e.component;
51
51
  }
52
52
  })
53
- })) : []), T = (e) => {
54
- if (!m()) {
53
+ })) : []), y = (e) => {
54
+ if (!u()) {
55
55
  if (o.sidebarContent) return o.sidebarContent(e);
56
- if (d)
57
- return t(ee, {
56
+ if (a)
57
+ return r(te, {
58
58
  get views() {
59
59
  return z();
60
60
  },
61
61
  activeId: e
62
62
  });
63
63
  }
64
- }, B = h(() => m() ? !0 : d ? d.getComponent(r.sidebarActiveTab())?.sidebar?.fullScreen ?? !1 : !1);
65
- g(() => {
66
- c() && B() && b(!1);
64
+ }, B = f(() => u() ? !0 : a ? a.getComponent(i.sidebarActiveTab())?.sidebar?.fullScreen ?? !1 : !1), F = f(() => {
65
+ if (u()) return !0;
66
+ if (!a) return !1;
67
+ const e = a.getComponent(i.sidebarActiveTab());
68
+ return e?.sidebar ? e.sidebar.fullScreen === !0 || e.sidebar.renderIn === "main" : !1;
67
69
  });
68
- const F = h(() => {
70
+ v(() => {
71
+ d() && B() && b(!1);
72
+ });
73
+ const H = f(() => {
69
74
  if (o.bottomBarItems) return o.bottomBarItems;
70
- if (!d) return;
71
- const e = [...d.statusBarItems()].sort((i, n) => (i.order ?? 100) - (n.order ?? 100)), a = e.filter((i) => i.position === "left"), l = e.filter((i) => i.position === "right");
75
+ if (!a) return;
76
+ const e = [...a.statusBarItems()].sort((t, n) => (t.order ?? 100) - (n.order ?? 100)), s = e.filter((t) => t.position === "left"), l = e.filter((t) => t.position === "right");
72
77
  return [(() => {
73
- var i = k();
74
- return s(i, t(y, {
75
- each: a,
76
- children: (n) => t(S, {
78
+ var t = k();
79
+ return c(t, r($, {
80
+ each: s,
81
+ children: (n) => r(S, {
77
82
  get component() {
78
83
  return n.component;
79
84
  }
80
85
  })
81
- })), i;
86
+ })), t;
82
87
  })(), (() => {
83
- var i = k();
84
- return s(i, t(y, {
88
+ var t = k();
89
+ return c(t, r($, {
85
90
  each: l,
86
- children: (n) => t(S, {
91
+ children: (n) => r(S, {
87
92
  get component() {
88
93
  return n.component;
89
94
  }
90
95
  })
91
- })), i;
96
+ })), t;
92
97
  })()];
93
98
  });
94
- g(() => {
95
- const e = f();
99
+ v(() => {
100
+ const e = g();
96
101
  if (!e.length) return;
97
- r.sidebarActiveTab() || I(e[0].id);
102
+ if (!i.sidebarActiveTab()) {
103
+ const l = e.find((t) => !t.onClick);
104
+ if (!l) return;
105
+ w(l.id);
106
+ }
98
107
  });
99
108
  const A = (e) => {
100
- const a = m() ? !0 : d?.getComponent(e)?.sidebar?.fullScreen ?? !1, {
109
+ const s = u() ? !0 : a?.getComponent(e)?.sidebar?.fullScreen ?? !1, {
101
110
  nextActiveId: l,
102
- nextMobileSidebarOpen: i
103
- } = Z({
111
+ nextMobileSidebarOpen: t
112
+ } = ee({
104
113
  clickedId: e,
105
- activeId: r.sidebarActiveTab(),
106
- mobileSidebarOpen: w(),
107
- clickedIsFullScreen: a
114
+ activeId: i.sidebarActiveTab(),
115
+ mobileSidebarOpen: I(),
116
+ clickedIsFullScreen: s
108
117
  });
109
- r.sidebarActiveTab() !== l && I(l), b(i);
110
- }, H = (e) => {
118
+ i.sidebarActiveTab() !== l && w(l), b(t);
119
+ }, P = (e) => {
111
120
  if (e.onClick) {
112
- L(() => e.onClick());
121
+ V(() => e.onClick());
113
122
  return;
114
123
  }
115
124
  A(e.id);
116
- }, R = h(() => {
125
+ }, R = f(() => {
117
126
  const e = o.topBarActions;
118
- if (!c() || (o.activityBottomItemsMobileMode ?? "hidden") !== "topBar") return e;
127
+ if (!d() || (o.activityBottomItemsMobileMode ?? "hidden") !== "topBar") return e;
119
128
  const l = o.activityBottomItems ?? [];
120
- return l.length ? [t(y, {
129
+ return l.length ? [r($, {
121
130
  each: l,
122
- children: (i) => t(G, {
131
+ children: (t) => r(J, {
123
132
  get label() {
124
- return i.label;
133
+ return t.label;
125
134
  },
126
- onClick: () => H(i),
135
+ onClick: () => P(t),
127
136
  get children() {
128
- return t(S, {
137
+ return r(S, {
129
138
  get component() {
130
- return i.icon;
139
+ return t.icon;
131
140
  },
132
141
  class: "w-4 h-4"
133
142
  });
134
143
  }
135
144
  })
136
145
  }), e] : e;
137
- }), P = () => m() ? !0 : r.sidebarCollapsed();
146
+ }), W = () => u() ? !0 : i.sidebarCollapsed();
138
147
  return (() => {
139
- var e = ne(), a = e.firstChild, l = a.firstChild, i = l.firstChild;
140
- return s(e, t(q, {
148
+ var e = oe(), s = e.firstChild, l = s.firstChild, t = l.firstChild;
149
+ return c(e, r(G, {
141
150
  get logo() {
142
151
  return o.logo;
143
152
  },
144
153
  get actions() {
145
154
  return R();
146
155
  }
147
- }), a), s(a, t(u, {
156
+ }), s), c(s, r(m, {
148
157
  get when() {
149
- return !c();
158
+ return !d();
150
159
  },
151
160
  get children() {
152
- return [t(u, {
161
+ return [r(m, {
153
162
  get when() {
154
- return f().length > 0;
163
+ return g().length > 0;
155
164
  },
156
165
  get children() {
157
- return t(X, {
166
+ return r(Y, {
158
167
  get items() {
159
- return f();
168
+ return g();
160
169
  },
161
170
  get bottomItems() {
162
171
  return o.activityBottomItems;
163
172
  },
164
173
  get activeId() {
165
- return r.sidebarActiveTab();
174
+ return i.sidebarActiveTab();
166
175
  },
167
- onActiveChange: I,
176
+ onActiveChange: w,
168
177
  get collapsed() {
169
- return P();
178
+ return W();
170
179
  },
171
180
  get onCollapsedChange() {
172
- return C(() => !!m())() ? void 0 : r.setSidebarCollapsed;
181
+ return C(() => !!u())() ? void 0 : i.setSidebarCollapsed;
173
182
  }
174
183
  });
175
184
  }
176
- }), t(u, {
185
+ }), r(m, {
177
186
  get when() {
178
- return !m();
187
+ return !u();
179
188
  },
180
189
  get children() {
181
- return t(j, {
190
+ return r(q, {
182
191
  get width() {
183
- return r.sidebarWidth();
192
+ return i.sidebarWidth();
184
193
  },
185
194
  get collapsed() {
186
- return r.sidebarCollapsed() || B();
195
+ return i.sidebarCollapsed() || B();
187
196
  },
188
197
  get resizer() {
189
- return t(_, {
198
+ return r(_, {
190
199
  direction: "horizontal",
191
- onResize: (n) => r.setSidebarWidth(r.sidebarWidth() + n)
200
+ onResize: (n) => i.setSidebarWidth(i.sidebarWidth() + n)
192
201
  });
193
202
  },
194
203
  get children() {
195
- return T(r.sidebarActiveTab());
204
+ return y(i.sidebarActiveTab());
196
205
  }
197
206
  });
198
207
  }
199
208
  })];
200
209
  }
201
- }), l), s(a, t(u, {
210
+ }), l), c(s, r(m, {
202
211
  get when() {
203
- return C(() => !!(c() && w()))() && !m();
212
+ return C(() => !!(d() && I()))() && !u();
204
213
  },
205
214
  get children() {
206
215
  return [(() => {
207
- var n = te();
216
+ var n = re();
208
217
  return n.$$click = () => b(!1), n;
209
218
  })(), (() => {
210
- var n = re(), p = n.firstChild;
211
- return s(p, () => T(r.sidebarActiveTab())), $(() => M(n, x("absolute left-0 top-0 bottom-0 z-50", "w-72 max-w-[80vw]", "bg-sidebar border-r border-sidebar-border", "shadow-xl", "animate-in slide-in-from-left duration-200"))), n;
219
+ var n = ie(), p = n.firstChild;
220
+ return c(p, () => y(i.sidebarActiveTab())), T(() => M(n, x("absolute left-0 top-0 bottom-0 z-50", "w-72 max-w-[80vw]", "bg-sidebar border-r border-sidebar-border", "shadow-xl", "animate-in slide-in-from-left duration-200"))), n;
212
221
  })()];
213
222
  }
214
- }), l), s(i, () => o.children), s(l, t(u, {
223
+ }), l), c(t, () => o.children), c(l, r(m, {
215
224
  get when() {
216
- return C(() => !!(!c() && r.terminalOpened()))() && o.terminalPanel;
225
+ return C(() => !!(!d() && i.terminalOpened()))() && o.terminalPanel;
217
226
  },
218
227
  get children() {
219
- var n = ie();
220
- return s(n, t(_, {
228
+ var n = ne();
229
+ return c(n, r(_, {
221
230
  direction: "vertical",
222
- onResize: (p) => r.setTerminalHeight(r.terminalHeight() - p)
223
- }), null), s(n, () => o.terminalPanel, null), $((p) => W(n, "height", `${r.terminalHeight()}px`)), n;
231
+ onResize: (p) => i.setTerminalHeight(i.terminalHeight() - p)
232
+ }), null), c(n, () => o.terminalPanel, null), T((p) => E(n, "height", `${i.terminalHeight()}px`)), n;
224
233
  }
225
- }), null), s(e, t(u, {
234
+ }), null), c(e, r(m, {
226
235
  get when() {
227
- return !c();
236
+ return !d();
228
237
  },
229
238
  get children() {
230
- return t(J, {
239
+ return r(U, {
231
240
  get children() {
232
- return F();
241
+ return H();
233
242
  }
234
243
  });
235
244
  }
236
- }), null), s(e, t(u, {
245
+ }), null), c(e, r(m, {
237
246
  get when() {
238
- return C(() => !!c())() && f().length > 0;
247
+ return C(() => !!d())() && g().length > 0;
239
248
  },
240
249
  get children() {
241
- return t(U, {
250
+ return r(X, {
242
251
  get items() {
243
- return f();
252
+ return g();
244
253
  },
245
254
  get activeId() {
246
- return Y({
247
- activeId: r.sidebarActiveTab(),
248
- mobileSidebarOpen: w(),
249
- activeIsFullScreen: B()
255
+ return Z({
256
+ activeId: i.sidebarActiveTab(),
257
+ mobileSidebarOpen: I(),
258
+ activeIsFullScreen: B(),
259
+ activeIsPage: F()
250
260
  });
251
261
  },
252
262
  onSelect: A
253
263
  });
254
264
  }
255
- }), null), $(() => M(e, x(
265
+ }), null), T(() => M(e, x(
256
266
  // Use dvh when supported to avoid mobile browser UI causing layout jumps.
257
267
  "h-screen h-[100dvh] w-full flex flex-col overflow-hidden",
258
268
  "bg-background text-foreground",
@@ -262,7 +272,7 @@ function Ie(o) {
262
272
  ))), e;
263
273
  })();
264
274
  }
265
- E(["click"]);
275
+ N(["click"]);
266
276
  export {
267
- Ie as Shell
277
+ Be as Shell
268
278
  };
@@ -5,6 +5,12 @@ export interface ResolveMobileTabActiveIdArgs {
5
5
  mobileSidebarOpen: boolean;
6
6
  /** Whether the active component is marked as fullScreen. */
7
7
  activeIsFullScreen: boolean;
8
+ /**
9
+ * Whether the active tab should be treated as a page, even if it isn't fullScreen.
10
+ *
11
+ * This is useful for "main view + sidebar panel" tabs.
12
+ */
13
+ activeIsPage?: boolean;
8
14
  }
9
15
  /**
10
16
  * Determine which tab should appear active in the mobile tab bar.
@@ -1,5 +1,5 @@
1
1
  function i(e) {
2
- return e.activeIsFullScreen || e.mobileSidebarOpen ? e.activeId : "";
2
+ return e.activeIsFullScreen || e.activeIsPage || e.mobileSidebarOpen ? e.activeId : "";
3
3
  }
4
4
  function t(e) {
5
5
  return e.clickedIsFullScreen ? { nextActiveId: e.clickedId, nextMobileSidebarOpen: !1 } : e.clickedId === e.activeId && e.mobileSidebarOpen ? { nextActiveId: e.clickedId, nextMobileSidebarOpen: !1 } : { nextActiveId: e.clickedId, nextMobileSidebarOpen: !0 };
@@ -56,6 +56,15 @@ export interface FloeComponent<TProtocol = unknown> {
56
56
  sidebar?: {
57
57
  order?: number;
58
58
  badge?: () => number | string | undefined;
59
+ /**
60
+ * Where this component should render when active.
61
+ *
62
+ * - `sidebar` (default): render inside Shell's sidebar panel.
63
+ * - `main`: render in the main content area (typically via ActivityAppsMain).
64
+ *
65
+ * Note: `fullScreen: true` implies `renderIn: 'main'` and also hides the sidebar.
66
+ */
67
+ renderIn?: 'sidebar' | 'main';
59
68
  /** When true, this component uses the full content area without sidebar */
60
69
  fullScreen?: boolean;
61
70
  /** When true, this component is hidden in the activity bar on mobile */