@floegence/floe-webapp-core 0.65.1 → 0.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/floe.css CHANGED
@@ -1,3 +1,4 @@
1
+ @import './primitives.css';
1
2
  @import './input-focus.css';
2
3
  @import './surface.css';
3
4
  @import './file-icons.css';
@@ -20,23 +21,6 @@
20
21
  @import './themes/dark.css';
21
22
  @import './themes/shell-presets.generated.css';
22
23
 
23
- :root {
24
- --radius: 0.375rem;
25
- --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
26
- --font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', Menlo, Monaco, Consolas, monospace;
27
- --floe-type-caption: 0.6875rem;
28
- --floe-type-control: 0.8125rem;
29
- --floe-type-body: 0.875rem;
30
- --floe-type-heading: 1rem;
31
- --floe-space-1: 0.25rem;
32
- --floe-space-2: 0.5rem;
33
- --floe-space-3: 0.75rem;
34
- --floe-space-4: 1rem;
35
- --floe-space-6: 1.5rem;
36
- --floe-radius-control: 0.375rem;
37
- --floe-radius-group: 0.5rem;
38
- --floe-radius-floating: 12px;
39
- }
40
24
 
41
25
  /*
42
26
  * TailwindCSS v4 requires @theme for utilities. However, CSS variable
@@ -0,0 +1,18 @@
1
+ /* Shared typography, spacing and shape; no layout or palette ownership. */
2
+ :root {
3
+ --radius: 0.375rem;
4
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
5
+ --font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', Menlo, Monaco, Consolas, monospace;
6
+ --floe-type-caption: 0.6875rem;
7
+ --floe-type-control: 0.8125rem;
8
+ --floe-type-body: 0.875rem;
9
+ --floe-type-heading: 1rem;
10
+ --floe-space-1: 0.25rem;
11
+ --floe-space-2: 0.5rem;
12
+ --floe-space-3: 0.75rem;
13
+ --floe-space-4: 1rem;
14
+ --floe-space-6: 1.5rem;
15
+ --floe-radius-control: 0.375rem;
16
+ --floe-radius-group: 0.5rem;
17
+ --floe-radius-floating: 12px;
18
+ }
@@ -0,0 +1,49 @@
1
+ /** Disposable presentation snapshots. Authorization and polling belong to the consumer. */
2
+ export interface ResourceCacheStorage {
3
+ /** Reads also update the entry's last-access time. */
4
+ get(key: string): Promise<string | null>;
5
+ set(key: string, value: string): Promise<void>;
6
+ remove(key: string): Promise<void>;
7
+ list(): Promise<readonly {
8
+ key: string;
9
+ bytes: number;
10
+ lastAccessedAt: number;
11
+ }[]>;
12
+ }
13
+ export interface ResourceSnapshot<T> {
14
+ readonly data: T | undefined;
15
+ readonly refreshing: boolean;
16
+ readonly stale: boolean;
17
+ readonly error: unknown;
18
+ }
19
+ export interface CachedResource<T> {
20
+ snapshot(): ResourceSnapshot<T>;
21
+ subscribe(listener: () => void): () => void;
22
+ hydrate(): Promise<void>;
23
+ refresh(fetcher: (signal: AbortSignal) => Promise<T>): Promise<T>;
24
+ set(value: T): void;
25
+ /** Keeps the visible snapshot by default, but removes its durable copy. */
26
+ invalidate(clear?: boolean): void;
27
+ }
28
+ export interface CachedResourceDefinition<T> {
29
+ scope: string;
30
+ key: string;
31
+ version: number;
32
+ /** Validate and decode untrusted persisted content; throw to reject it. */
33
+ decode(value: unknown): T;
34
+ /** Persist an explicit presentation projection when live data contains private fields. */
35
+ persist?(value: T): unknown;
36
+ }
37
+ export interface ResourceCache {
38
+ resource<T>(definition: CachedResourceDefinition<T>): CachedResource<T>;
39
+ clearScope(scope: string): Promise<void>;
40
+ flush(): Promise<void>;
41
+ dispose(): void;
42
+ }
43
+ export declare function createResourceCache(options: {
44
+ storage: ResourceCacheStorage;
45
+ maxBytes?: number;
46
+ writeDelayMs?: number;
47
+ }): ResourceCache;
48
+ /** A dedicated database containing disposable snapshots only, never application settings. */
49
+ export declare function createIndexedDBResourceCacheStorage(name?: string): ResourceCacheStorage;
@@ -0,0 +1,162 @@
1
+ function I(m) {
2
+ const d = m.storage, E = Math.max(0, m.maxBytes ?? 32 * 1024 * 1024), v = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map();
3
+ let n, t = Promise.resolve(), o = !1;
4
+ const i = (e) => (t = t.then(e).catch(() => {
5
+ }), t), h = async () => {
6
+ const e = [...await d.list()].sort((l, s) => l.lastAccessedAt - s.lastAccessedAt);
7
+ let r = e.reduce((l, s) => l + s.bytes, 0);
8
+ for (const l of e) {
9
+ if (r <= E) break;
10
+ await d.remove(l.key), r -= l.bytes;
11
+ }
12
+ }, f = async () => {
13
+ clearTimeout(n), n = void 0;
14
+ const e = [...c];
15
+ c.clear(), e.length && i(async () => {
16
+ for (const [r, l] of e)
17
+ if (l.valid())
18
+ try {
19
+ await d.set(r, l.value), l.stored();
20
+ } catch {
21
+ }
22
+ await h();
23
+ }), await t;
24
+ }, k = (e, r, l, s) => {
25
+ c.set(e, { value: r, valid: l, stored: s }), n === void 0 && (n = setTimeout(() => {
26
+ f();
27
+ }, m.writeDelayMs ?? 100));
28
+ };
29
+ return {
30
+ resource: (e) => {
31
+ if (o) throw new Error("Resource cache is disposed");
32
+ if (!e.scope || !e.key || !Number.isSafeInteger(e.version)) throw new Error("Invalid resource identity");
33
+ const r = JSON.stringify([e.scope, e.key, e.version]), l = v.get(r);
34
+ if (l) return l.handle;
35
+ let s = { data: void 0, refreshing: !1, stale: !0, error: void 0 };
36
+ const S = /* @__PURE__ */ new Set();
37
+ let x = 0, y = 0, q, D, w, p;
38
+ const b = () => {
39
+ for (const a of S) a();
40
+ }, R = (a) => {
41
+ ++x, s = { data: a, refreshing: s.refreshing, stale: !1, error: void 0 };
42
+ try {
43
+ const u = JSON.stringify({ version: e.version, data: e.persist ? e.persist(a) : a });
44
+ q = u, u !== D ? k(r, u, () => q === u, () => {
45
+ D = u;
46
+ }) : c.delete(r);
47
+ } catch {
48
+ }
49
+ b();
50
+ }, O = x, P = d.get(r).then((a) => {
51
+ if (!(o || x !== O || a === null))
52
+ try {
53
+ const u = JSON.parse(a);
54
+ if (u.version !== e.version) throw new Error("Unsupported snapshot");
55
+ const g = e.decode(u.data);
56
+ s = { ...s, data: g, stale: !0 }, q = a, D = a, b();
57
+ } catch {
58
+ i(() => d.remove(r));
59
+ }
60
+ }).catch(() => {
61
+ }), N = {
62
+ snapshot: () => s,
63
+ subscribe: (a) => (S.add(a), () => {
64
+ S.delete(a);
65
+ }),
66
+ hydrate: () => P,
67
+ refresh: (a) => {
68
+ if (p) return p;
69
+ const u = ++y, g = new AbortController();
70
+ return w = g, s = { ...s, refreshing: !0, error: void 0 }, b(), p = Promise.resolve().then(() => a(g.signal)).then((A) => (!o && u === y && !g.signal.aborted && R(A), A), (A) => {
71
+ throw !o && u === y && !g.signal.aborted && (s = { ...s, stale: !0, error: A }, b()), A;
72
+ }).finally(() => {
73
+ u === y && (p = void 0, w = void 0, s = { ...s, refreshing: !1 }, b());
74
+ }), p;
75
+ },
76
+ set: (a) => {
77
+ ++y, w?.abort(), p = void 0, s = { ...s, refreshing: !1 }, R(a);
78
+ },
79
+ invalidate: (a = !1) => {
80
+ ++x, ++y, w?.abort(), w = void 0, p = void 0, q = void 0, D = void 0, c.delete(r), s = { data: a ? void 0 : s.data, refreshing: !1, stale: !0, error: void 0 }, b(), i(() => d.remove(r));
81
+ }
82
+ };
83
+ return v.set(r, { scope: e.scope, handle: N, stop: () => {
84
+ ++y, w?.abort(), S.clear();
85
+ } }), N;
86
+ },
87
+ flush: f,
88
+ clearScope: async (e) => {
89
+ for (const r of v.values()) r.scope === e && r.handle.invalidate(!0);
90
+ await i(async () => {
91
+ for (const r of await d.list())
92
+ try {
93
+ JSON.parse(r.key)[0] === e && await d.remove(r.key);
94
+ } catch {
95
+ }
96
+ });
97
+ },
98
+ dispose: () => {
99
+ if (!o) {
100
+ o = !0;
101
+ for (const e of v.values()) e.stop();
102
+ f(), v.clear();
103
+ }
104
+ }
105
+ };
106
+ }
107
+ function J(m = "floe-resource-cache") {
108
+ let d;
109
+ const E = () => d ??= new Promise((c, n) => {
110
+ const t = indexedDB.open(m, 1);
111
+ t.onupgradeneeded = () => t.result.createObjectStore("snapshots", { keyPath: "key" }), t.onsuccess = () => {
112
+ const o = t.result;
113
+ o.onversionchange = () => {
114
+ o.close(), d = void 0;
115
+ }, c(o);
116
+ }, t.onerror = () => {
117
+ d = void 0, n(t.error);
118
+ }, t.onblocked = () => {
119
+ d = void 0, n(new Error("Resource cache database is blocked"));
120
+ };
121
+ }), v = async (c, n) => {
122
+ const t = await E();
123
+ return new Promise((o, i) => {
124
+ const h = t.transaction("snapshots", c);
125
+ let f;
126
+ h.oncomplete = () => o(f), h.onerror = () => i(h.error), h.onabort = () => i(h.error ?? new Error("Resource cache transaction aborted")), n(h.objectStore("snapshots"), (k) => {
127
+ f = k;
128
+ });
129
+ });
130
+ };
131
+ return {
132
+ get: (c) => v("readwrite", (n, t) => {
133
+ const o = n.get(c);
134
+ o.onsuccess = () => {
135
+ const i = o.result;
136
+ i && n.put({ ...i, lastAccessedAt: Date.now() }), t(i?.value ?? null);
137
+ };
138
+ }),
139
+ set: (c, n) => v("readwrite", (t, o) => {
140
+ t.put({ key: c, value: n, bytes: new TextEncoder().encode(n).byteLength, lastAccessedAt: Date.now() }), o(void 0);
141
+ }),
142
+ remove: (c) => v("readwrite", (n, t) => {
143
+ n.delete(c), t(void 0);
144
+ }),
145
+ list: () => v("readonly", (c, n) => {
146
+ const t = [], o = c.openCursor();
147
+ o.onsuccess = () => {
148
+ const i = o.result;
149
+ if (!i) {
150
+ n(t);
151
+ return;
152
+ }
153
+ const { key: h, bytes: f, lastAccessedAt: k } = i.value;
154
+ t.push({ key: h, bytes: f, lastAccessedAt: k }), i.continue();
155
+ };
156
+ })
157
+ };
158
+ }
159
+ export {
160
+ J as createIndexedDBResourceCacheStorage,
161
+ I as createResourceCache
162
+ };
@@ -0,0 +1,11 @@
1
+ /* First-party standalone documents: the same themes, geometry tokens and
2
+ * material as Floe, without the shell, Tailwind utilities or renderer runtime.
3
+ * Set .light/.dark, data-floe-shell-theme and data-floe-surface-style on <html>.
4
+ * Applications own layout and declare data-floe-surface on visible boundaries.
5
+ */
6
+ @import './primitives.css';
7
+ @import './themes/light.css';
8
+ @import './themes/dark.css';
9
+ @import './themes/shell-presets.generated.css';
10
+ @import './surface.css';
11
+ @import './input-focus.css';