@zaflun/lumio-sdk 0.1.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/index.js ADDED
@@ -0,0 +1,876 @@
1
+ // src/core/lumio.tsx
2
+ import { createRoot } from "react-dom/client";
3
+ var RENDER_TIMEOUT_MS = 1e4;
4
+ var hasRendered = false;
5
+ var renderTimeout = null;
6
+ function startRenderTimeout() {
7
+ if (renderTimeout) return;
8
+ renderTimeout = setTimeout(() => {
9
+ if (!hasRendered) {
10
+ console.error(
11
+ "[Lumio SDK] Extension did not call Lumio.render() within 10 seconds. Terminating."
12
+ );
13
+ window.parent.postMessage(
14
+ {
15
+ type: "ERROR",
16
+ code: "RENDER_TIMEOUT",
17
+ message: "Extension did not render within 10 seconds"
18
+ },
19
+ "*"
20
+ );
21
+ }
22
+ }, RENDER_TIMEOUT_MS);
23
+ }
24
+ if (typeof window !== "undefined") {
25
+ startRenderTimeout();
26
+ }
27
+ var Lumio = {
28
+ render(element, options) {
29
+ hasRendered = true;
30
+ if (renderTimeout) {
31
+ clearTimeout(renderTimeout);
32
+ renderTimeout = null;
33
+ }
34
+ let rootElement = document.getElementById("lumio-root");
35
+ if (!rootElement) {
36
+ rootElement = document.createElement("div");
37
+ rootElement.id = "lumio-root";
38
+ document.body.appendChild(rootElement);
39
+ }
40
+ const root = createRoot(rootElement);
41
+ root.render(element);
42
+ window.parent.postMessage({ type: "READY" }, "*");
43
+ void options;
44
+ }
45
+ };
46
+
47
+ // src/bridge/WorkerBridge.ts
48
+ var WorkerBridge = class {
49
+ notificationHandlers = /* @__PURE__ */ new Map();
50
+ requestHandlers = /* @__PURE__ */ new Map();
51
+ pendingRequests = /* @__PURE__ */ new Map();
52
+ requestCounter = 0;
53
+ requestTimeout;
54
+ messageListener = null;
55
+ destroyed = false;
56
+ constructor(options) {
57
+ this.requestTimeout = options?.requestTimeout ?? 3e4;
58
+ this.messageListener = this.handleMessage.bind(this);
59
+ globalThis.addEventListener("message", this.messageListener);
60
+ }
61
+ notify(method, params) {
62
+ const msg = {
63
+ jsonrpc: "2.0",
64
+ method,
65
+ ...params !== void 0 ? { params } : {}
66
+ };
67
+ globalThis.postMessage(msg);
68
+ }
69
+ request(method, params) {
70
+ const id = `req_${++this.requestCounter}`;
71
+ const msg = {
72
+ jsonrpc: "2.0",
73
+ id,
74
+ method,
75
+ ...params !== void 0 ? { params } : {}
76
+ };
77
+ return new Promise((resolve, reject) => {
78
+ const timer = setTimeout(() => {
79
+ this.pendingRequests.delete(id);
80
+ reject(new Error("Request timeout"));
81
+ }, this.requestTimeout);
82
+ this.pendingRequests.set(id, { resolve, reject, timer });
83
+ globalThis.postMessage(msg);
84
+ });
85
+ }
86
+ onNotification(method, handler) {
87
+ if (!this.notificationHandlers.has(method)) {
88
+ this.notificationHandlers.set(method, /* @__PURE__ */ new Set());
89
+ }
90
+ this.notificationHandlers.get(method).add(handler);
91
+ return () => {
92
+ this.notificationHandlers.get(method)?.delete(handler);
93
+ };
94
+ }
95
+ onRequest(method, handler) {
96
+ this.requestHandlers.set(method, handler);
97
+ }
98
+ destroy() {
99
+ this.destroyed = true;
100
+ if (this.messageListener) {
101
+ globalThis.removeEventListener("message", this.messageListener);
102
+ this.messageListener = null;
103
+ }
104
+ for (const { timer, reject } of this.pendingRequests.values()) {
105
+ if (timer) clearTimeout(timer);
106
+ reject(new Error("Bridge destroyed"));
107
+ }
108
+ this.pendingRequests.clear();
109
+ this.notificationHandlers.clear();
110
+ this.requestHandlers.clear();
111
+ }
112
+ handleMessage(event) {
113
+ if (this.destroyed) return;
114
+ const data = event.data;
115
+ if (!data || typeof data !== "object" || data.jsonrpc !== "2.0") return;
116
+ if ("id" in data && !("method" in data)) {
117
+ const pending = this.pendingRequests.get(data.id);
118
+ if (pending) {
119
+ this.pendingRequests.delete(data.id);
120
+ if (pending.timer) clearTimeout(pending.timer);
121
+ if (data.error) {
122
+ pending.reject(new Error(data.error.message));
123
+ } else {
124
+ pending.resolve(data.result);
125
+ }
126
+ }
127
+ return;
128
+ }
129
+ if ("id" in data && "method" in data) {
130
+ const handler = this.requestHandlers.get(data.method);
131
+ if (handler) {
132
+ handler(data.params).then((result) => {
133
+ const response = { jsonrpc: "2.0", id: data.id, result };
134
+ globalThis.postMessage(response);
135
+ }).catch((err) => {
136
+ const response = {
137
+ jsonrpc: "2.0",
138
+ id: data.id,
139
+ error: { code: -32603, message: err.message }
140
+ };
141
+ globalThis.postMessage(response);
142
+ });
143
+ }
144
+ return;
145
+ }
146
+ if ("method" in data && !("id" in data)) {
147
+ const handlers = this.notificationHandlers.get(data.method);
148
+ if (handlers) {
149
+ for (const handler of handlers) {
150
+ handler(data.params);
151
+ }
152
+ }
153
+ }
154
+ }
155
+ };
156
+
157
+ // src/components/Box.tsx
158
+ import React from "react";
159
+ function Box({ children, style }) {
160
+ return React.createElement("Box", { style }, children);
161
+ }
162
+
163
+ // src/components/VStack.tsx
164
+ import React2 from "react";
165
+ function VStack({ children, gap, style }) {
166
+ return React2.createElement("VStack", { gap, style }, children);
167
+ }
168
+
169
+ // src/components/HStack.tsx
170
+ import React3 from "react";
171
+ function HStack({ children, gap, style }) {
172
+ return React3.createElement("HStack", { gap, style }, children);
173
+ }
174
+
175
+ // src/components/CompactView.tsx
176
+ import React4 from "react";
177
+ function CompactView({ title, children }) {
178
+ return React4.createElement("CompactView", { title }, children);
179
+ }
180
+
181
+ // src/components/List.tsx
182
+ import React5 from "react";
183
+ function List({ items, renderItem, emptyText }) {
184
+ if (items.length === 0) {
185
+ return React5.createElement("List", { emptyText, items: [] });
186
+ }
187
+ const children = items.map((item, index) => renderItem(item, index));
188
+ return React5.createElement("List", { items, emptyText }, ...children);
189
+ }
190
+
191
+ // src/components/Text.tsx
192
+ import React6 from "react";
193
+ function Text({ content, variant = "default" }) {
194
+ return React6.createElement("Text", { content, variant });
195
+ }
196
+
197
+ // src/components/Image.tsx
198
+ import React7 from "react";
199
+ function Image({ src, alt, objectFit }) {
200
+ return React7.createElement("Image", { src, alt, objectFit });
201
+ }
202
+
203
+ // src/components/Button.tsx
204
+ import React8 from "react";
205
+ function Button({ label, onClick, variant = "default", disabled = false }) {
206
+ return React8.createElement("Button", { label, onClick, variant, disabled });
207
+ }
208
+
209
+ // src/components/Toggle.tsx
210
+ import React9 from "react";
211
+ function Toggle({ label, checked, onChange }) {
212
+ return React9.createElement("Toggle", { label, checked, onChange });
213
+ }
214
+
215
+ // src/components/TextField.tsx
216
+ import React10 from "react";
217
+ function TextField({ label, value, onChange, placeholder }) {
218
+ return React10.createElement("TextField", { label, value, onChange, placeholder });
219
+ }
220
+
221
+ // src/components/TextArea.tsx
222
+ import React11 from "react";
223
+ function TextArea({ label, value, onChange, placeholder, rows = 3 }) {
224
+ return React11.createElement("TextArea", { label, value, onChange, placeholder, rows });
225
+ }
226
+
227
+ // src/components/NumberField.tsx
228
+ import React12 from "react";
229
+ function NumberField({ label, value, onChange, min, max, step }) {
230
+ return React12.createElement("NumberField", { label, value, onChange, min, max, step });
231
+ }
232
+
233
+ // src/components/Dropdown.tsx
234
+ import React13 from "react";
235
+ function Dropdown({ label, value, options, onChange }) {
236
+ return React13.createElement("Dropdown", { label, value, options, onChange });
237
+ }
238
+
239
+ // src/components/Slider.tsx
240
+ import React14 from "react";
241
+ function Slider({ label, value, onChange, min, max, step = 1 }) {
242
+ return React14.createElement("Slider", { label, value, onChange, min, max, step });
243
+ }
244
+
245
+ // src/hooks/useExtensionStorage.ts
246
+ import { useState, useEffect, useCallback } from "react";
247
+
248
+ // src/renderer/bridge-context.ts
249
+ var bridgeInstance = null;
250
+ function getBridge() {
251
+ if (!bridgeInstance) {
252
+ bridgeInstance = new WorkerBridge();
253
+ }
254
+ return bridgeInstance;
255
+ }
256
+
257
+ // src/hooks/useExtensionStorage.ts
258
+ import { HOST_METHODS, WORKER_METHODS } from "@zaflun/lumio-protocol";
259
+ function useExtensionStorage(key, initialValue) {
260
+ const [storage, setStorageState] = useState(initialValue);
261
+ useEffect(() => {
262
+ const bridge = getBridge();
263
+ const unsub = bridge.onNotification(
264
+ HOST_METHODS.STORAGE_UPDATE,
265
+ (params) => {
266
+ const p = params;
267
+ if (p.key === key) {
268
+ setStorageState(p.value);
269
+ }
270
+ }
271
+ );
272
+ bridge.request(WORKER_METHODS.STORAGE_GET, { key }).then((result) => {
273
+ const r = result;
274
+ if (r && r.value !== void 0) {
275
+ setStorageState(r.value);
276
+ }
277
+ }).catch(() => {
278
+ });
279
+ return unsub;
280
+ }, [key]);
281
+ const setStorage = useCallback(
282
+ (value) => {
283
+ setStorageState(value);
284
+ const bridge = getBridge();
285
+ bridge.notify(WORKER_METHODS.STORAGE_SET, { key, value });
286
+ },
287
+ [key]
288
+ );
289
+ return [storage, setStorage];
290
+ }
291
+
292
+ // src/hooks/useVisionState.ts
293
+ import { useState as useState2, useCallback as useCallback2 } from "react";
294
+ import { WORKER_METHODS as WORKER_METHODS2 } from "@zaflun/lumio-protocol";
295
+ function useVisionState(key, defaultValue) {
296
+ const [value, setValueState] = useState2(defaultValue);
297
+ const setValue = useCallback2(
298
+ (newValue) => {
299
+ setValueState(newValue);
300
+ const bridge = getBridge();
301
+ bridge.notify(WORKER_METHODS2.STORAGE_SET, { key, value: newValue });
302
+ },
303
+ [key]
304
+ );
305
+ return [value, setValue];
306
+ }
307
+
308
+ // src/hooks/useExtensionContext.ts
309
+ import { useState as useState3, useEffect as useEffect2 } from "react";
310
+ import { HOST_METHODS as HOST_METHODS2 } from "@zaflun/lumio-protocol";
311
+ var defaultContext = {
312
+ extensionId: null,
313
+ target: null,
314
+ overlayId: null,
315
+ interactiveUrl: null
316
+ };
317
+ function useExtensionContext() {
318
+ const [context, setContext] = useState3(defaultContext);
319
+ useEffect2(() => {
320
+ const bridge = getBridge();
321
+ const unsub = bridge.onNotification(
322
+ HOST_METHODS2.LIFECYCLE_INIT,
323
+ (params) => {
324
+ const p = params;
325
+ setContext({
326
+ extensionId: p.extensionId ?? null,
327
+ target: p.target ?? null,
328
+ overlayId: p.installId ?? null,
329
+ interactiveUrl: p.interactiveUrl ?? null
330
+ });
331
+ }
332
+ );
333
+ return unsub;
334
+ }, []);
335
+ return context;
336
+ }
337
+
338
+ // src/hooks/useLumioEvent.ts
339
+ import { useState as useState4, useEffect as useEffect3 } from "react";
340
+ import { HOST_METHODS as HOST_METHODS3 } from "@zaflun/lumio-protocol";
341
+ function useLumioEvent(eventType) {
342
+ const [eventData, setEventData] = useState4(null);
343
+ useEffect3(() => {
344
+ const bridge = getBridge();
345
+ const unsub = bridge.onNotification(
346
+ HOST_METHODS3.EVENT_PLATFORM,
347
+ (params) => {
348
+ const p = params;
349
+ if (p.eventType === eventType) {
350
+ setEventData(p.data ?? null);
351
+ }
352
+ }
353
+ );
354
+ return unsub;
355
+ }, [eventType]);
356
+ return eventData;
357
+ }
358
+
359
+ // src/hooks/useLumioConfig.ts
360
+ import { useState as useState5, useEffect as useEffect4, useCallback as useCallback3 } from "react";
361
+ import { HOST_METHODS as HOST_METHODS4 } from "@zaflun/lumio-protocol";
362
+ function useLumioConfig() {
363
+ const [config, setConfigState] = useState5({});
364
+ useEffect4(() => {
365
+ const bridge = getBridge();
366
+ const unsub = bridge.onNotification(
367
+ HOST_METHODS4.LIFECYCLE_INIT,
368
+ (params) => {
369
+ const p = params;
370
+ setConfigState({
371
+ extension_id: p.extensionId,
372
+ install_id: p.installId,
373
+ account_id: p.accountId,
374
+ target: p.target,
375
+ permissions: p.permissions,
376
+ settings: p.settings
377
+ });
378
+ }
379
+ );
380
+ return unsub;
381
+ }, []);
382
+ const setConfig = useCallback3(
383
+ (newConfig) => {
384
+ setConfigState(newConfig);
385
+ },
386
+ []
387
+ );
388
+ return [config, setConfig];
389
+ }
390
+
391
+ // src/hooks/useLumioTheme.ts
392
+ import { useState as useState6, useEffect as useEffect5 } from "react";
393
+ import { HOST_METHODS as HOST_METHODS5 } from "@zaflun/lumio-protocol";
394
+ var DEFAULT_THEME = {
395
+ colors: {
396
+ primary: "#6366f1",
397
+ secondary: "#8b5cf6",
398
+ accent: "#06b6d4",
399
+ background: "transparent",
400
+ surface: "rgba(15, 23, 42, 0.8)",
401
+ text: "#f8fafc",
402
+ muted: "#94a3b8",
403
+ border: "rgba(148, 163, 184, 0.2)"
404
+ },
405
+ fonts: {
406
+ heading: "inherit",
407
+ body: "inherit"
408
+ },
409
+ borderRadius: {
410
+ sm: "4px",
411
+ md: "8px",
412
+ lg: "12px"
413
+ },
414
+ spacing: 8
415
+ };
416
+ function useLumioTheme() {
417
+ const [theme, setTheme] = useState6(DEFAULT_THEME);
418
+ useEffect5(() => {
419
+ const bridge = getBridge();
420
+ const unsubInit = bridge.onNotification(
421
+ HOST_METHODS5.LIFECYCLE_INIT,
422
+ (params) => {
423
+ const p = params;
424
+ if (p.theme) {
425
+ setTheme((prev) => ({ ...prev, ...p.theme }));
426
+ }
427
+ }
428
+ );
429
+ const unsubTheme = bridge.onNotification(
430
+ HOST_METHODS5.THEME_CHANGE,
431
+ (params) => {
432
+ const p = params;
433
+ if (p.theme) {
434
+ setTheme((prev) => ({ ...prev, ...p.theme }));
435
+ }
436
+ }
437
+ );
438
+ return () => {
439
+ unsubInit();
440
+ unsubTheme();
441
+ };
442
+ }, []);
443
+ return theme;
444
+ }
445
+
446
+ // src/hooks/useLumioIdentity.ts
447
+ import { useState as useState7, useEffect as useEffect6 } from "react";
448
+ import { HOST_METHODS as HOST_METHODS6 } from "@zaflun/lumio-protocol";
449
+ var defaultIdentity = {
450
+ userId: null,
451
+ accountId: null,
452
+ role: null
453
+ };
454
+ function useLumioIdentity() {
455
+ const [identity, setIdentity] = useState7(defaultIdentity);
456
+ useEffect6(() => {
457
+ const bridge = getBridge();
458
+ const unsub = bridge.onNotification(
459
+ HOST_METHODS6.LIFECYCLE_INIT,
460
+ (params) => {
461
+ const p = params;
462
+ setIdentity({
463
+ userId: p.userId ?? null,
464
+ accountId: p.accountId ?? null,
465
+ role: p.role ?? null
466
+ });
467
+ }
468
+ );
469
+ return unsub;
470
+ }, []);
471
+ return identity;
472
+ }
473
+
474
+ // src/hooks/useLumioAction.ts
475
+ import { useState as useState8, useCallback as useCallback4, useRef } from "react";
476
+ function useLumioAction(action) {
477
+ const [data, setData] = useState8(null);
478
+ const [isLoading, setIsLoading] = useState8(false);
479
+ const [error, setError] = useState8(null);
480
+ const actionRef = useRef(action);
481
+ actionRef.current = action;
482
+ const execute = useCallback4(
483
+ (params = {}) => {
484
+ setIsLoading(true);
485
+ setError(null);
486
+ const bridge = getBridge();
487
+ bridge.request("action.execute", { action, params }).then((result) => {
488
+ setIsLoading(false);
489
+ setData(result ?? null);
490
+ setError(null);
491
+ }).catch((err) => {
492
+ setIsLoading(false);
493
+ setError(err instanceof Error ? err.message : "Unknown error");
494
+ setData(null);
495
+ });
496
+ },
497
+ [action]
498
+ );
499
+ return { execute, data, isLoading, error };
500
+ }
501
+
502
+ // src/hooks/useQuery.ts
503
+ import { useState as useState9, useEffect as useEffect7, useCallback as useCallback5, useRef as useRef2 } from "react";
504
+ import { WORKER_METHODS as WORKER_METHODS3 } from "@zaflun/lumio-protocol";
505
+ function useQuery(functionName, params) {
506
+ const [data, setData] = useState9(null);
507
+ const [isLoading, setIsLoading] = useState9(false);
508
+ const [error, setError] = useState9(null);
509
+ const fnRef = useRef2(functionName);
510
+ fnRef.current = functionName;
511
+ const sendQuery = useCallback5(() => {
512
+ setIsLoading(true);
513
+ setError(null);
514
+ const bridge = getBridge();
515
+ bridge.request(WORKER_METHODS3.SERVER_QUERY, { fn: functionName, params: params ?? {} }).then((result) => {
516
+ setIsLoading(false);
517
+ setData(result ?? null);
518
+ setError(null);
519
+ }).catch((err) => {
520
+ setIsLoading(false);
521
+ setError(err instanceof Error ? err.message : "Unknown error");
522
+ setData(null);
523
+ });
524
+ }, [functionName, params]);
525
+ useEffect7(() => {
526
+ sendQuery();
527
+ }, [functionName]);
528
+ return { data, isLoading, error, refetch: sendQuery };
529
+ }
530
+
531
+ // src/hooks/useMutation.ts
532
+ import { useState as useState10, useCallback as useCallback6 } from "react";
533
+ import { WORKER_METHODS as WORKER_METHODS4 } from "@zaflun/lumio-protocol";
534
+ function useMutation(functionName) {
535
+ const [data, setData] = useState10(null);
536
+ const [isLoading, setIsLoading] = useState10(false);
537
+ const [error, setError] = useState10(null);
538
+ const sendMutation = useCallback6(
539
+ (params = {}) => {
540
+ setIsLoading(true);
541
+ setError(null);
542
+ const bridge = getBridge();
543
+ return bridge.request(WORKER_METHODS4.SERVER_MUTATION, { fn: functionName, params }).then((result) => {
544
+ setIsLoading(false);
545
+ setData(result ?? null);
546
+ setError(null);
547
+ return result;
548
+ }).catch((err) => {
549
+ setIsLoading(false);
550
+ const message = err instanceof Error ? err.message : "Unknown error";
551
+ setError(message);
552
+ setData(null);
553
+ throw err;
554
+ });
555
+ },
556
+ [functionName]
557
+ );
558
+ const mutateAsync = useCallback6(
559
+ (params) => sendMutation(params),
560
+ [sendMutation]
561
+ );
562
+ const mutate = useCallback6(
563
+ (params) => {
564
+ sendMutation(params).catch(() => {
565
+ });
566
+ },
567
+ [sendMutation]
568
+ );
569
+ return { mutate, mutateAsync, data, isLoading, error };
570
+ }
571
+
572
+ // src/animation/keyframes.ts
573
+ var registry = /* @__PURE__ */ new Map();
574
+ var counter = 0;
575
+ function camelToKebab(str) {
576
+ return str.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);
577
+ }
578
+ function keyframesToCSS(name, def) {
579
+ const stops = Object.entries(def).map(([stop, block]) => {
580
+ const props = Object.entries(block).map(([prop, value]) => ` ${camelToKebab(prop)}: ${value};`).join("\n");
581
+ return ` ${stop} {
582
+ ${props}
583
+ }`;
584
+ }).join("\n");
585
+ return `@keyframes ${name} {
586
+ ${stops}
587
+ }`;
588
+ }
589
+ function defineKeyframes(definition) {
590
+ const hash = JSON.stringify(definition);
591
+ const existing = registry.get(hash);
592
+ if (existing !== void 0) {
593
+ return existing;
594
+ }
595
+ const name = `lumio-kf-${counter++}`;
596
+ registry.set(hash, name);
597
+ return name;
598
+ }
599
+ function getRegisteredCSS() {
600
+ const parts = [];
601
+ for (const [hash, name] of registry.entries()) {
602
+ const def = JSON.parse(hash);
603
+ parts.push(keyframesToCSS(name, def));
604
+ }
605
+ return parts.join("\n\n");
606
+ }
607
+ function flushKeyframes() {
608
+ const css = getRegisteredCSS();
609
+ if (!css) return;
610
+ try {
611
+ getBridge().notify("ui.keyframes", { css });
612
+ } catch {
613
+ }
614
+ }
615
+
616
+ // src/animation/presets.ts
617
+ var ANIMATION_PRESETS = {
618
+ // Basic
619
+ fadeIn: { from: { opacity: "0" }, to: { opacity: "1" } },
620
+ fadeOut: { from: { opacity: "1" }, to: { opacity: "0" } },
621
+ zoomIn: { from: { opacity: "0", transform: "scale(0.5)" }, to: { opacity: "1", transform: "scale(1)" } },
622
+ zoomOut: { from: { opacity: "1", transform: "scale(1)" }, to: { opacity: "0", transform: "scale(0.5)" } },
623
+ // Slide In/Out
624
+ slideLeftIn: { from: { opacity: "0", transform: "translateX(-100%)" }, to: { opacity: "1", transform: "translateX(0)" } },
625
+ slideLeftOut: { from: { opacity: "1", transform: "translateX(0)" }, to: { opacity: "0", transform: "translateX(-100%)" } },
626
+ slideRightIn: { from: { opacity: "0", transform: "translateX(100%)" }, to: { opacity: "1", transform: "translateX(0)" } },
627
+ slideRightOut: { from: { opacity: "1", transform: "translateX(0)" }, to: { opacity: "0", transform: "translateX(100%)" } },
628
+ slideUpIn: { from: { opacity: "0", transform: "translateY(-100%)" }, to: { opacity: "1", transform: "translateY(0)" } },
629
+ slideUpOut: { from: { opacity: "1", transform: "translateY(0)" }, to: { opacity: "0", transform: "translateY(-100%)" } },
630
+ slideDownIn: { from: { opacity: "0", transform: "translateY(100%)" }, to: { opacity: "1", transform: "translateY(0)" } },
631
+ slideDownOut: { from: { opacity: "1", transform: "translateY(0)" }, to: { opacity: "0", transform: "translateY(100%)" } },
632
+ // Push In/Out (no opacity change)
633
+ pushLeftIn: { from: { transform: "translateX(100%)" }, to: { transform: "translateX(0)" } },
634
+ pushLeftOut: { from: { transform: "translateX(0)" }, to: { transform: "translateX(-100%)" } },
635
+ pushRightIn: { from: { transform: "translateX(-100%)" }, to: { transform: "translateX(0)" } },
636
+ pushRightOut: { from: { transform: "translateX(0)" }, to: { transform: "translateX(100%)" } },
637
+ pushUpIn: { from: { transform: "translateY(100%)" }, to: { transform: "translateY(0)" } },
638
+ pushUpOut: { from: { transform: "translateY(0)" }, to: { transform: "translateY(-100%)" } },
639
+ pushDownIn: { from: { transform: "translateY(-100%)" }, to: { transform: "translateY(0)" } },
640
+ pushDownOut: { from: { transform: "translateY(0)" }, to: { transform: "translateY(100%)" } },
641
+ // Loop
642
+ pulse: {
643
+ "0%": { transform: "scale(1)" },
644
+ "50%": { transform: "scale(1.05)" },
645
+ "100%": { transform: "scale(1)" }
646
+ },
647
+ bounce: {
648
+ "0%": { transform: "translateY(0)" },
649
+ "50%": { transform: "translateY(-10px)" },
650
+ "100%": { transform: "translateY(0)" }
651
+ }
652
+ };
653
+ function getPreset(name) {
654
+ return defineKeyframes(ANIMATION_PRESETS[name]);
655
+ }
656
+
657
+ // src/animation/Animated.tsx
658
+ import React15, { useEffect as useEffect8, useRef as useRef3, useState as useState11 } from "react";
659
+ function resolveAnimation(name) {
660
+ if (name === void 0) return void 0;
661
+ try {
662
+ return getPreset(name);
663
+ } catch {
664
+ return name;
665
+ }
666
+ }
667
+ function Animated({
668
+ children,
669
+ in: inProp,
670
+ out: outProp,
671
+ loop: loopProp,
672
+ duration = 300,
673
+ loopDuration = 1e3,
674
+ easing = "ease",
675
+ delay = 0,
676
+ visible = true,
677
+ onAnimationEnd
678
+ }) {
679
+ const [phase, setPhase] = useState11(() => visible ? "in" : "idle");
680
+ const prevVisibleRef = useRef3(visible);
681
+ const timerRef = useRef3(null);
682
+ function clearTimer() {
683
+ if (timerRef.current !== null) {
684
+ clearTimeout(timerRef.current);
685
+ timerRef.current = null;
686
+ }
687
+ }
688
+ useEffect8(() => {
689
+ const prevVisible = prevVisibleRef.current;
690
+ prevVisibleRef.current = visible;
691
+ if (visible && !prevVisible) {
692
+ clearTimer();
693
+ setPhase("in");
694
+ } else if (!visible && prevVisible) {
695
+ clearTimer();
696
+ setPhase("out");
697
+ }
698
+ }, [visible]);
699
+ useEffect8(() => {
700
+ if (phase === "in") {
701
+ const totalDuration = duration + delay;
702
+ if (loopProp !== void 0) {
703
+ timerRef.current = setTimeout(() => {
704
+ setPhase("loop");
705
+ }, totalDuration);
706
+ } else {
707
+ if (onAnimationEnd) {
708
+ timerRef.current = setTimeout(() => {
709
+ onAnimationEnd();
710
+ }, totalDuration);
711
+ }
712
+ }
713
+ } else if (phase === "out" && onAnimationEnd) {
714
+ const totalDuration = duration + delay;
715
+ timerRef.current = setTimeout(() => {
716
+ onAnimationEnd();
717
+ }, totalDuration);
718
+ }
719
+ return () => clearTimer();
720
+ }, [phase]);
721
+ const animationStyles = {};
722
+ if (phase === "in" && inProp !== void 0) {
723
+ const animName = resolveAnimation(inProp);
724
+ if (animName !== void 0) {
725
+ animationStyles.animationName = animName;
726
+ animationStyles.animationDuration = `${duration}ms`;
727
+ animationStyles.animationTimingFunction = easing;
728
+ animationStyles.animationDelay = `${delay}ms`;
729
+ animationStyles.animationFillMode = "forwards";
730
+ animationStyles.animationIterationCount = 1;
731
+ }
732
+ } else if (phase === "loop" && loopProp !== void 0) {
733
+ const animName = resolveAnimation(loopProp);
734
+ if (animName !== void 0) {
735
+ animationStyles.animationName = animName;
736
+ animationStyles.animationDuration = `${loopDuration}ms`;
737
+ animationStyles.animationTimingFunction = easing;
738
+ animationStyles.animationDelay = "0ms";
739
+ animationStyles.animationFillMode = "forwards";
740
+ animationStyles.animationIterationCount = "infinite";
741
+ }
742
+ } else if (phase === "out" && outProp !== void 0) {
743
+ const animName = resolveAnimation(outProp);
744
+ if (animName !== void 0) {
745
+ animationStyles.animationName = animName;
746
+ animationStyles.animationDuration = `${duration}ms`;
747
+ animationStyles.animationTimingFunction = easing;
748
+ animationStyles.animationDelay = `${delay}ms`;
749
+ animationStyles.animationFillMode = "forwards";
750
+ animationStyles.animationIterationCount = 1;
751
+ }
752
+ }
753
+ return React15.createElement("Box", { style: animationStyles }, children);
754
+ }
755
+
756
+ // src/animation/useAnimation.ts
757
+ import { useState as useState12, useCallback as useCallback7 } from "react";
758
+ function resolvePreset(name) {
759
+ try {
760
+ return getPreset(name);
761
+ } catch {
762
+ return name;
763
+ }
764
+ }
765
+ function useAnimation() {
766
+ const [isAnimating, setIsAnimating] = useState12(false);
767
+ const [currentAnimation, setCurrentAnimation] = useState12(null);
768
+ const [style, setStyle] = useState12({});
769
+ const trigger = useCallback7((preset, duration = 300) => {
770
+ const animationName = resolvePreset(preset);
771
+ setIsAnimating(true);
772
+ setCurrentAnimation(preset);
773
+ setStyle({
774
+ animationName,
775
+ animationDuration: `${duration}ms`,
776
+ animationFillMode: "forwards"
777
+ });
778
+ return animationName;
779
+ }, []);
780
+ const reset = useCallback7(() => {
781
+ setIsAnimating(false);
782
+ setCurrentAnimation(null);
783
+ setStyle({});
784
+ }, []);
785
+ return { trigger, reset, isAnimating, currentAnimation, style };
786
+ }
787
+
788
+ // src/fonts/localFont.ts
789
+ var registeredFonts = [];
790
+ function formatFromPath(path) {
791
+ const lower = path.toLowerCase();
792
+ if (lower.endsWith(".woff2")) return "woff2";
793
+ if (lower.endsWith(".woff")) return "woff";
794
+ return "truetype";
795
+ }
796
+ function buildFontFace(family, src, display, weight, style) {
797
+ const format = formatFromPath(src);
798
+ const lines = [
799
+ "@font-face {",
800
+ ` font-family: "${family}";`,
801
+ ` src: url("${src}") format("${format}");`,
802
+ ` font-display: ${display};`
803
+ ];
804
+ if (weight !== void 0) {
805
+ lines.push(` font-weight: ${weight};`);
806
+ }
807
+ if (style !== void 0) {
808
+ lines.push(` font-style: ${style};`);
809
+ }
810
+ lines.push("}");
811
+ return lines.join("\n");
812
+ }
813
+ function localFont(options) {
814
+ const { src, family, weight, style, display = "swap", fallback } = options;
815
+ const blocks = [];
816
+ if (typeof src === "string") {
817
+ blocks.push(buildFontFace(family, src, display, weight, style));
818
+ } else {
819
+ for (const source of src) {
820
+ blocks.push(
821
+ buildFontFace(
822
+ family,
823
+ source.path,
824
+ display,
825
+ source.weight ?? weight,
826
+ source.style ?? style
827
+ )
828
+ );
829
+ }
830
+ }
831
+ for (const block of blocks) {
832
+ registeredFonts.push(block);
833
+ }
834
+ const css = blocks.join("\n\n");
835
+ try {
836
+ getBridge().notify("ui.keyframes", { css });
837
+ } catch {
838
+ }
839
+ const families = [family, ...fallback ?? []].join(", ");
840
+ return { fontFamily: families };
841
+ }
842
+ export {
843
+ ANIMATION_PRESETS,
844
+ Animated,
845
+ Box,
846
+ Button,
847
+ CompactView,
848
+ Dropdown,
849
+ HStack,
850
+ Image,
851
+ List,
852
+ Lumio,
853
+ NumberField,
854
+ Slider,
855
+ Text,
856
+ TextArea,
857
+ TextField,
858
+ Toggle,
859
+ VStack,
860
+ WorkerBridge,
861
+ defineKeyframes,
862
+ flushKeyframes,
863
+ getPreset,
864
+ localFont,
865
+ useAnimation,
866
+ useExtensionContext,
867
+ useExtensionStorage,
868
+ useLumioAction,
869
+ useLumioConfig,
870
+ useLumioEvent,
871
+ useLumioIdentity,
872
+ useLumioTheme,
873
+ useMutation,
874
+ useQuery,
875
+ useVisionState
876
+ };