@garretapp/sdk 0.1.3 → 0.2.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/{platform-qz2Ef0Rp.d.cts → platform-Byqljdn8.d.cts} +5 -1
- package/dist/{platform-Bbj2Vh3W.d.ts → platform-CRkiyy2a.d.ts} +5 -1
- package/dist/react.cjs +70 -0
- package/dist/react.d.cts +56 -3
- package/dist/react.d.ts +56 -3
- package/dist/react.js +68 -1
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/package.json +1 -1
|
@@ -111,7 +111,11 @@ interface GarretPlatform {
|
|
|
111
111
|
/** Pack-shared store — present only when the pack declares `shared`; otherwise its calls reject. */
|
|
112
112
|
shared: SharedApi;
|
|
113
113
|
service<T extends ServiceClient = ServiceClient>(id: string): T;
|
|
114
|
-
|
|
114
|
+
/** Show a system notification. `opts.url` makes it clickable → opens the link (requires the
|
|
115
|
+
* `openExternal` capability; ignored otherwise). */
|
|
116
|
+
notify(title: string, body?: string, opts?: {
|
|
117
|
+
url?: string;
|
|
118
|
+
}): void;
|
|
115
119
|
openExternal(url: string): Promise<boolean>;
|
|
116
120
|
clipboard: {
|
|
117
121
|
readText(): Promise<string>;
|
|
@@ -111,7 +111,11 @@ interface GarretPlatform {
|
|
|
111
111
|
/** Pack-shared store — present only when the pack declares `shared`; otherwise its calls reject. */
|
|
112
112
|
shared: SharedApi;
|
|
113
113
|
service<T extends ServiceClient = ServiceClient>(id: string): T;
|
|
114
|
-
|
|
114
|
+
/** Show a system notification. `opts.url` makes it clickable → opens the link (requires the
|
|
115
|
+
* `openExternal` capability; ignored otherwise). */
|
|
116
|
+
notify(title: string, body?: string, opts?: {
|
|
117
|
+
url?: string;
|
|
118
|
+
}): void;
|
|
115
119
|
openExternal(url: string): Promise<boolean>;
|
|
116
120
|
clipboard: {
|
|
117
121
|
readText(): Promise<string>;
|
package/dist/react.cjs
CHANGED
|
@@ -293,6 +293,26 @@ function Accordion({
|
|
|
293
293
|
open && /* @__PURE__ */ jsxRuntime.jsx("div", { children })
|
|
294
294
|
] });
|
|
295
295
|
}
|
|
296
|
+
function StatusStrip({
|
|
297
|
+
error,
|
|
298
|
+
loading,
|
|
299
|
+
onRetry
|
|
300
|
+
}) {
|
|
301
|
+
if (error) {
|
|
302
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gx-status gx-status--error", children: [
|
|
303
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 1l22 22M16.72 11.06A10.94 10.94 0 0 1 19 12.55M5 12.55a10.94 10.94 0 0 1 5.17-2.39M10.71 5.05A16 16 0 0 1 22.58 9M1.42 9a15.91 15.91 0 0 1 4.7-2.88M8.53 16.11a6 6 0 0 1 6.95 0M12 20h.01" }) }),
|
|
304
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Couldn\u2019t refresh \u2014 showing last update" }),
|
|
305
|
+
onRetry && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "gx-status-retry", onClick: onRetry, children: "Retry" })
|
|
306
|
+
] });
|
|
307
|
+
}
|
|
308
|
+
if (loading) {
|
|
309
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gx-status", children: [
|
|
310
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "gx-status-spin", width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }),
|
|
311
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Refreshing\u2026" })
|
|
312
|
+
] });
|
|
313
|
+
}
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
296
316
|
function Badge({ tone = "neutral", children }) {
|
|
297
317
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `gx-badge gx-badge--${tone}`, children });
|
|
298
318
|
}
|
|
@@ -359,6 +379,21 @@ function Select({
|
|
|
359
379
|
function Switch({ on, onChange }) {
|
|
360
380
|
return /* @__PURE__ */ jsxRuntime.jsx("button", { className: `gx-switch${on ? " gx-switch--on" : ""}`, role: "switch", "aria-checked": on, onClick: () => onChange(!on), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "gx-switch-knob" }) });
|
|
361
381
|
}
|
|
382
|
+
function AutoForm({
|
|
383
|
+
schema,
|
|
384
|
+
value,
|
|
385
|
+
onChange
|
|
386
|
+
}) {
|
|
387
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FieldGroup, { children: schema.map((f) => /* @__PURE__ */ jsxRuntime.jsx(Field, { label: f.label, children: f.type === "select" ? /* @__PURE__ */ jsxRuntime.jsx(Select, { value: String(value[f.key] ?? ""), options: f.options, onChange: (v) => onChange({ [f.key]: v }) }) : f.type === "switch" ? /* @__PURE__ */ jsxRuntime.jsx(Switch, { on: Boolean(value[f.key]), onChange: (v) => onChange({ [f.key]: v }) }) : f.type === "number" ? /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { value: value[f.key], onCommit: (v) => onChange({ [f.key]: v }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
388
|
+
TextInput,
|
|
389
|
+
{
|
|
390
|
+
value: value[f.key],
|
|
391
|
+
placeholder: f.placeholder,
|
|
392
|
+
secret: f.type === "secret",
|
|
393
|
+
onCommit: (v) => onChange({ [f.key]: v })
|
|
394
|
+
}
|
|
395
|
+
) }, f.key)) });
|
|
396
|
+
}
|
|
362
397
|
|
|
363
398
|
// src/react.ts
|
|
364
399
|
var singleton;
|
|
@@ -471,6 +506,38 @@ function useInstanceConfig(defaults) {
|
|
|
471
506
|
);
|
|
472
507
|
return { cfg, set, loaded };
|
|
473
508
|
}
|
|
509
|
+
function usePoll(fn, opts) {
|
|
510
|
+
const { intervalMs, deps = [], enabled = true, background = false, idleFloorMs = 3e5 } = opts;
|
|
511
|
+
const active = useActive();
|
|
512
|
+
const [data, setData] = react.useState(void 0);
|
|
513
|
+
const [error, setError] = react.useState("");
|
|
514
|
+
const [loading, setLoading] = react.useState(false);
|
|
515
|
+
const fnRef = react.useRef(fn);
|
|
516
|
+
fnRef.current = fn;
|
|
517
|
+
const run = react.useCallback(async () => {
|
|
518
|
+
setLoading(true);
|
|
519
|
+
try {
|
|
520
|
+
setData(await fnRef.current());
|
|
521
|
+
setError("");
|
|
522
|
+
} catch (e) {
|
|
523
|
+
setError(e?.message || "Request failed");
|
|
524
|
+
} finally {
|
|
525
|
+
setLoading(false);
|
|
526
|
+
}
|
|
527
|
+
}, []);
|
|
528
|
+
react.useEffect(() => {
|
|
529
|
+
if (enabled) void run();
|
|
530
|
+
}, [enabled, run, ...deps]);
|
|
531
|
+
react.useEffect(() => {
|
|
532
|
+
if (!enabled || !(intervalMs > 0)) return;
|
|
533
|
+
const period = active ? intervalMs : Math.max(intervalMs, idleFloorMs);
|
|
534
|
+
const t = setInterval(() => {
|
|
535
|
+
if (active || background) void run();
|
|
536
|
+
}, period);
|
|
537
|
+
return () => clearInterval(t);
|
|
538
|
+
}, [enabled, intervalMs, active, background, idleFloorMs, run]);
|
|
539
|
+
return { data, error, loading, refresh: run };
|
|
540
|
+
}
|
|
474
541
|
function useProps() {
|
|
475
542
|
const g = getGarret();
|
|
476
543
|
const [props, setProps] = react.useState({});
|
|
@@ -479,6 +546,7 @@ function useProps() {
|
|
|
479
546
|
}
|
|
480
547
|
|
|
481
548
|
exports.Accordion = Accordion;
|
|
549
|
+
exports.AutoForm = AutoForm;
|
|
482
550
|
exports.Badge = Badge;
|
|
483
551
|
exports.Dot = Dot;
|
|
484
552
|
exports.EmptyState = EmptyState;
|
|
@@ -491,6 +559,7 @@ exports.NumberInput = NumberInput;
|
|
|
491
559
|
exports.Scroll = Scroll;
|
|
492
560
|
exports.Select = Select;
|
|
493
561
|
exports.SettingsPanel = SettingsPanel;
|
|
562
|
+
exports.StatusStrip = StatusStrip;
|
|
494
563
|
exports.Switch = Switch;
|
|
495
564
|
exports.TextInput = TextInput;
|
|
496
565
|
exports.useActive = useActive;
|
|
@@ -499,6 +568,7 @@ exports.useGarret = useGarret;
|
|
|
499
568
|
exports.useHost = useHost;
|
|
500
569
|
exports.useHostEvent = useHostEvent;
|
|
501
570
|
exports.useInstanceConfig = useInstanceConfig;
|
|
571
|
+
exports.usePoll = usePoll;
|
|
502
572
|
exports.useProps = useProps;
|
|
503
573
|
exports.useStream = useStream;
|
|
504
574
|
exports.useWidgetMenu = useWidgetMenu;
|
package/dist/react.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { G as GarretError, E as EventMap, H as HostClient, f as StreamCall } from './types-BxSYAH_H.cjs';
|
|
2
|
-
import { G as GarretPlatform } from './platform-
|
|
3
|
-
export { S as SurfaceApi, a as SurfaceHandle, b as SurfaceOpenOptions, W as WindowControls } from './platform-
|
|
2
|
+
import { G as GarretPlatform } from './platform-Byqljdn8.cjs';
|
|
3
|
+
export { S as SurfaceApi, a as SurfaceHandle, b as SurfaceOpenOptions, W as WindowControls } from './platform-Byqljdn8.cjs';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
import './protocol-Do0BJdeE.cjs';
|
|
6
6
|
|
|
@@ -40,6 +40,14 @@ declare function Accordion({ title, aside, defaultOpen, children }: {
|
|
|
40
40
|
defaultOpen?: boolean;
|
|
41
41
|
children: ReactNode;
|
|
42
42
|
}): JSX.Element;
|
|
43
|
+
/** A thin status strip shown ABOVE content that already has data: a "couldn't refresh" notice
|
|
44
|
+
* (stale-while-error) or a subtle "refreshing" hint. Renders nothing when fresh + idle. Pair with
|
|
45
|
+
* `usePoll` — pass its `{ error, loading, refresh }`. */
|
|
46
|
+
declare function StatusStrip({ error, loading, onRetry }: {
|
|
47
|
+
error?: string;
|
|
48
|
+
loading?: boolean;
|
|
49
|
+
onRetry?: () => void;
|
|
50
|
+
}): JSX.Element | null;
|
|
43
51
|
/** A small pill; `tone` sets the color. */
|
|
44
52
|
declare function Badge({ tone, children }: {
|
|
45
53
|
tone?: Tone;
|
|
@@ -85,6 +93,34 @@ declare function Switch({ on, onChange }: {
|
|
|
85
93
|
on: boolean;
|
|
86
94
|
onChange: (v: boolean) => void;
|
|
87
95
|
}): JSX.Element;
|
|
96
|
+
/** One declarative settings field for `AutoForm`. */
|
|
97
|
+
type FieldSpec = {
|
|
98
|
+
key: string;
|
|
99
|
+
label: string;
|
|
100
|
+
type: 'text' | 'secret';
|
|
101
|
+
placeholder?: string;
|
|
102
|
+
} | {
|
|
103
|
+
key: string;
|
|
104
|
+
label: string;
|
|
105
|
+
type: 'number';
|
|
106
|
+
} | {
|
|
107
|
+
key: string;
|
|
108
|
+
label: string;
|
|
109
|
+
type: 'select';
|
|
110
|
+
options: [value: string, label: string][];
|
|
111
|
+
} | {
|
|
112
|
+
key: string;
|
|
113
|
+
label: string;
|
|
114
|
+
type: 'switch';
|
|
115
|
+
};
|
|
116
|
+
/** Render a settings form from a declarative schema — a convenience over hand-composing Field +
|
|
117
|
+
* inputs. `value` supplies current values by key; `onChange` gets a shallow patch. Compose freely
|
|
118
|
+
* with your own Fields (wrap in FieldGroup / SettingsPanel as you like). */
|
|
119
|
+
declare function AutoForm<T extends Record<string, unknown>>({ schema, value, onChange }: {
|
|
120
|
+
schema: FieldSpec[];
|
|
121
|
+
value: T;
|
|
122
|
+
onChange: (patch: Partial<T>) => void;
|
|
123
|
+
}): JSX.Element;
|
|
88
124
|
|
|
89
125
|
/** Typed proxy of your host's methods. Stream-vs-Promise is inferred from each method's `Api` return
|
|
90
126
|
* type — nothing to configure. */
|
|
@@ -126,10 +162,27 @@ declare function useInstanceConfig<T extends Record<string, unknown>>(defaults:
|
|
|
126
162
|
set: (patch: Partial<T>) => void;
|
|
127
163
|
loaded: boolean;
|
|
128
164
|
};
|
|
165
|
+
/** Declarative polling: runs `fn` on mount + whenever `deps` change, then every `intervalMs`. Gated on
|
|
166
|
+
* board activity — pauses when the board is idle UNLESS `background` is set, in which case it keeps
|
|
167
|
+
* polling at a throttled floor (`idleFloorMs`, default 5 min) so alerts/data stay fresh while you're
|
|
168
|
+
* not looking (no extra process — the widget's own webview). Stale-while-error: keeps the last data on
|
|
169
|
+
* failure and surfaces `error`. Pair with `<StatusStrip error={error} loading={loading} onRetry={refresh} />`. */
|
|
170
|
+
declare function usePoll<T>(fn: () => Promise<T>, opts: {
|
|
171
|
+
intervalMs: number;
|
|
172
|
+
deps?: unknown[];
|
|
173
|
+
enabled?: boolean;
|
|
174
|
+
background?: boolean;
|
|
175
|
+
idleFloorMs?: number;
|
|
176
|
+
}): {
|
|
177
|
+
data: T | undefined;
|
|
178
|
+
error: string;
|
|
179
|
+
loading: boolean;
|
|
180
|
+
refresh: () => void;
|
|
181
|
+
};
|
|
129
182
|
|
|
130
183
|
/** Launch props for a spawned surface window (`g.surfaces.open(..., { props })`). `{}` for the board
|
|
131
184
|
* surface. Delivered via `onReady`'s callback (a contextBridge getter would be frozen at exposure
|
|
132
185
|
* time), so this re-renders when the runtime binds. The `T` is an unchecked cast — validate it yourself. */
|
|
133
186
|
declare function useProps<T = Record<string, unknown>>(): T;
|
|
134
187
|
|
|
135
|
-
export { Accordion, Badge, Dot, EmptyState, ErrorState, Field, FieldGroup, GarretError, GarretPlatform, Item, NumberInput, Scroll, Select, SettingsPanel, type StreamStatus, Switch, TextInput, type Tone, type UseStreamResult, useActive, useConfig, useGarret, useHost, useHostEvent, useInstanceConfig, useProps, useStream, useWidgetMenu };
|
|
188
|
+
export { Accordion, AutoForm, Badge, Dot, EmptyState, ErrorState, Field, FieldGroup, type FieldSpec, GarretError, GarretPlatform, Item, NumberInput, Scroll, Select, SettingsPanel, StatusStrip, type StreamStatus, Switch, TextInput, type Tone, type UseStreamResult, useActive, useConfig, useGarret, useHost, useHostEvent, useInstanceConfig, usePoll, useProps, useStream, useWidgetMenu };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { G as GarretError, E as EventMap, H as HostClient, f as StreamCall } from './types-BxSYAH_H.js';
|
|
2
|
-
import { G as GarretPlatform } from './platform-
|
|
3
|
-
export { S as SurfaceApi, a as SurfaceHandle, b as SurfaceOpenOptions, W as WindowControls } from './platform-
|
|
2
|
+
import { G as GarretPlatform } from './platform-CRkiyy2a.js';
|
|
3
|
+
export { S as SurfaceApi, a as SurfaceHandle, b as SurfaceOpenOptions, W as WindowControls } from './platform-CRkiyy2a.js';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
import './protocol-Do0BJdeE.js';
|
|
6
6
|
|
|
@@ -40,6 +40,14 @@ declare function Accordion({ title, aside, defaultOpen, children }: {
|
|
|
40
40
|
defaultOpen?: boolean;
|
|
41
41
|
children: ReactNode;
|
|
42
42
|
}): JSX.Element;
|
|
43
|
+
/** A thin status strip shown ABOVE content that already has data: a "couldn't refresh" notice
|
|
44
|
+
* (stale-while-error) or a subtle "refreshing" hint. Renders nothing when fresh + idle. Pair with
|
|
45
|
+
* `usePoll` — pass its `{ error, loading, refresh }`. */
|
|
46
|
+
declare function StatusStrip({ error, loading, onRetry }: {
|
|
47
|
+
error?: string;
|
|
48
|
+
loading?: boolean;
|
|
49
|
+
onRetry?: () => void;
|
|
50
|
+
}): JSX.Element | null;
|
|
43
51
|
/** A small pill; `tone` sets the color. */
|
|
44
52
|
declare function Badge({ tone, children }: {
|
|
45
53
|
tone?: Tone;
|
|
@@ -85,6 +93,34 @@ declare function Switch({ on, onChange }: {
|
|
|
85
93
|
on: boolean;
|
|
86
94
|
onChange: (v: boolean) => void;
|
|
87
95
|
}): JSX.Element;
|
|
96
|
+
/** One declarative settings field for `AutoForm`. */
|
|
97
|
+
type FieldSpec = {
|
|
98
|
+
key: string;
|
|
99
|
+
label: string;
|
|
100
|
+
type: 'text' | 'secret';
|
|
101
|
+
placeholder?: string;
|
|
102
|
+
} | {
|
|
103
|
+
key: string;
|
|
104
|
+
label: string;
|
|
105
|
+
type: 'number';
|
|
106
|
+
} | {
|
|
107
|
+
key: string;
|
|
108
|
+
label: string;
|
|
109
|
+
type: 'select';
|
|
110
|
+
options: [value: string, label: string][];
|
|
111
|
+
} | {
|
|
112
|
+
key: string;
|
|
113
|
+
label: string;
|
|
114
|
+
type: 'switch';
|
|
115
|
+
};
|
|
116
|
+
/** Render a settings form from a declarative schema — a convenience over hand-composing Field +
|
|
117
|
+
* inputs. `value` supplies current values by key; `onChange` gets a shallow patch. Compose freely
|
|
118
|
+
* with your own Fields (wrap in FieldGroup / SettingsPanel as you like). */
|
|
119
|
+
declare function AutoForm<T extends Record<string, unknown>>({ schema, value, onChange }: {
|
|
120
|
+
schema: FieldSpec[];
|
|
121
|
+
value: T;
|
|
122
|
+
onChange: (patch: Partial<T>) => void;
|
|
123
|
+
}): JSX.Element;
|
|
88
124
|
|
|
89
125
|
/** Typed proxy of your host's methods. Stream-vs-Promise is inferred from each method's `Api` return
|
|
90
126
|
* type — nothing to configure. */
|
|
@@ -126,10 +162,27 @@ declare function useInstanceConfig<T extends Record<string, unknown>>(defaults:
|
|
|
126
162
|
set: (patch: Partial<T>) => void;
|
|
127
163
|
loaded: boolean;
|
|
128
164
|
};
|
|
165
|
+
/** Declarative polling: runs `fn` on mount + whenever `deps` change, then every `intervalMs`. Gated on
|
|
166
|
+
* board activity — pauses when the board is idle UNLESS `background` is set, in which case it keeps
|
|
167
|
+
* polling at a throttled floor (`idleFloorMs`, default 5 min) so alerts/data stay fresh while you're
|
|
168
|
+
* not looking (no extra process — the widget's own webview). Stale-while-error: keeps the last data on
|
|
169
|
+
* failure and surfaces `error`. Pair with `<StatusStrip error={error} loading={loading} onRetry={refresh} />`. */
|
|
170
|
+
declare function usePoll<T>(fn: () => Promise<T>, opts: {
|
|
171
|
+
intervalMs: number;
|
|
172
|
+
deps?: unknown[];
|
|
173
|
+
enabled?: boolean;
|
|
174
|
+
background?: boolean;
|
|
175
|
+
idleFloorMs?: number;
|
|
176
|
+
}): {
|
|
177
|
+
data: T | undefined;
|
|
178
|
+
error: string;
|
|
179
|
+
loading: boolean;
|
|
180
|
+
refresh: () => void;
|
|
181
|
+
};
|
|
129
182
|
|
|
130
183
|
/** Launch props for a spawned surface window (`g.surfaces.open(..., { props })`). `{}` for the board
|
|
131
184
|
* surface. Delivered via `onReady`'s callback (a contextBridge getter would be frozen at exposure
|
|
132
185
|
* time), so this re-renders when the runtime binds. The `T` is an unchecked cast — validate it yourself. */
|
|
133
186
|
declare function useProps<T = Record<string, unknown>>(): T;
|
|
134
187
|
|
|
135
|
-
export { Accordion, Badge, Dot, EmptyState, ErrorState, Field, FieldGroup, GarretError, GarretPlatform, Item, NumberInput, Scroll, Select, SettingsPanel, type StreamStatus, Switch, TextInput, type Tone, type UseStreamResult, useActive, useConfig, useGarret, useHost, useHostEvent, useInstanceConfig, useProps, useStream, useWidgetMenu };
|
|
188
|
+
export { Accordion, AutoForm, Badge, Dot, EmptyState, ErrorState, Field, FieldGroup, type FieldSpec, GarretError, GarretPlatform, Item, NumberInput, Scroll, Select, SettingsPanel, StatusStrip, type StreamStatus, Switch, TextInput, type Tone, type UseStreamResult, useActive, useConfig, useGarret, useHost, useHostEvent, useInstanceConfig, usePoll, useProps, useStream, useWidgetMenu };
|
package/dist/react.js
CHANGED
|
@@ -58,6 +58,26 @@ function Accordion({
|
|
|
58
58
|
open && /* @__PURE__ */ jsx("div", { children })
|
|
59
59
|
] });
|
|
60
60
|
}
|
|
61
|
+
function StatusStrip({
|
|
62
|
+
error,
|
|
63
|
+
loading,
|
|
64
|
+
onRetry
|
|
65
|
+
}) {
|
|
66
|
+
if (error) {
|
|
67
|
+
return /* @__PURE__ */ jsxs("div", { className: "gx-status gx-status--error", children: [
|
|
68
|
+
/* @__PURE__ */ jsx("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M1 1l22 22M16.72 11.06A10.94 10.94 0 0 1 19 12.55M5 12.55a10.94 10.94 0 0 1 5.17-2.39M10.71 5.05A16 16 0 0 1 22.58 9M1.42 9a15.91 15.91 0 0 1 4.7-2.88M8.53 16.11a6 6 0 0 1 6.95 0M12 20h.01" }) }),
|
|
69
|
+
/* @__PURE__ */ jsx("span", { children: "Couldn\u2019t refresh \u2014 showing last update" }),
|
|
70
|
+
onRetry && /* @__PURE__ */ jsx("button", { className: "gx-status-retry", onClick: onRetry, children: "Retry" })
|
|
71
|
+
] });
|
|
72
|
+
}
|
|
73
|
+
if (loading) {
|
|
74
|
+
return /* @__PURE__ */ jsxs("div", { className: "gx-status", children: [
|
|
75
|
+
/* @__PURE__ */ jsx("svg", { className: "gx-status-spin", width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }),
|
|
76
|
+
/* @__PURE__ */ jsx("span", { children: "Refreshing\u2026" })
|
|
77
|
+
] });
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
61
81
|
function Badge({ tone = "neutral", children }) {
|
|
62
82
|
return /* @__PURE__ */ jsx("span", { className: `gx-badge gx-badge--${tone}`, children });
|
|
63
83
|
}
|
|
@@ -124,6 +144,21 @@ function Select({
|
|
|
124
144
|
function Switch({ on, onChange }) {
|
|
125
145
|
return /* @__PURE__ */ jsx("button", { className: `gx-switch${on ? " gx-switch--on" : ""}`, role: "switch", "aria-checked": on, onClick: () => onChange(!on), children: /* @__PURE__ */ jsx("span", { className: "gx-switch-knob" }) });
|
|
126
146
|
}
|
|
147
|
+
function AutoForm({
|
|
148
|
+
schema,
|
|
149
|
+
value,
|
|
150
|
+
onChange
|
|
151
|
+
}) {
|
|
152
|
+
return /* @__PURE__ */ jsx(FieldGroup, { children: schema.map((f) => /* @__PURE__ */ jsx(Field, { label: f.label, children: f.type === "select" ? /* @__PURE__ */ jsx(Select, { value: String(value[f.key] ?? ""), options: f.options, onChange: (v) => onChange({ [f.key]: v }) }) : f.type === "switch" ? /* @__PURE__ */ jsx(Switch, { on: Boolean(value[f.key]), onChange: (v) => onChange({ [f.key]: v }) }) : f.type === "number" ? /* @__PURE__ */ jsx(NumberInput, { value: value[f.key], onCommit: (v) => onChange({ [f.key]: v }) }) : /* @__PURE__ */ jsx(
|
|
153
|
+
TextInput,
|
|
154
|
+
{
|
|
155
|
+
value: value[f.key],
|
|
156
|
+
placeholder: f.placeholder,
|
|
157
|
+
secret: f.type === "secret",
|
|
158
|
+
onCommit: (v) => onChange({ [f.key]: v })
|
|
159
|
+
}
|
|
160
|
+
) }, f.key)) });
|
|
161
|
+
}
|
|
127
162
|
|
|
128
163
|
// src/react.ts
|
|
129
164
|
var singleton;
|
|
@@ -236,6 +271,38 @@ function useInstanceConfig(defaults) {
|
|
|
236
271
|
);
|
|
237
272
|
return { cfg, set, loaded };
|
|
238
273
|
}
|
|
274
|
+
function usePoll(fn, opts) {
|
|
275
|
+
const { intervalMs, deps = [], enabled = true, background = false, idleFloorMs = 3e5 } = opts;
|
|
276
|
+
const active = useActive();
|
|
277
|
+
const [data, setData] = useState(void 0);
|
|
278
|
+
const [error, setError] = useState("");
|
|
279
|
+
const [loading, setLoading] = useState(false);
|
|
280
|
+
const fnRef = useRef(fn);
|
|
281
|
+
fnRef.current = fn;
|
|
282
|
+
const run = useCallback(async () => {
|
|
283
|
+
setLoading(true);
|
|
284
|
+
try {
|
|
285
|
+
setData(await fnRef.current());
|
|
286
|
+
setError("");
|
|
287
|
+
} catch (e) {
|
|
288
|
+
setError(e?.message || "Request failed");
|
|
289
|
+
} finally {
|
|
290
|
+
setLoading(false);
|
|
291
|
+
}
|
|
292
|
+
}, []);
|
|
293
|
+
useEffect(() => {
|
|
294
|
+
if (enabled) void run();
|
|
295
|
+
}, [enabled, run, ...deps]);
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
if (!enabled || !(intervalMs > 0)) return;
|
|
298
|
+
const period = active ? intervalMs : Math.max(intervalMs, idleFloorMs);
|
|
299
|
+
const t = setInterval(() => {
|
|
300
|
+
if (active || background) void run();
|
|
301
|
+
}, period);
|
|
302
|
+
return () => clearInterval(t);
|
|
303
|
+
}, [enabled, intervalMs, active, background, idleFloorMs, run]);
|
|
304
|
+
return { data, error, loading, refresh: run };
|
|
305
|
+
}
|
|
239
306
|
function useProps() {
|
|
240
307
|
const g = getGarret();
|
|
241
308
|
const [props, setProps] = useState({});
|
|
@@ -243,4 +310,4 @@ function useProps() {
|
|
|
243
310
|
return props;
|
|
244
311
|
}
|
|
245
312
|
|
|
246
|
-
export { Accordion, Badge, Dot, EmptyState, ErrorState, Field, FieldGroup, Item, NumberInput, Scroll, Select, SettingsPanel, Switch, TextInput, useActive, useConfig, useGarret, useHost, useHostEvent, useInstanceConfig, useProps, useStream, useWidgetMenu };
|
|
313
|
+
export { Accordion, AutoForm, Badge, Dot, EmptyState, ErrorState, Field, FieldGroup, Item, NumberInput, Scroll, Select, SettingsPanel, StatusStrip, Switch, TextInput, useActive, useConfig, useGarret, useHost, useHostEvent, useInstanceConfig, usePoll, useProps, useStream, useWidgetMenu };
|
package/dist/ui.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { T as Transport } from './protocol-Do0BJdeE.cjs';
|
|
2
2
|
import { E as EventMap, H as HostClient } from './types-BxSYAH_H.cjs';
|
|
3
3
|
export { C as Capability, G as GarretError, M as Manifest, S as Stream, f as StreamCall, g as defineConfig, h as defineManifest } from './types-BxSYAH_H.cjs';
|
|
4
|
-
export { G as GarretPlatform, c as GarretRuntime, d as SecretsApi, e as ServiceClient, f as StorageApi, S as SurfaceApi, a as SurfaceHandle, b as SurfaceOpenOptions, W as WindowControls, g as getGarret, h as getHostTransport, i as getInstanceId, j as getRuntime } from './platform-
|
|
4
|
+
export { G as GarretPlatform, c as GarretRuntime, d as SecretsApi, e as ServiceClient, f as StorageApi, S as SurfaceApi, a as SurfaceHandle, b as SurfaceOpenOptions, W as WindowControls, g as getGarret, h as getHostTransport, i as getInstanceId, j as getRuntime } from './platform-Byqljdn8.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* UI-side host client — a typed proxy over the wire (protocol.ts). Every call returns ONE handle
|
package/dist/ui.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { T as Transport } from './protocol-Do0BJdeE.js';
|
|
2
2
|
import { E as EventMap, H as HostClient } from './types-BxSYAH_H.js';
|
|
3
3
|
export { C as Capability, G as GarretError, M as Manifest, S as Stream, f as StreamCall, g as defineConfig, h as defineManifest } from './types-BxSYAH_H.js';
|
|
4
|
-
export { G as GarretPlatform, c as GarretRuntime, d as SecretsApi, e as ServiceClient, f as StorageApi, S as SurfaceApi, a as SurfaceHandle, b as SurfaceOpenOptions, W as WindowControls, g as getGarret, h as getHostTransport, i as getInstanceId, j as getRuntime } from './platform-
|
|
4
|
+
export { G as GarretPlatform, c as GarretRuntime, d as SecretsApi, e as ServiceClient, f as StorageApi, S as SurfaceApi, a as SurfaceHandle, b as SurfaceOpenOptions, W as WindowControls, g as getGarret, h as getHostTransport, i as getInstanceId, j as getRuntime } from './platform-CRkiyy2a.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* UI-side host client — a typed proxy over the wire (protocol.ts). Every call returns ONE handle
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@garretapp/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Build extensions for Garret — one SDK for both web widgets and full-access native extensions. Host runtime (defineHost), UI client + React hooks. See docs/garret.html.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sudharsan Selvaraj",
|