knobkit 0.0.1
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/LICENSE +21 -0
- package/dist/assets/cell-renderer-CLTRlCa5-DIlwS99c.js +1 -0
- package/dist/assets/chart-D8ctp-_1.js +36 -0
- package/dist/assets/code-BMuLQBYq.js +2 -0
- package/dist/assets/column.service-C6hByxPy-XG9X0y3N.js +1 -0
- package/dist/assets/debounce-PCRWZliA-BjJpj_P7.js +32 -0
- package/dist/assets/dimension.helpers-CGKwSvw6-D_czicbS.js +1 -0
- package/dist/assets/dist-1hsZpGRf.js +23 -0
- package/dist/assets/dist-B-y4Etc5.js +1 -0
- package/dist/assets/dist-B8BXgMDk.js +10 -0
- package/dist/assets/dist-BJlXPLNt.js +1 -0
- package/dist/assets/dist-ByhR2UY_.js +1 -0
- package/dist/assets/dist-C0bxYHYH.js +2 -0
- package/dist/assets/dist-C8dagUDy.js +6 -0
- package/dist/assets/dist-CtLpohkg.js +1 -0
- package/dist/assets/dist-D00mNtIr.js +1 -0
- package/dist/assets/dist-Dh1Dvy3h.js +1 -0
- package/dist/assets/dist-DlwQ1Qqm.js +1 -0
- package/dist/assets/dist-DtZDI7jp.js +1 -0
- package/dist/assets/dist-thZFs69d.js +9 -0
- package/dist/assets/edit.utils-Dnnbd0xG-OAxDw8WC.js +1 -0
- package/dist/assets/events-BvSmBueA-4kqQ57iN.js +1 -0
- package/dist/assets/filter.button-BFwo1uvz-CyvQhOO5.js +1 -0
- package/dist/assets/header-cell-renderer-BMmXRsd_-BHbC7fao.js +1 -0
- package/dist/assets/index-Db3qZoW5-peeY7EGw.js +1 -0
- package/dist/assets/markdown-dDCgur7g.js +29 -0
- package/dist/assets/revo-grid.entry-CfI6s-uT.js +1 -0
- package/dist/assets/revogr-attribution_7.entry-6fUjzImt.js +1 -0
- package/dist/assets/revogr-clipboard_3.entry-DmI7LkER.js +2 -0
- package/dist/assets/revogr-data_4.entry-CYZIiXNw.js +1 -0
- package/dist/assets/revogr-filter-panel.entry-TmQHTQxw.js +1 -0
- package/dist/assets/table-Zn7rpfG-.js +1 -0
- package/dist/assets/text-editor-C3RUSwH5-DuDr9wKc.js +1 -0
- package/dist/assets/theme.service-BmnDvr6P-DftEgmbe.js +3 -0
- package/dist/assets/throttle-CaUDyxyU-Djj__DCp.js +1 -0
- package/dist/assets/viewport.helpers-CoCAvmZs-ByVRjjkF.js +1 -0
- package/dist/assets/viewport.store-_c579YyM-B_ZSqqka.js +1 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.js +82 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +77 -0
- package/dist/cli/mount.d.ts +2 -0
- package/dist/cli/mount.js +26 -0
- package/dist/cli/serve.d.ts +1 -0
- package/dist/cli/serve.js +21 -0
- package/dist/client/app.d.ts +8 -0
- package/dist/client/app.js +40 -0
- package/dist/client/context.d.ts +2 -0
- package/dist/client/context.js +16 -0
- package/dist/client/mount.d.ts +3 -0
- package/dist/client/mount.js +42 -0
- package/dist/client/runtime.d.ts +19 -0
- package/dist/client/runtime.js +88 -0
- package/dist/client/view.d.ts +12 -0
- package/dist/client/view.js +1 -0
- package/dist/client/widgets/accordion/index.d.ts +5 -0
- package/dist/client/widgets/accordion/index.js +8 -0
- package/dist/client/widgets/annotated-image/index.d.ts +8 -0
- package/dist/client/widgets/annotated-image/index.js +34 -0
- package/dist/client/widgets/audio/index.d.ts +5 -0
- package/dist/client/widgets/audio/index.js +5 -0
- package/dist/client/widgets/button/index.d.ts +4 -0
- package/dist/client/widgets/button/index.js +5 -0
- package/dist/client/widgets/chart/index.d.ts +5 -0
- package/dist/client/widgets/chart/index.js +23 -0
- package/dist/client/widgets/chart/lazy.d.ts +3 -0
- package/dist/client/widgets/chart/lazy.js +9 -0
- package/dist/client/widgets/chat/index.d.ts +6 -0
- package/dist/client/widgets/chat/index.js +77 -0
- package/dist/client/widgets/checkbox/index.d.ts +6 -0
- package/dist/client/widgets/checkbox/index.js +9 -0
- package/dist/client/widgets/checkbox-group/index.d.ts +6 -0
- package/dist/client/widgets/checkbox-group/index.js +12 -0
- package/dist/client/widgets/code/index.d.ts +5 -0
- package/dist/client/widgets/code/index.js +101 -0
- package/dist/client/widgets/code/lazy.d.ts +3 -0
- package/dist/client/widgets/code/lazy.js +10 -0
- package/dist/client/widgets/dropdown/index.d.ts +5 -0
- package/dist/client/widgets/dropdown/index.js +9 -0
- package/dist/client/widgets/file/index.d.ts +6 -0
- package/dist/client/widgets/file/index.js +7 -0
- package/dist/client/widgets/frame/index.d.ts +6 -0
- package/dist/client/widgets/frame/index.js +11 -0
- package/dist/client/widgets/gallery/index.d.ts +6 -0
- package/dist/client/widgets/gallery/index.js +8 -0
- package/dist/client/widgets/highlighted-text/index.d.ts +7 -0
- package/dist/client/widgets/highlighted-text/index.js +20 -0
- package/dist/client/widgets/html/index.d.ts +4 -0
- package/dist/client/widgets/html/index.js +8 -0
- package/dist/client/widgets/image/index.d.ts +4 -0
- package/dist/client/widgets/image/index.js +4 -0
- package/dist/client/widgets/json/index.d.ts +4 -0
- package/dist/client/widgets/json/index.js +4 -0
- package/dist/client/widgets/label/index.d.ts +7 -0
- package/dist/client/widgets/label/index.js +8 -0
- package/dist/client/widgets/layout/index.d.ts +4 -0
- package/dist/client/widgets/layout/index.js +7 -0
- package/dist/client/widgets/log/index.d.ts +4 -0
- package/dist/client/widgets/log/index.js +4 -0
- package/dist/client/widgets/mic/index.d.ts +6 -0
- package/dist/client/widgets/mic/index.js +70 -0
- package/dist/client/widgets/number/index.d.ts +5 -0
- package/dist/client/widgets/number/index.js +8 -0
- package/dist/client/widgets/output/index.d.ts +6 -0
- package/dist/client/widgets/output/index.js +13 -0
- package/dist/client/widgets/output/markdown.d.ts +3 -0
- package/dist/client/widgets/output/markdown.js +8 -0
- package/dist/client/widgets/progress/index.d.ts +6 -0
- package/dist/client/widgets/progress/index.js +6 -0
- package/dist/client/widgets/radio/index.d.ts +6 -0
- package/dist/client/widgets/radio/index.js +10 -0
- package/dist/client/widgets/registry.d.ts +2 -0
- package/dist/client/widgets/registry.js +69 -0
- package/dist/client/widgets/slider/index.d.ts +6 -0
- package/dist/client/widgets/slider/index.js +9 -0
- package/dist/client/widgets/table/index.d.ts +6 -0
- package/dist/client/widgets/table/index.js +72 -0
- package/dist/client/widgets/table/lazy.d.ts +3 -0
- package/dist/client/widgets/table/lazy.js +16 -0
- package/dist/client/widgets/tabs/index.d.ts +5 -0
- package/dist/client/widgets/tabs/index.js +10 -0
- package/dist/client/widgets/text/index.d.ts +6 -0
- package/dist/client/widgets/text/index.js +10 -0
- package/dist/client/widgets/upload/index.d.ts +6 -0
- package/dist/client/widgets/upload/index.js +16 -0
- package/dist/client/widgets/video/index.d.ts +5 -0
- package/dist/client/widgets/video/index.js +5 -0
- package/dist/client/widgets/webcam/index.d.ts +6 -0
- package/dist/client/widgets/webcam/index.js +62 -0
- package/dist/client.css +1 -0
- package/dist/client.js +11 -0
- package/dist/knobkit.browser.css +2 -0
- package/dist/knobkit.browser.js +151 -0
- package/dist/lib/bound.d.ts +12 -0
- package/dist/lib/bound.js +10 -0
- package/dist/lib/controls.d.ts +9 -0
- package/dist/lib/controls.js +35 -0
- package/dist/lib/ctx.d.ts +9 -0
- package/dist/lib/ctx.js +22 -0
- package/dist/lib/declare.d.ts +18 -0
- package/dist/lib/declare.js +43 -0
- package/dist/lib/event.d.ts +2 -0
- package/dist/lib/event.js +9 -0
- package/dist/lib/index.d.ts +10 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/knobkit.d.ts +19 -0
- package/dist/lib/knobkit.js +48 -0
- package/dist/lib/on.d.ts +2 -0
- package/dist/lib/on.js +1 -0
- package/dist/lib/stream.d.ts +1 -0
- package/dist/lib/stream.js +33 -0
- package/dist/lib/types.d.ts +48 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/widget.d.ts +7 -0
- package/dist/lib/widget.js +4 -0
- package/dist/lib/widgets/annotated-image.d.ts +14 -0
- package/dist/lib/widgets/annotated-image.js +16 -0
- package/dist/lib/widgets/audio.d.ts +10 -0
- package/dist/lib/widgets/audio.js +13 -0
- package/dist/lib/widgets/button.d.ts +11 -0
- package/dist/lib/widgets/button.js +17 -0
- package/dist/lib/widgets/chart.d.ts +20 -0
- package/dist/lib/widgets/chart.js +24 -0
- package/dist/lib/widgets/chat.d.ts +26 -0
- package/dist/lib/widgets/chat.js +24 -0
- package/dist/lib/widgets/checkbox-group.d.ts +4 -0
- package/dist/lib/widgets/checkbox-group.js +5 -0
- package/dist/lib/widgets/checkbox.d.ts +4 -0
- package/dist/lib/widgets/checkbox.js +4 -0
- package/dist/lib/widgets/code.d.ts +5 -0
- package/dist/lib/widgets/code.js +10 -0
- package/dist/lib/widgets/dropdown.d.ts +4 -0
- package/dist/lib/widgets/dropdown.js +4 -0
- package/dist/lib/widgets/embed.d.ts +5 -0
- package/dist/lib/widgets/embed.js +23 -0
- package/dist/lib/widgets/file.d.ts +11 -0
- package/dist/lib/widgets/file.js +15 -0
- package/dist/lib/widgets/frame.d.ts +18 -0
- package/dist/lib/widgets/frame.js +25 -0
- package/dist/lib/widgets/gallery.d.ts +12 -0
- package/dist/lib/widgets/gallery.js +17 -0
- package/dist/lib/widgets/highlighted-text.d.ts +12 -0
- package/dist/lib/widgets/highlighted-text.js +15 -0
- package/dist/lib/widgets/html.d.ts +9 -0
- package/dist/lib/widgets/html.js +12 -0
- package/dist/lib/widgets/image.d.ts +7 -0
- package/dist/lib/widgets/image.js +12 -0
- package/dist/lib/widgets/index.d.ts +31 -0
- package/dist/lib/widgets/index.js +31 -0
- package/dist/lib/widgets/json.d.ts +7 -0
- package/dist/lib/widgets/json.js +12 -0
- package/dist/lib/widgets/label.d.ts +15 -0
- package/dist/lib/widgets/label.js +18 -0
- package/dist/lib/widgets/layout.d.ts +21 -0
- package/dist/lib/widgets/layout.js +29 -0
- package/dist/lib/widgets/log.d.ts +8 -0
- package/dist/lib/widgets/log.js +15 -0
- package/dist/lib/widgets/mic.d.ts +19 -0
- package/dist/lib/widgets/mic.js +28 -0
- package/dist/lib/widgets/number.d.ts +5 -0
- package/dist/lib/widgets/number.js +4 -0
- package/dist/lib/widgets/output.d.ts +10 -0
- package/dist/lib/widgets/output.js +13 -0
- package/dist/lib/widgets/progress.d.ts +10 -0
- package/dist/lib/widgets/progress.js +15 -0
- package/dist/lib/widgets/radio.d.ts +4 -0
- package/dist/lib/widgets/radio.js +5 -0
- package/dist/lib/widgets/slider.d.ts +6 -0
- package/dist/lib/widgets/slider.js +6 -0
- package/dist/lib/widgets/table.d.ts +32 -0
- package/dist/lib/widgets/table.js +36 -0
- package/dist/lib/widgets/text.d.ts +4 -0
- package/dist/lib/widgets/text.js +4 -0
- package/dist/lib/widgets/upload.d.ts +3 -0
- package/dist/lib/widgets/upload.js +5 -0
- package/dist/lib/widgets/value.d.ts +9 -0
- package/dist/lib/widgets/value.js +20 -0
- package/dist/lib/widgets/video.d.ts +12 -0
- package/dist/lib/widgets/video.js +14 -0
- package/dist/lib/widgets/webcam.d.ts +21 -0
- package/dist/lib/widgets/webcam.js +29 -0
- package/dist/server/context.d.ts +2 -0
- package/dist/server/context.js +10 -0
- package/dist/server/serve.d.ts +5 -0
- package/dist/server/serve.js +131 -0
- package/package.json +71 -0
- package/src/cli/config.ts +83 -0
- package/src/cli/index.ts +82 -0
- package/src/cli/mount.ts +25 -0
- package/src/cli/serve.ts +22 -0
- package/src/client/app.test.tsx +70 -0
- package/src/client/app.tsx +62 -0
- package/src/client/browser-runtime.test.ts +22 -0
- package/src/client/browser.ts +3 -0
- package/src/client/context.ts +17 -0
- package/src/client/embed.test.tsx +58 -0
- package/src/client/entry.tsx +25 -0
- package/src/client/mount.test.tsx +36 -0
- package/src/client/mount.tsx +48 -0
- package/src/client/runtime.test.ts +64 -0
- package/src/client/runtime.ts +112 -0
- package/src/client/serve-stub.ts +3 -0
- package/src/client/styles.css +131 -0
- package/src/client/view.ts +16 -0
- package/src/client/widgets/accordion/accordion.css +35 -0
- package/src/client/widgets/accordion/index.tsx +17 -0
- package/src/client/widgets/annotated-image/annotated-image.css +62 -0
- package/src/client/widgets/annotated-image/index.tsx +73 -0
- package/src/client/widgets/audio/audio.css +6 -0
- package/src/client/widgets/audio/index.tsx +6 -0
- package/src/client/widgets/button/button.css +25 -0
- package/src/client/widgets/button/index.tsx +11 -0
- package/src/client/widgets/chart/chart.css +12 -0
- package/src/client/widgets/chart/index.tsx +63 -0
- package/src/client/widgets/chart/lazy.tsx +15 -0
- package/src/client/widgets/chat/chat.css +97 -0
- package/src/client/widgets/chat/index.tsx +121 -0
- package/src/client/widgets/checkbox/checkbox.css +15 -0
- package/src/client/widgets/checkbox/index.tsx +15 -0
- package/src/client/widgets/checkbox-group/checkbox-group.css +20 -0
- package/src/client/widgets/checkbox-group/index.tsx +22 -0
- package/src/client/widgets/code/code.css +31 -0
- package/src/client/widgets/code/index.tsx +108 -0
- package/src/client/widgets/code/lazy.tsx +16 -0
- package/src/client/widgets/dropdown/dropdown.css +0 -0
- package/src/client/widgets/dropdown/index.tsx +19 -0
- package/src/client/widgets/file/file.css +26 -0
- package/src/client/widgets/file/index.tsx +12 -0
- package/src/client/widgets/frame/frame.css +17 -0
- package/src/client/widgets/frame/index.tsx +15 -0
- package/src/client/widgets/gallery/gallery.css +26 -0
- package/src/client/widgets/gallery/index.tsx +18 -0
- package/src/client/widgets/highlighted-text/highlighted-text.css +21 -0
- package/src/client/widgets/highlighted-text/index.tsx +42 -0
- package/src/client/widgets/html/index.tsx +8 -0
- package/src/client/widgets/image/index.tsx +5 -0
- package/src/client/widgets/json/index.tsx +5 -0
- package/src/client/widgets/json/json.css +0 -0
- package/src/client/widgets/label/index.tsx +20 -0
- package/src/client/widgets/label/label.css +39 -0
- package/src/client/widgets/layout/index.tsx +14 -0
- package/src/client/widgets/log/index.tsx +5 -0
- package/src/client/widgets/log/log.css +0 -0
- package/src/client/widgets/mic/index.tsx +85 -0
- package/src/client/widgets/mic/mic.css +8 -0
- package/src/client/widgets/number/index.tsx +10 -0
- package/src/client/widgets/number/number.css +0 -0
- package/src/client/widgets/output/index.tsx +19 -0
- package/src/client/widgets/output/markdown.tsx +12 -0
- package/src/client/widgets/output/output.css +75 -0
- package/src/client/widgets/progress/index.tsx +14 -0
- package/src/client/widgets/progress/progress.css +26 -0
- package/src/client/widgets/radio/index.tsx +20 -0
- package/src/client/widgets/radio/radio.css +20 -0
- package/src/client/widgets/registry.tsx +71 -0
- package/src/client/widgets/slider/index.tsx +23 -0
- package/src/client/widgets/slider/slider.css +18 -0
- package/src/client/widgets/table/index.tsx +95 -0
- package/src/client/widgets/table/lazy.tsx +23 -0
- package/src/client/widgets/table/table.css +15 -0
- package/src/client/widgets/tabs/index.tsx +28 -0
- package/src/client/widgets/tabs/tabs.css +30 -0
- package/src/client/widgets/text/index.tsx +16 -0
- package/src/client/widgets/text/text.css +21 -0
- package/src/client/widgets/upload/index.tsx +30 -0
- package/src/client/widgets/upload/upload.css +30 -0
- package/src/client/widgets/video/index.tsx +10 -0
- package/src/client/widgets/video/video.css +8 -0
- package/src/client/widgets/webcam/index.tsx +81 -0
- package/src/client/widgets/webcam/webcam.css +46 -0
- package/src/css.d.ts +1 -0
- package/src/env.d.ts +1 -0
- package/src/lib/bound.ts +30 -0
- package/src/lib/controls.ts +36 -0
- package/src/lib/ctx.ts +31 -0
- package/src/lib/declare.test.ts +46 -0
- package/src/lib/declare.ts +74 -0
- package/src/lib/event.ts +12 -0
- package/src/lib/index.ts +21 -0
- package/src/lib/knobkit.ts +57 -0
- package/src/lib/on.ts +3 -0
- package/src/lib/stream.ts +38 -0
- package/src/lib/types.ts +63 -0
- package/src/lib/widget.ts +11 -0
- package/src/lib/widgets/annotated-image.ts +34 -0
- package/src/lib/widgets/audio.ts +20 -0
- package/src/lib/widgets/button.ts +27 -0
- package/src/lib/widgets/chart.ts +44 -0
- package/src/lib/widgets/chat.ts +43 -0
- package/src/lib/widgets/checkbox-group.ts +6 -0
- package/src/lib/widgets/checkbox.ts +5 -0
- package/src/lib/widgets/code.ts +11 -0
- package/src/lib/widgets/dropdown.ts +5 -0
- package/src/lib/widgets/embed.ts +26 -0
- package/src/lib/widgets/file.ts +23 -0
- package/src/lib/widgets/frame.ts +36 -0
- package/src/lib/widgets/gallery.ts +29 -0
- package/src/lib/widgets/highlighted-text.ts +29 -0
- package/src/lib/widgets/html.ts +18 -0
- package/src/lib/widgets/image.ts +18 -0
- package/src/lib/widgets/index.ts +31 -0
- package/src/lib/widgets/json.ts +18 -0
- package/src/lib/widgets/label.ts +29 -0
- package/src/lib/widgets/layout.ts +47 -0
- package/src/lib/widgets/log.ts +22 -0
- package/src/lib/widgets/mic.ts +42 -0
- package/src/lib/widgets/number.ts +5 -0
- package/src/lib/widgets/output.ts +20 -0
- package/src/lib/widgets/progress.ts +21 -0
- package/src/lib/widgets/radio.ts +6 -0
- package/src/lib/widgets/slider.ts +7 -0
- package/src/lib/widgets/table.ts +58 -0
- package/src/lib/widgets/text.ts +5 -0
- package/src/lib/widgets/upload.ts +6 -0
- package/src/lib/widgets/value.ts +28 -0
- package/src/lib/widgets/video.ts +22 -0
- package/src/lib/widgets/webcam.ts +46 -0
- package/src/server/context.ts +12 -0
- package/src/server/serve.test.ts +121 -0
- package/src/server/serve.ts +130 -0
- package/tsconfig.base.json +14 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface FileWidget extends Widget<{ name: string; url: string }> {
|
|
6
|
+
// Offer a file for download — the output counterpart to `upload`. Pass a URL (or data URL) and an
|
|
7
|
+
// optional display name; the name defaults to the URL's last path segment.
|
|
8
|
+
set(value: { name?: string; url: string } | string): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function file(): FileWidget {
|
|
12
|
+
return {
|
|
13
|
+
type: "file",
|
|
14
|
+
state: { name: "", url: "" },
|
|
15
|
+
...controls,
|
|
16
|
+
set(value: { name?: string; url: string } | string): void {
|
|
17
|
+
const v = typeof value === "string" ? { url: value } : value;
|
|
18
|
+
const b = bound(this);
|
|
19
|
+
b.edit(this, "set", ["url"], v.url);
|
|
20
|
+
b.edit(this, "set", ["name"], v.name ?? v.url.split("/").pop()?.split("?")[0] ?? "download");
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { event } from "../event.js";
|
|
2
|
+
import { bound } from "../bound.js";
|
|
3
|
+
import { controls } from "../controls.js";
|
|
4
|
+
import type { EventCtor, Widget } from "../types.js";
|
|
5
|
+
|
|
6
|
+
export interface FrameWidget extends Widget<{ src: string; doc: string }> {
|
|
7
|
+
sandbox?: string;
|
|
8
|
+
title: string;
|
|
9
|
+
loaded: EventCtor;
|
|
10
|
+
load(url: string): void;
|
|
11
|
+
show(doc: string): void;
|
|
12
|
+
clear(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function frame(opts: { src?: string; doc?: string; sandbox?: string; title?: string } = {}): FrameWidget {
|
|
16
|
+
return {
|
|
17
|
+
type: "frame",
|
|
18
|
+
state: { src: opts.src ?? "", doc: opts.doc ?? "" },
|
|
19
|
+
sandbox: opts.sandbox,
|
|
20
|
+
title: opts.title ?? "frame",
|
|
21
|
+
loaded: event("frame.loaded"),
|
|
22
|
+
...controls,
|
|
23
|
+
load(url: string): void {
|
|
24
|
+
bound(this).edit(this, "set", ["doc"], "");
|
|
25
|
+
bound(this).edit(this, "set", ["src"], url);
|
|
26
|
+
},
|
|
27
|
+
show(doc: string): void {
|
|
28
|
+
bound(this).edit(this, "set", ["src"], "");
|
|
29
|
+
bound(this).edit(this, "set", ["doc"], doc);
|
|
30
|
+
},
|
|
31
|
+
clear(): void {
|
|
32
|
+
bound(this).edit(this, "set", ["src"], "");
|
|
33
|
+
bound(this).edit(this, "set", ["doc"], "");
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface GalleryItem {
|
|
6
|
+
src: string; // URL or data URL
|
|
7
|
+
caption?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface GalleryWidget extends Widget<{ items: GalleryItem[] }> {
|
|
11
|
+
set(items: GalleryItem[]): void; // replace the whole grid
|
|
12
|
+
add(item: GalleryItem): void; // append one image
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// A grid of images (the canonical output for batched image generation). Not a layout container — its
|
|
16
|
+
// `items` are image records, not child widget keys.
|
|
17
|
+
export function gallery(): GalleryWidget {
|
|
18
|
+
return {
|
|
19
|
+
type: "gallery",
|
|
20
|
+
state: { items: [] },
|
|
21
|
+
...controls,
|
|
22
|
+
set(items: GalleryItem[]): void {
|
|
23
|
+
bound(this).edit(this, "set", ["items"], items);
|
|
24
|
+
},
|
|
25
|
+
add(item: GalleryItem): void {
|
|
26
|
+
bound(this).edit(this, "append", ["items"], item);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface HighlightSpan {
|
|
6
|
+
text: string;
|
|
7
|
+
label?: string | null; // null/omitted => plain, unhighlighted run of text
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface HighlightedTextWidget
|
|
11
|
+
extends Widget<{ value: HighlightSpan[]; colorMap: Record<string, string> }> {
|
|
12
|
+
// The canonical output for token classification / NER / diff: a sequence of text runs, each
|
|
13
|
+
// optionally tagged with a label that colors it. `colorMap` pins a color per label; unmapped
|
|
14
|
+
// labels get a stable auto color in the view.
|
|
15
|
+
set(value: HighlightSpan[], colorMap?: Record<string, string>): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function highlightedText(): HighlightedTextWidget {
|
|
19
|
+
return {
|
|
20
|
+
type: "highlightedText",
|
|
21
|
+
state: { value: [], colorMap: {} },
|
|
22
|
+
...controls,
|
|
23
|
+
set(value: HighlightSpan[], colorMap?: Record<string, string>): void {
|
|
24
|
+
const b = bound(this);
|
|
25
|
+
if (colorMap !== undefined) b.edit(this, "set", ["colorMap"], colorMap);
|
|
26
|
+
b.edit(this, "set", ["value"], value);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface HtmlWidget extends Widget<{ value: string }> {
|
|
6
|
+
set(value: string): void; // replace the rendered HTML (the escape hatch for custom markup)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function html(opts: { value?: string } = {}): HtmlWidget {
|
|
10
|
+
return {
|
|
11
|
+
type: "html",
|
|
12
|
+
state: { value: opts.value ?? "" },
|
|
13
|
+
...controls,
|
|
14
|
+
set(value: string): void {
|
|
15
|
+
bound(this).edit(this, "set", ["value"], value);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface ImageWidget extends Widget<{ src: string }> {
|
|
6
|
+
set(value: string): void; // set the displayed image (URL or data URL)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function image(): ImageWidget {
|
|
10
|
+
return {
|
|
11
|
+
type: "image",
|
|
12
|
+
state: { src: "" },
|
|
13
|
+
...controls,
|
|
14
|
+
set(value: string): void {
|
|
15
|
+
bound(this).edit(this, "set", ["src"], value);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export * from "./text.js";
|
|
2
|
+
export * from "./number.js";
|
|
3
|
+
export * from "./slider.js";
|
|
4
|
+
export * from "./code.js";
|
|
5
|
+
export * from "./table.js";
|
|
6
|
+
export * from "./chart.js";
|
|
7
|
+
export * from "./dropdown.js";
|
|
8
|
+
export * from "./checkbox.js";
|
|
9
|
+
export * from "./checkbox-group.js";
|
|
10
|
+
export * from "./radio.js";
|
|
11
|
+
export * from "./gallery.js";
|
|
12
|
+
export * from "./video.js";
|
|
13
|
+
export * from "./label.js";
|
|
14
|
+
export * from "./highlighted-text.js";
|
|
15
|
+
export * from "./annotated-image.js";
|
|
16
|
+
export * from "./file.js";
|
|
17
|
+
export * from "./progress.js";
|
|
18
|
+
export * from "./html.js";
|
|
19
|
+
export * from "./frame.js";
|
|
20
|
+
export * from "./upload.js";
|
|
21
|
+
export * from "./image.js";
|
|
22
|
+
export * from "./button.js";
|
|
23
|
+
export * from "./mic.js";
|
|
24
|
+
export * from "./chat.js";
|
|
25
|
+
export * from "./output.js";
|
|
26
|
+
export * from "./json.js";
|
|
27
|
+
export * from "./log.js";
|
|
28
|
+
export * from "./audio.js";
|
|
29
|
+
export * from "./webcam.js";
|
|
30
|
+
export * from "./layout.js";
|
|
31
|
+
export { embed } from "./embed.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface JsonWidget extends Widget<{ value: unknown }> {
|
|
6
|
+
set(value: unknown): void; // replace the displayed value
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function json(): JsonWidget {
|
|
10
|
+
return {
|
|
11
|
+
type: "json",
|
|
12
|
+
state: { value: null },
|
|
13
|
+
...controls,
|
|
14
|
+
set(value: unknown): void {
|
|
15
|
+
bound(this).edit(this, "set", ["value"], value);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface LabelClass {
|
|
6
|
+
label: string;
|
|
7
|
+
score: number; // 0..1
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface LabelWidget extends Widget<{ label: string; confidences: LabelClass[] }> {
|
|
11
|
+
// The classifier result: either a bare label, or a label with per-class confidences (rendered as
|
|
12
|
+
// bars). When only confidences are given, the top-scoring class becomes the headline label.
|
|
13
|
+
set(value: string | { label?: string; confidences?: LabelClass[] }): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function label(): LabelWidget {
|
|
17
|
+
return {
|
|
18
|
+
type: "label",
|
|
19
|
+
state: { label: "", confidences: [] },
|
|
20
|
+
...controls,
|
|
21
|
+
set(value: string | { label?: string; confidences?: LabelClass[] }): void {
|
|
22
|
+
const v = typeof value === "string" ? { label: value, confidences: [] as LabelClass[] } : value;
|
|
23
|
+
const b = bound(this);
|
|
24
|
+
if (v.confidences !== undefined) b.edit(this, "set", ["confidences"], v.confidences);
|
|
25
|
+
const top = v.label ?? v.confidences?.reduce((a, c) => (c.score > a.score ? c : a), v.confidences[0])?.label;
|
|
26
|
+
if (top !== undefined) b.edit(this, "set", ["label"], top);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface LayoutWidget extends Widget<{ items: string[] }> {
|
|
6
|
+
children: Widget<any>[];
|
|
7
|
+
add(child: Widget<any>): void;
|
|
8
|
+
remove(child: Widget<any>): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function container(type: string, children: Widget<any>[], props: Record<string, unknown> = {}): LayoutWidget {
|
|
12
|
+
return {
|
|
13
|
+
type,
|
|
14
|
+
state: { items: [] },
|
|
15
|
+
children,
|
|
16
|
+
...controls,
|
|
17
|
+
add(child: Widget<any>): void {
|
|
18
|
+
const b = bound(this);
|
|
19
|
+
b.edit(this, "append", ["items"], b.key(child));
|
|
20
|
+
},
|
|
21
|
+
async remove(child: Widget<any>): Promise<void> {
|
|
22
|
+
const b = bound(this);
|
|
23
|
+
const key = b.key(child);
|
|
24
|
+
const items = await b.read<string[]>(this, ["items"]);
|
|
25
|
+
b.edit(this, "set", ["items"], items.filter((k) => k !== key));
|
|
26
|
+
},
|
|
27
|
+
...props,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const row = (...children: Widget<any>[]): LayoutWidget => container("row", children);
|
|
32
|
+
export const col = (...children: Widget<any>[]): LayoutWidget => container("col", children);
|
|
33
|
+
export const grid = (children: Widget<any>[], opts: { cols?: number } = {}): LayoutWidget =>
|
|
34
|
+
container("grid", children, { cols: opts.cols ?? 2 });
|
|
35
|
+
|
|
36
|
+
// Tabbed container: each panel is a labelled child. `labels` rides alongside `items` (the child keys)
|
|
37
|
+
// in the same order; the active tab is view-local state, so switching tabs never round-trips.
|
|
38
|
+
export const tabs = (panels: { label: string; content: Widget<any> }[]): LayoutWidget =>
|
|
39
|
+
container(
|
|
40
|
+
"tabs",
|
|
41
|
+
panels.map((p) => p.content),
|
|
42
|
+
{ labels: panels.map((p) => p.label) },
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// A single collapsible section. `open` is the initial state; toggling it is view-local.
|
|
46
|
+
export const accordion = (opts: { label: string; open?: boolean }, ...children: Widget<any>[]): LayoutWidget =>
|
|
47
|
+
container("accordion", children, { label: opts.label, open: opts.open ?? true });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface LogWidget extends Widget<{ lines: string[] }> {
|
|
6
|
+
push(line: string): void;
|
|
7
|
+
all(): Promise<string[]>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function log(): LogWidget {
|
|
11
|
+
return {
|
|
12
|
+
type: "log",
|
|
13
|
+
state: { lines: [] },
|
|
14
|
+
...controls,
|
|
15
|
+
push(line: string): void {
|
|
16
|
+
bound(this).edit(this, "append", ["lines"], line);
|
|
17
|
+
},
|
|
18
|
+
all(): Promise<string[]> {
|
|
19
|
+
return bound(this).read<string[]>(this, ["lines"]);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { event } from "../event.js";
|
|
2
|
+
import { bound } from "../bound.js";
|
|
3
|
+
import { controls } from "../controls.js";
|
|
4
|
+
import type { EventCtor, Widget } from "../types.js";
|
|
5
|
+
|
|
6
|
+
export interface MicWidget extends Widget<{ live: boolean }> {
|
|
7
|
+
clip: EventCtor<Float32Array>;
|
|
8
|
+
toggled: EventCtor<boolean>;
|
|
9
|
+
every: number;
|
|
10
|
+
control: boolean;
|
|
11
|
+
hold: boolean;
|
|
12
|
+
start(): void;
|
|
13
|
+
stop(): void;
|
|
14
|
+
toggle(): Promise<void>;
|
|
15
|
+
live(): Promise<boolean>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function mic(opts: { every?: number; control?: boolean; hold?: boolean } = {}): MicWidget {
|
|
19
|
+
return {
|
|
20
|
+
type: "mic",
|
|
21
|
+
state: { live: false },
|
|
22
|
+
clip: event<Float32Array>("mic.clip"),
|
|
23
|
+
toggled: event<boolean>("mic.toggled"),
|
|
24
|
+
every: opts.every ?? 0,
|
|
25
|
+
control: opts.control ?? true,
|
|
26
|
+
hold: opts.hold ?? true,
|
|
27
|
+
...controls,
|
|
28
|
+
start(): void {
|
|
29
|
+
bound(this).edit(this, "set", ["live"], true);
|
|
30
|
+
},
|
|
31
|
+
stop(): void {
|
|
32
|
+
bound(this).edit(this, "set", ["live"], false);
|
|
33
|
+
},
|
|
34
|
+
async toggle(): Promise<void> {
|
|
35
|
+
const live = await bound(this).read<boolean>(this, ["live"]);
|
|
36
|
+
bound(this).edit(this, "set", ["live"], !live);
|
|
37
|
+
},
|
|
38
|
+
live(): Promise<boolean> {
|
|
39
|
+
return bound(this).read<boolean>(this, ["live"]);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface OutputWidget extends Widget<{ value: string }> {
|
|
6
|
+
format: "text" | "markdown"; // how the view renders `value`; "text" is plain, "markdown" renders GFM
|
|
7
|
+
set(value: string): void; // replace the displayed text
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function output(opts: { format?: "text" | "markdown" } = {}): OutputWidget {
|
|
11
|
+
return {
|
|
12
|
+
type: "output",
|
|
13
|
+
state: { value: "" },
|
|
14
|
+
format: opts.format ?? "text",
|
|
15
|
+
...controls,
|
|
16
|
+
set(value: string): void {
|
|
17
|
+
bound(this).edit(this, "set", ["value"], value);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface ProgressWidget extends Widget<{ value: number; label: string }> {
|
|
6
|
+
// Drive a determinate bar: `value` is a 0..1 fraction, with an optional caption.
|
|
7
|
+
set(value: number, label?: string): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function progress(opts: { label?: string } = {}): ProgressWidget {
|
|
11
|
+
return {
|
|
12
|
+
type: "progress",
|
|
13
|
+
state: { value: 0, label: opts.label ?? "" },
|
|
14
|
+
...controls,
|
|
15
|
+
set(value: number, label?: string): void {
|
|
16
|
+
const b = bound(this);
|
|
17
|
+
b.edit(this, "set", ["value"], value);
|
|
18
|
+
if (label !== undefined) b.edit(this, "set", ["label"], label);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { value } from "./value.js";
|
|
2
|
+
|
|
3
|
+
// Single-select from a fixed set, like dropdown but rendered as radios.
|
|
4
|
+
export function radio(opts: { choices: string[]; value?: string }) {
|
|
5
|
+
return value("radio", opts.value ?? opts.choices[0]!, { choices: opts.choices });
|
|
6
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { value } from "./value.js";
|
|
2
|
+
|
|
3
|
+
export function slider(opts: { value?: number; min?: number; max?: number; step?: number } = {}) {
|
|
4
|
+
const min = opts.min ?? 0;
|
|
5
|
+
const max = opts.max ?? 100;
|
|
6
|
+
return value("slider", opts.value ?? min, { min, max, step: opts.step ?? 1 });
|
|
7
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { event } from "../event.js";
|
|
2
|
+
import { bound } from "../bound.js";
|
|
3
|
+
import { controls } from "../controls.js";
|
|
4
|
+
import type { EventCtor, Widget } from "../types.js";
|
|
5
|
+
|
|
6
|
+
export interface Column {
|
|
7
|
+
key: string; // maps a column to the per-row object key (RevoGrid `prop`)
|
|
8
|
+
label?: string; // header text; defaults to `key`
|
|
9
|
+
type?: "text" | "number"; // cell editor/parsing hint
|
|
10
|
+
width?: number;
|
|
11
|
+
}
|
|
12
|
+
export type Row = Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
export interface TableWidget extends Widget<{ columns: Column[]; rows: Row[] }> {
|
|
15
|
+
edited: EventCtor<{ row: number; key: string; value: unknown }>; // a cell (or pasted cell) changed
|
|
16
|
+
editable: boolean;
|
|
17
|
+
maxHeight: number; // height ceiling in px; the grid fits its rows up to this, then scrolls
|
|
18
|
+
data(): Promise<Row[]>; // read all rows
|
|
19
|
+
columnsOf(): Promise<Column[]>; // read the column defs
|
|
20
|
+
setRows(rows: Row[]): void; // replace all rows
|
|
21
|
+
setColumns(columns: Column[]): void; // replace the column defs
|
|
22
|
+
addRow(row: Row): void; // append one row
|
|
23
|
+
setCell(row: number, key: string, value: unknown): void; // set one cell by row index + column key
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// A tabular widget rendered by RevoGrid (virtualized, range-select, copy/paste, in-cell editing). State
|
|
27
|
+
// is the uniform shape — `{ columns, rows }` — and every mutation is a structured edit by path, so a
|
|
28
|
+
// cell edit is `set ["rows", r, key]` and a new row is `append ["rows"]`; the grid stays controlled by
|
|
29
|
+
// the store on both tiers. Defaults to read-only (a display table); pass `editable: true` to let the
|
|
30
|
+
// user edit cells.
|
|
31
|
+
export function table(opts: { columns?: Column[]; rows?: Row[]; editable?: boolean; maxHeight?: number } = {}): TableWidget {
|
|
32
|
+
return {
|
|
33
|
+
type: "table",
|
|
34
|
+
state: { columns: opts.columns ?? [], rows: opts.rows ?? [] },
|
|
35
|
+
edited: event<{ row: number; key: string; value: unknown }>("table.edited"),
|
|
36
|
+
editable: opts.editable ?? false,
|
|
37
|
+
maxHeight: opts.maxHeight ?? 500,
|
|
38
|
+
...controls,
|
|
39
|
+
data(): Promise<Row[]> {
|
|
40
|
+
return bound(this).read<Row[]>(this, ["rows"]);
|
|
41
|
+
},
|
|
42
|
+
columnsOf(): Promise<Column[]> {
|
|
43
|
+
return bound(this).read<Column[]>(this, ["columns"]);
|
|
44
|
+
},
|
|
45
|
+
setRows(rows: Row[]): void {
|
|
46
|
+
bound(this).edit(this, "set", ["rows"], rows);
|
|
47
|
+
},
|
|
48
|
+
setColumns(columns: Column[]): void {
|
|
49
|
+
bound(this).edit(this, "set", ["columns"], columns);
|
|
50
|
+
},
|
|
51
|
+
addRow(row: Row): void {
|
|
52
|
+
bound(this).edit(this, "append", ["rows"], row);
|
|
53
|
+
},
|
|
54
|
+
setCell(row: number, key: string, value: unknown): void {
|
|
55
|
+
bound(this).edit(this, "set", ["rows", row, key], value);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { event } from "../event.js";
|
|
2
|
+
import { bound } from "../bound.js";
|
|
3
|
+
import { controls } from "../controls.js";
|
|
4
|
+
import type { EventCtor, Widget } from "../types.js";
|
|
5
|
+
|
|
6
|
+
export interface ValueWidget<S> extends Widget<{ value: S }> {
|
|
7
|
+
changed: EventCtor<S>;
|
|
8
|
+
value(): Promise<S>; // read the current input value
|
|
9
|
+
set(value: S): void; // set it programmatically
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// A self-managing value input: it holds a single `value` attribute; its view (in `client`) edits that
|
|
13
|
+
// value locally as the user types and emits `changed` for handlers that care.
|
|
14
|
+
export function value<S>(type: string, initial: S, props: Record<string, unknown> = {}): ValueWidget<S> {
|
|
15
|
+
return {
|
|
16
|
+
type,
|
|
17
|
+
state: { value: initial },
|
|
18
|
+
changed: event<S>(`${type}.changed`),
|
|
19
|
+
...controls,
|
|
20
|
+
value(): Promise<S> {
|
|
21
|
+
return bound(this).read<S>(this, ["value"]);
|
|
22
|
+
},
|
|
23
|
+
set(v: S): void {
|
|
24
|
+
bound(this).edit(this, "set", ["value"], v);
|
|
25
|
+
},
|
|
26
|
+
...props,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { bound } from "../bound.js";
|
|
2
|
+
import { controls } from "../controls.js";
|
|
3
|
+
import type { Widget } from "../types.js";
|
|
4
|
+
|
|
5
|
+
export interface VideoWidget extends Widget<{ src: string }> {
|
|
6
|
+
autoplay: boolean;
|
|
7
|
+
loop: boolean;
|
|
8
|
+
set(value: string): void; // set the video source (URL or data URL)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function video(opts: { autoplay?: boolean; loop?: boolean } = {}): VideoWidget {
|
|
12
|
+
return {
|
|
13
|
+
type: "video",
|
|
14
|
+
state: { src: "" },
|
|
15
|
+
autoplay: opts.autoplay ?? false,
|
|
16
|
+
loop: opts.loop ?? false,
|
|
17
|
+
...controls,
|
|
18
|
+
set(value: string): void {
|
|
19
|
+
bound(this).edit(this, "set", ["src"], value);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { event } from "../event.js";
|
|
2
|
+
import { bound } from "../bound.js";
|
|
3
|
+
import { controls } from "../controls.js";
|
|
4
|
+
import type { EventCtor, Widget } from "../types.js";
|
|
5
|
+
|
|
6
|
+
export interface WebcamWidget extends Widget<{ live: boolean }> {
|
|
7
|
+
frame: EventCtor<string>;
|
|
8
|
+
toggled: EventCtor<boolean>;
|
|
9
|
+
every: number;
|
|
10
|
+
control: boolean;
|
|
11
|
+
preview: boolean;
|
|
12
|
+
facing: "user" | "environment";
|
|
13
|
+
start(): void;
|
|
14
|
+
stop(): void;
|
|
15
|
+
toggle(): Promise<void>;
|
|
16
|
+
live(): Promise<boolean>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function webcam(
|
|
20
|
+
opts: { every?: number; control?: boolean; preview?: boolean; facing?: "user" | "environment" } = {},
|
|
21
|
+
): WebcamWidget {
|
|
22
|
+
return {
|
|
23
|
+
type: "webcam",
|
|
24
|
+
state: { live: false },
|
|
25
|
+
frame: event<string>("webcam.frame"),
|
|
26
|
+
toggled: event<boolean>("webcam.toggled"),
|
|
27
|
+
every: opts.every ?? 0, // 0 = preview only; >0 = a frame every N ms
|
|
28
|
+
control: opts.control ?? true,
|
|
29
|
+
preview: opts.preview ?? true,
|
|
30
|
+
facing: opts.facing ?? "user",
|
|
31
|
+
...controls,
|
|
32
|
+
start(): void {
|
|
33
|
+
bound(this).edit(this, "set", ["live"], true);
|
|
34
|
+
},
|
|
35
|
+
stop(): void {
|
|
36
|
+
bound(this).edit(this, "set", ["live"], false);
|
|
37
|
+
},
|
|
38
|
+
async toggle(): Promise<void> {
|
|
39
|
+
const live = await bound(this).read<boolean>(this, ["live"]);
|
|
40
|
+
bound(this).edit(this, "set", ["live"], !live);
|
|
41
|
+
},
|
|
42
|
+
live(): Promise<boolean> {
|
|
43
|
+
return bound(this).read<boolean>(this, ["live"]);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { setBoundResolver, type Bound } from "../lib/bound.js";
|
|
3
|
+
|
|
4
|
+
// Per-request context binding for handlers. Each socket request runs inside `run(bound, …)`, so a
|
|
5
|
+
// widget method's `bound(this)` resolves to that request's snapshot reader / event sender even across
|
|
6
|
+
// awaits and concurrent requests.
|
|
7
|
+
const store = new AsyncLocalStorage<Bound>();
|
|
8
|
+
setBoundResolver(() => store.getStore());
|
|
9
|
+
|
|
10
|
+
export function run<T>(bound: Bound, fn: () => T): T {
|
|
11
|
+
return store.run(bound, fn);
|
|
12
|
+
}
|