@floegence/floe-webapp-core 0.26.5 → 0.26.6

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.
@@ -1,36 +1,30 @@
1
- import { createComponent as n, Dynamic as a } from "solid-js/web";
1
+ import { createComponent as i, Dynamic as u } from "solid-js/web";
2
2
  import { untrack as d, createMemo as m } from "solid-js";
3
3
  import { useLayout as l } from "../context/LayoutContext.js";
4
- import { useComponentRegistry as v } from "../context/ComponentRegistry.js";
4
+ import { useOptionalComponentRegistry as v } from "../context/ComponentRegistry.js";
5
5
  import { KeepAliveStack as f } from "../components/layout/KeepAliveStack.js";
6
- function y(e) {
6
+ function w(e) {
7
7
  return e.sidebar?.fullScreen === !0 || e.sidebar?.renderIn === "main";
8
8
  }
9
- function A(e) {
10
- const i = l(), r = (() => {
11
- try {
12
- return v();
13
- } catch {
14
- return null;
15
- }
16
- })();
9
+ function b(e) {
10
+ const n = l(), r = v();
17
11
  if (!d(() => !!e.views) && !r)
18
12
  throw new Error("ActivityAppsMain requires ComponentRegistryProvider when `views` is not provided.");
19
- const o = () => e.activeId ? e.activeId() : i.sidebarActiveTab(), u = m(() => {
13
+ const o = () => e.activeId ? e.activeId() : n.sidebarActiveTab(), s = m(() => {
20
14
  if (!r) return [];
21
- const s = e.include ?? y;
22
- return r.sidebarItems().filter((t) => s(t)).map((t) => ({
15
+ const c = e.include ?? w;
16
+ return r.sidebarItems().filter((t) => c(t)).map((t) => ({
23
17
  id: t.id,
24
- render: () => n(a, {
18
+ render: () => i(u, {
25
19
  get component() {
26
20
  return t.component;
27
21
  }
28
22
  })
29
23
  }));
30
- }), c = () => e.views ?? u();
31
- return n(f, {
24
+ }), a = () => e.views ?? s();
25
+ return i(f, {
32
26
  get views() {
33
- return c();
27
+ return a();
34
28
  },
35
29
  get activeId() {
36
30
  return o();
@@ -47,5 +41,5 @@ function A(e) {
47
41
  });
48
42
  }
49
43
  export {
50
- A as ActivityAppsMain
44
+ b as ActivityAppsMain
51
45
  };
@@ -98,4 +98,6 @@ export declare const ComponentRegistryProvider: (props: {
98
98
  children: import("solid-js").JSX.Element;
99
99
  }) => import("solid-js").JSX.Element;
100
100
  export declare function useComponentRegistry<TProtocol = unknown>(): ComponentRegistryValue<TProtocol>;
101
+ export declare function useOptionalComponentRegistry<TProtocol = unknown>(): ComponentRegistryValue<TProtocol> | undefined;
102
+ export declare function hasComponentRegistryContext(): boolean;
101
103
  export declare function createComponentRegistry(): ComponentRegistryValue<unknown>;
@@ -1,12 +1,12 @@
1
- import { createSignal as y } from "solid-js";
1
+ import { createSignal as C } from "solid-js";
2
2
  import { createSimpleContext as h } from "./createSimpleContext.js";
3
3
  import { useResolvedFloeConfig as w } from "./FloeConfigContext.js";
4
- import { useTheme as v } from "./ThemeContext.js";
5
- import { useLayout as x } from "./LayoutContext.js";
4
+ import { useTheme as x } from "./ThemeContext.js";
5
+ import { useLayout as v } from "./LayoutContext.js";
6
6
  import { useCommand as b } from "./CommandContext.js";
7
- import { useNotification as M } from "./NotificationContext.js";
8
- import { deferNonBlocking as S } from "../utils/defer.js";
9
- function A(r) {
7
+ import { useNotification as R } from "./NotificationContext.js";
8
+ import { deferNonBlocking as M } from "../utils/defer.js";
9
+ function S(r) {
10
10
  const s = `[${r}]`;
11
11
  return {
12
12
  debug: (...n) => console.debug(s, ...n),
@@ -15,47 +15,53 @@ function A(r) {
15
15
  error: (...n) => console.error(s, ...n)
16
16
  };
17
17
  }
18
- function R(r, s) {
18
+ function A(r, s) {
19
19
  const n = `component:${s}:`;
20
20
  return {
21
21
  get: (a, m) => r.load(n + a, m),
22
22
  set: (a, m) => r.debouncedSave(n + a, m),
23
- remove: (a) => S(() => r.remove(n + a))
23
+ remove: (a) => M(() => r.remove(n + a))
24
24
  };
25
25
  }
26
- function G() {
27
- const r = v(), s = x(), n = b(), a = M(), m = w();
28
- return (f, l) => ({
29
- protocol: l?.protocol,
26
+ function D() {
27
+ const r = x(), s = v(), n = b(), a = R(), m = w();
28
+ return (f, p) => ({
29
+ protocol: p?.protocol,
30
30
  theme: r,
31
31
  layout: s,
32
32
  commands: n,
33
33
  notifications: a,
34
- storage: R(m.persist, f),
35
- logger: A(f)
34
+ storage: A(m.persist, f),
35
+ logger: S(f)
36
36
  });
37
37
  }
38
- const C = h({
38
+ const l = h({
39
39
  name: "ComponentRegistry",
40
40
  init: B
41
- }), H = C.Provider;
41
+ }), G = l.Provider;
42
+ function H() {
43
+ return l.use();
44
+ }
42
45
  function J() {
43
- return C.use();
46
+ return l.useOptional();
47
+ }
48
+ function K() {
49
+ return l.has();
44
50
  }
45
51
  function B() {
46
- const [r, s] = y(/* @__PURE__ */ new Map()), [n, a] = y(/* @__PURE__ */ new Set()), m = /* @__PURE__ */ new Map(), f = (t) => {
52
+ const [r, s] = C(/* @__PURE__ */ new Map()), [n, a] = C(/* @__PURE__ */ new Set()), m = /* @__PURE__ */ new Map(), f = (t) => {
47
53
  s((e) => new Map(e).set(t.id, t));
48
- }, l = (t) => {
54
+ }, p = (t) => {
49
55
  const e = t.map((o) => o.id).filter((o) => !!o);
50
56
  return s((o) => {
51
57
  const c = new Map(o);
52
58
  return t.forEach((u) => c.set(u.id, u)), c;
53
59
  }), () => {
54
60
  e.forEach((o) => {
55
- g(o);
61
+ y(o);
56
62
  });
57
63
  };
58
- }, d = async (t, e) => {
64
+ }, g = async (t, e) => {
59
65
  const o = r().get(t);
60
66
  if (!o || n().has(t)) return;
61
67
  const c = [];
@@ -79,7 +85,7 @@ function B() {
79
85
  } catch (u) {
80
86
  throw c.forEach((i) => i()), u;
81
87
  }
82
- }, p = async (t) => {
88
+ }, d = async (t) => {
83
89
  const e = r().get(t);
84
90
  if (e && n().has(t))
85
91
  try {
@@ -90,25 +96,25 @@ function B() {
90
96
  return c.delete(t), c;
91
97
  });
92
98
  }
93
- }, g = async (t) => {
94
- await p(t), s((e) => {
99
+ }, y = async (t) => {
100
+ await d(t), s((e) => {
95
101
  const o = new Map(e);
96
102
  return o.delete(t), o;
97
103
  });
98
104
  };
99
105
  return {
100
106
  register: f,
101
- registerAll: l,
102
- unregister: g,
103
- mount: d,
104
- unmount: p,
107
+ registerAll: p,
108
+ unregister: y,
109
+ mount: g,
110
+ unmount: d,
105
111
  mountAll: async (t) => {
106
112
  for (const e of r().keys())
107
- await d(e, t(e));
113
+ await g(e, t(e));
108
114
  },
109
115
  unmountAll: async () => {
110
116
  for (const t of n())
111
- await p(t);
117
+ await d(t);
112
118
  },
113
119
  components: r,
114
120
  mountedComponents: n,
@@ -137,8 +143,10 @@ function B() {
137
143
  };
138
144
  }
139
145
  export {
140
- H as ComponentRegistryProvider,
146
+ G as ComponentRegistryProvider,
141
147
  B as createComponentRegistry,
142
- G as useComponentContextFactory,
143
- J as useComponentRegistry
148
+ K as hasComponentRegistryContext,
149
+ D as useComponentContextFactory,
150
+ H as useComponentRegistry,
151
+ J as useOptionalComponentRegistry
144
152
  };
@@ -156,6 +156,8 @@ export interface PersistApi {
156
156
  * while keeping debounced persistence in the hot interaction path.
157
157
  */
158
158
  flush?: () => void;
159
+ /** Cleanup pending timers (best-effort). */
160
+ dispose?: () => void;
159
161
  }
160
162
  export interface FloeConfigValue {
161
163
  config: FloeConfig;
@@ -165,6 +167,13 @@ export type DeepPartial<T> = T extends (...args: never[]) => unknown ? T : T ext
165
167
  [K in keyof T]?: DeepPartial<T[K]>;
166
168
  } : T;
167
169
  export declare const DEFAULT_FLOE_CONFIG: FloeConfig;
170
+ /**
171
+ * Install page lifecycle listeners that flush pending debounced saves.
172
+ *
173
+ * Keep this side-effect separate from createPersist() so importing the module does not
174
+ * register global listeners (important for testability and predictable composition).
175
+ */
176
+ export declare function installPersistFlushListeners(persist: Pick<PersistApi, 'flush'>): () => void;
168
177
  export interface FloeConfigProviderProps {
169
178
  config?: DeepPartial<FloeConfig>;
170
179
  children: JSX.Element;
@@ -1,5 +1,5 @@
1
- import { createComponent as I } from "solid-js/web";
2
- import { createContext as b, createMemo as u, useContext as h } from "solid-js";
1
+ import { createComponent as C } from "solid-js/web";
2
+ import { createContext as F, createMemo as u, createEffect as I, onCleanup as E, useContext as h } from "solid-js";
3
3
  const m = {
4
4
  storage: {
5
5
  namespace: "floe",
@@ -70,7 +70,7 @@ const m = {
70
70
  }
71
71
  }
72
72
  };
73
- function F() {
73
+ function S() {
74
74
  if (!(typeof window > "u"))
75
75
  return {
76
76
  getItem: (e) => localStorage.getItem(e),
@@ -80,79 +80,108 @@ function F() {
80
80
  };
81
81
  }
82
82
  function v(e) {
83
- const t = e.adapter ?? F(), c = e.namespace ? `${e.namespace}-` : "", i = (n) => `${c}${n}`, o = () => e.enabled && !!t, a = /* @__PURE__ */ new Map(), d = () => {
84
- if (o()) {
85
- for (const [n, r] of a.entries()) {
86
- clearTimeout(r.timer);
83
+ const t = e.adapter ?? S(), c = e.namespace ? `${e.namespace}-` : "", r = (o) => `${c}${o}`, n = () => e.enabled && !!t, i = /* @__PURE__ */ new Map(), d = () => {
84
+ if (n()) {
85
+ for (const [o, a] of i.entries()) {
86
+ clearTimeout(a.timer);
87
87
  try {
88
- t.setItem(n, JSON.stringify(r.value));
88
+ t.setItem(o, JSON.stringify(a.value));
89
89
  } catch (s) {
90
- console.warn(`Failed to save ${n}:`, s);
90
+ console.warn(`Failed to save ${o}:`, s);
91
91
  }
92
92
  }
93
- a.clear();
93
+ i.clear();
94
94
  }
95
95
  };
96
- if (typeof window < "u")
97
- try {
98
- window.addEventListener("pagehide", d), window.addEventListener("beforeunload", d), typeof document < "u" && document.addEventListener("visibilitychange", () => {
99
- document.visibilityState === "hidden" && d();
100
- });
101
- } catch {
102
- }
103
96
  return {
104
- key: i,
105
- load: (n, r) => {
106
- if (!o()) return r;
97
+ key: r,
98
+ load: (o, a) => {
99
+ if (!n()) return a;
107
100
  try {
108
- const s = t.getItem(i(n));
109
- return s === null ? r : JSON.parse(s);
101
+ const s = t.getItem(r(o));
102
+ return s === null ? a : JSON.parse(s);
110
103
  } catch {
111
- return r;
104
+ return a;
112
105
  }
113
106
  },
114
- save: (n, r) => {
115
- if (o())
107
+ save: (o, a) => {
108
+ if (n())
116
109
  try {
117
- t.setItem(i(n), JSON.stringify(r));
110
+ t.setItem(r(o), JSON.stringify(a));
118
111
  } catch (s) {
119
- console.warn(`Failed to save ${i(n)}:`, s);
112
+ console.warn(`Failed to save ${r(o)}:`, s);
120
113
  }
121
114
  },
122
- debouncedSave: (n, r, s = 300) => {
123
- if (!o()) return;
124
- const l = i(n), g = a.get(l);
125
- g && clearTimeout(g.timer);
126
- const p = setTimeout(() => {
127
- const f = a.get(l);
128
- if (!(!f || f.timer !== p)) {
129
- a.delete(l);
115
+ debouncedSave: (o, a, s = 300) => {
116
+ if (!n()) return;
117
+ const l = r(o), p = i.get(l);
118
+ p && clearTimeout(p.timer);
119
+ const g = setTimeout(() => {
120
+ const f = i.get(l);
121
+ if (!(!f || f.timer !== g)) {
122
+ i.delete(l);
130
123
  try {
131
124
  t.setItem(l, JSON.stringify(f.value));
132
- } catch (C) {
133
- console.warn(`Failed to save ${l}:`, C);
125
+ } catch (b) {
126
+ console.warn(`Failed to save ${l}:`, b);
134
127
  }
135
128
  }
136
129
  }, s);
137
- a.set(l, {
138
- timer: p,
139
- value: r
130
+ i.set(l, {
131
+ timer: g,
132
+ value: a
140
133
  });
141
134
  },
142
- remove: (n) => {
143
- if (o())
135
+ remove: (o) => {
136
+ if (n())
144
137
  try {
145
- t.removeItem(i(n));
138
+ t.removeItem(r(o));
146
139
  } catch {
147
140
  }
148
141
  },
149
142
  clearAll: () => {
150
- if (!o()) return;
151
- const n = t.keys?.() ?? [];
152
- for (const r of n)
153
- r.startsWith(c) && t.removeItem(r);
143
+ if (!n()) return;
144
+ const o = t.keys?.() ?? [];
145
+ for (const a of o)
146
+ a.startsWith(c) && t.removeItem(a);
154
147
  },
155
- flush: d
148
+ flush: d,
149
+ dispose: () => {
150
+ try {
151
+ d();
152
+ } finally {
153
+ for (const o of i.values())
154
+ clearTimeout(o.timer);
155
+ i.clear();
156
+ }
157
+ }
158
+ };
159
+ }
160
+ function k(e) {
161
+ if (typeof window > "u") return () => {
162
+ };
163
+ const t = () => {
164
+ try {
165
+ e.flush?.();
166
+ } catch {
167
+ }
168
+ }, c = () => t(), r = () => t(), n = () => {
169
+ try {
170
+ typeof document < "u" && document.visibilityState === "hidden" && t();
171
+ } catch {
172
+ }
173
+ };
174
+ try {
175
+ window.addEventListener("pagehide", c), window.addEventListener("beforeunload", r), typeof document < "u" && document.addEventListener("visibilitychange", n);
176
+ } catch {
177
+ return () => {
178
+ };
179
+ }
180
+ return () => {
181
+ try {
182
+ window.removeEventListener("pagehide", c), window.removeEventListener("beforeunload", r), typeof document < "u" && document.removeEventListener("visibilitychange", n);
183
+ } catch {
184
+ }
156
185
  };
157
186
  }
158
187
  function w(e, t) {
@@ -161,44 +190,53 @@ function w(e, t) {
161
190
  const c = {
162
191
  ...e
163
192
  };
164
- for (const [i, o] of Object.entries(t)) {
165
- if (o === void 0) continue;
166
- const a = e[i];
167
- typeof a == "object" && a !== null && typeof o == "object" && o !== null && !Array.isArray(o) ? c[i] = w(a, o) : c[i] = o;
193
+ for (const [r, n] of Object.entries(t)) {
194
+ if (n === void 0) continue;
195
+ const i = e[r];
196
+ typeof i == "object" && i !== null && typeof n == "object" && n !== null && !Array.isArray(n) ? c[r] = w(i, n) : c[r] = n;
168
197
  }
169
198
  return c;
170
199
  }
171
- const y = b();
172
- function A(e) {
173
- const t = u(() => w(m, e.config)), c = u(() => v(t().storage)), i = u(() => ({
200
+ const y = F();
201
+ function O(e) {
202
+ const t = u(() => w(m, e.config)), c = u(() => v(t().storage));
203
+ I(() => {
204
+ const n = c(), d = t().storage.enabled ? k(n) : () => {
205
+ };
206
+ E(() => {
207
+ d(), n.dispose?.();
208
+ });
209
+ });
210
+ const r = u(() => ({
174
211
  config: t(),
175
212
  persist: c()
176
213
  }));
177
- return I(y.Provider, {
214
+ return C(y.Provider, {
178
215
  get value() {
179
- return i();
216
+ return r();
180
217
  },
181
218
  get children() {
182
219
  return e.children;
183
220
  }
184
221
  });
185
222
  }
186
- function E() {
223
+ function D() {
187
224
  const e = h(y);
188
225
  if (!e)
189
226
  throw new Error("FloeConfigContext not found. Make sure to wrap your app with FloeConfigProvider (or FloeProvider).");
190
227
  return e;
191
228
  }
192
- const S = v(m.storage), k = {
229
+ const L = v(m.storage), T = {
193
230
  config: m,
194
- persist: S
231
+ persist: L
195
232
  };
196
- function L() {
197
- return h(y) ?? k;
233
+ function N() {
234
+ return h(y) ?? T;
198
235
  }
199
236
  export {
200
237
  m as DEFAULT_FLOE_CONFIG,
201
- A as FloeConfigProvider,
202
- E as useFloeConfig,
203
- L as useResolvedFloeConfig
238
+ O as FloeConfigProvider,
239
+ k as installPersistFlushListeners,
240
+ D as useFloeConfig,
241
+ N as useResolvedFloeConfig
204
242
  };
@@ -11,5 +11,7 @@ export declare function createSimpleContext<T>(options: {
11
11
  children: JSX.Element;
12
12
  }) => JSX.Element;
13
13
  use: () => T;
14
+ useOptional: () => T | undefined;
15
+ has: () => boolean;
14
16
  Context: import("solid-js").Context<T | undefined>;
15
17
  };
@@ -1,28 +1,36 @@
1
- import { createComponent as i } from "solid-js/web";
2
- import { createContext as u, useContext as m } from "solid-js";
3
- function x(t) {
4
- const r = u();
5
- function n(e) {
6
- const c = t.init();
7
- return i(r.Provider, {
1
+ import { createComponent as a } from "solid-js/web";
2
+ import { createContext as f, useContext as m } from "solid-js";
3
+ function p(e) {
4
+ const n = f();
5
+ function o(t) {
6
+ const c = e.init();
7
+ return a(n.Provider, {
8
8
  value: c,
9
9
  get children() {
10
- return e.children;
10
+ return t.children;
11
11
  }
12
12
  });
13
13
  }
14
- function o() {
15
- const e = m(r);
16
- if (!e)
17
- throw new Error(`${t.name}Context not found. Make sure to wrap your component with ${t.name}Provider.`);
18
- return e;
14
+ function r() {
15
+ return m(n);
16
+ }
17
+ function u() {
18
+ const t = r();
19
+ if (!t)
20
+ throw new Error(`${e.name}Context not found. Make sure to wrap your component with ${e.name}Provider.`);
21
+ return t;
22
+ }
23
+ function i() {
24
+ return r() !== void 0;
19
25
  }
20
26
  return {
21
- Provider: n,
22
- use: o,
23
- Context: r
27
+ Provider: o,
28
+ use: u,
29
+ useOptional: r,
30
+ has: i,
31
+ Context: n
24
32
  };
25
33
  }
26
34
  export {
27
- x as createSimpleContext
35
+ p as createSimpleContext
28
36
  };
@@ -4,7 +4,7 @@ export { ThemeProvider, useTheme, createThemeService, type ThemeContextValue } f
4
4
  export { LayoutProvider, useLayout, createLayoutService, type LayoutContextValue } from './LayoutContext';
5
5
  export { CommandProvider, useCommand, createCommandService, type Command, type CommandContextValue } from './CommandContext';
6
6
  export { NotificationProvider, useNotification, createNotificationService, NotificationContainer, type Notification, type NotificationType, type NotificationContextValue, } from './NotificationContext';
7
- export { ComponentRegistryProvider, useComponentRegistry, useComponentContextFactory, createComponentRegistry, type FloeComponent, type ComponentContext, type CommandContribution, type StatusBarContribution, type ComponentRegistryValue, } from './ComponentRegistry';
7
+ export { ComponentRegistryProvider, useComponentRegistry, useOptionalComponentRegistry, hasComponentRegistryContext, useComponentContextFactory, createComponentRegistry, type FloeComponent, type ComponentContext, type CommandContribution, type StatusBarContribution, type ComponentRegistryValue, } from './ComponentRegistry';
8
8
  export { WidgetRegistryProvider, useWidgetRegistry, createWidgetRegistry, type WidgetDefinition, type WidgetProps, type WidgetRegistryValue, } from './WidgetRegistry';
9
9
  export { DeckProvider, useDeck, createDeckService, type DeckWidget, type DeckLayout, type DragState, type ResizeState, type DeckContextValue, } from './DeckContext';
10
10
  export { WidgetStateProvider, useWidgetStateContext, useWidgetState, useCurrentWidgetId, type WidgetStateContextValue, type WidgetStateProviderProps, } from './WidgetStateContext';