@openlearning/widget-framework 1.0.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.
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import type { WidgetConfigBase, LearnerViewProps, SetupViewProps } from "./types";
3
+ export interface DevAppProps<T extends WidgetConfigBase = WidgetConfigBase> {
4
+ LearnerViewComponent: React.ComponentType<LearnerViewProps<T>>;
5
+ SetupViewComponent: React.ComponentType<SetupViewProps<T>>;
6
+ defaultConfig: T;
7
+ }
8
+ /**
9
+ * Generic development app for testing LearnerView and SetupView components locally
10
+ * Use ?mode=setup to test setup view, defaults to learner view
11
+ */
12
+ export declare function DevApp<T extends WidgetConfigBase = WidgetConfigBase>({ LearnerViewComponent, SetupViewComponent, defaultConfig, }: DevAppProps<T>): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=DevApp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevApp.d.ts","sourceRoot":"","sources":["../src/DevApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAyB,MAAM,SAAS,CAAC;AAEzG,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IACxE,oBAAoB,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,kBAAkB,EAAE,KAAK,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,aAAa,EAAE,CAAC,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EAAE,EACpE,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,GACd,EAAE,WAAW,CAAC,CAAC,CAAC,2CAiDhB"}
package/dist/DevApp.js ADDED
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Generic development app for testing LearnerView and SetupView components locally
4
+ * Use ?mode=setup to test setup view, defaults to learner view
5
+ */
6
+ export function DevApp({ LearnerViewComponent, SetupViewComponent, defaultConfig, }) {
7
+ const handleConfigSave = (newConfig) => {
8
+ console.log("[Mock PostMessage Out] SAVE_CONFIG:", newConfig);
9
+ };
10
+ const complete = () => {
11
+ console.log("[Mock PostMessage Out] COMPLETE");
12
+ };
13
+ const share = (attachments, thumbnail) => {
14
+ console.log("[Mock PostMessage Out] SHARE:", { attachments, thumbnail });
15
+ };
16
+ const resize = (height) => {
17
+ console.log("[Mock PostMessage Out] RESIZE:", height);
18
+ };
19
+ const saveLearnerData = (name, value) => {
20
+ console.log("[Mock PostMessage Out] SET_VALUE:", { name, value });
21
+ };
22
+ const reinit = () => {
23
+ console.log("[Mock PostMessage Out] REINIT");
24
+ };
25
+ const urlParams = new URLSearchParams(window.location.search);
26
+ const currentMode = urlParams.get("mode") || "learner";
27
+ return (_jsx(_Fragment, { children: currentMode === "setup" ? (_jsx(SetupViewComponent, { config: defaultConfig, onChange: handleConfigSave, onResize: resize, onReinit: reinit })) : (_jsx(LearnerViewComponent, { config: defaultConfig, onComplete: complete, onShare: share, onResize: resize, onSave: saveLearnerData, onReinit: reinit })) }));
28
+ }
29
+ //# sourceMappingURL=DevApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevApp.js","sourceRoot":"","sources":["../src/DevApp.tsx"],"names":[],"mappings":";AASA;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAgD,EACpE,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,GACE;IACf,MAAM,gBAAgB,GAAG,CAAC,SAAY,EAAE,EAAE;QACxC,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,SAAS,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IACjD,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,CAAC,WAAyB,EAAE,SAAiB,EAAE,EAAE;QAC7D,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,EAAE;QAChC,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,MAAM,CAAC,CAAC;IACxD,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,IAAY,EAAE,KAAgB,EAAE,EAAE;QACzD,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC/C,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9D,MAAM,WAAW,GAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAyB,IAAI,SAAS,CAAC;IAEhF,OAAO,CACL,4BACG,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,CACzB,KAAC,kBAAkB,IACjB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAChB,CACH,CAAC,CAAC,CAAC,CACF,KAAC,oBAAoB,IACnB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,QAAQ,EACpB,OAAO,EAAE,KAAK,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,MAAM,GAChB,CACH,GACA,CACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ import type { WidgetConfigBase, Attachment, JSONValue, LearnerViewProps } from "./types";
3
+ export interface LearnerEntryProps<T extends WidgetConfigBase = WidgetConfigBase> {
4
+ config: T | null;
5
+ onComplete: () => void;
6
+ onShare: (attachments: Attachment[], thumbnail: string) => void;
7
+ onResize: (height: number) => void;
8
+ onSave: (name: string, value: JSONValue) => void;
9
+ onReinit: () => void;
10
+ }
11
+ /**
12
+ * Factory function to create a learner entry point
13
+ * Pass your LearnerView component that accepts LearnerViewProps<T>
14
+ */
15
+ export declare function createLearnerEntry<T extends WidgetConfigBase = WidgetConfigBase>(LearnerViewComponent: React.ComponentType<LearnerViewProps<T>>): void;
16
+ //# sourceMappingURL=createLearnerEntry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createLearnerEntry.d.ts","sourceRoot":"","sources":["../src/createLearnerEntry.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIzF,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IAC9E,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;IACjB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACjD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EAC9E,oBAAoB,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,QA+D/D"}
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import ReactDOM from "react-dom/client";
4
+ import { useParentMessaging } from "./useParentMessaging";
5
+ import { useWidgetConfig } from "./useWidgetConfig";
6
+ const DEFAULT_HEIGHT = 700;
7
+ /**
8
+ * Factory function to create a learner entry point
9
+ * Pass your LearnerView component that accepts LearnerViewProps<T>
10
+ */
11
+ export function createLearnerEntry(LearnerViewComponent) {
12
+ const InitLearnerView = () => {
13
+ const { globalConfig, subscribe, sendMessage } = useParentMessaging();
14
+ const config = useWidgetConfig(globalConfig, subscribe);
15
+ const complete = React.useCallback(() => {
16
+ sendMessage("complete");
17
+ }, [sendMessage]);
18
+ const share = React.useCallback((attachments, thumbnail) => {
19
+ sendMessage("share", { attachments, thumbnail });
20
+ }, [sendMessage]);
21
+ const resize = React.useCallback((height) => {
22
+ sendMessage("resize", { height });
23
+ }, [sendMessage]);
24
+ const save = React.useCallback((name, value) => {
25
+ sendMessage("set", { name, value });
26
+ }, [sendMessage]);
27
+ const reinit = React.useCallback(() => {
28
+ sendMessage("ready");
29
+ }, [sendMessage]);
30
+ React.useEffect(() => {
31
+ // Notify parent that widget is ready
32
+ sendMessage("ready");
33
+ sendMessage("resize", { height: DEFAULT_HEIGHT });
34
+ }, [sendMessage]);
35
+ if (!config) {
36
+ return _jsx("div", { className: "p-4", children: "Loading..." });
37
+ }
38
+ return (_jsx(LearnerViewComponent, { config: config, onComplete: complete, onShare: share, onResize: resize, onSave: save, onReinit: reinit }));
39
+ };
40
+ // Render the component
41
+ ReactDOM.createRoot(document.getElementById("root")).render(_jsx(React.StrictMode, { children: _jsx(InitLearnerView, {}) }));
42
+ }
43
+ //# sourceMappingURL=createLearnerEntry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createLearnerEntry.js","sourceRoot":"","sources":["../src/createLearnerEntry.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,kBAAkB,CAAC;AAExC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAWpD,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,oBAA8D;IAE9D,MAAM,eAAe,GAAG,GAAG,EAAE;QAC3B,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,kBAAkB,EAAK,CAAC;QACzE,MAAM,MAAM,GAAG,eAAe,CAAI,YAAY,EAAE,SAAS,CAAC,CAAC;QAE3D,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;YACtC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1B,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QAElB,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAC7B,CAAC,WAAyB,EAAE,SAAiB,EAAE,EAAE;YAC/C,WAAW,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;QACnD,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;QAEF,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAC9B,CAAC,MAAc,EAAE,EAAE;YACjB,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QACpC,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;QAEF,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAC5B,CAAC,IAAY,EAAE,KAAgB,EAAE,EAAE;YACjC,WAAW,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtC,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;QAEF,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;YACpC,WAAW,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QAElB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;YACnB,qCAAqC;YACrC,WAAW,CAAC,OAAO,CAAC,CAAC;YACrB,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;QACpD,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QAElB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,cAAK,SAAS,EAAC,KAAK,2BAAiB,CAAC;QAC/C,CAAC;QAED,OAAO,CACL,KAAC,oBAAoB,IACnB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,QAAQ,EACpB,OAAO,EAAE,KAAK,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,EACZ,QAAQ,EAAE,MAAM,GAChB,CACH,CAAC;IACJ,CAAC,CAAC;IAEF,uBAAuB;IACvB,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAE,CAAC,CAAC,MAAM,CAC1D,KAAC,KAAK,CAAC,UAAU,cACf,KAAC,eAAe,KAAG,GACF,CACpB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import type { WidgetConfigBase, SetupViewProps } from "./types";
3
+ export interface SetupEntryProps<T extends WidgetConfigBase = WidgetConfigBase> {
4
+ config: T | null;
5
+ onChange: (value: T) => void;
6
+ onResize: (height: number) => void;
7
+ onReinit: () => void;
8
+ }
9
+ /**
10
+ * Factory function to create a setup entry point
11
+ * Pass your SetupView component that accepts SetupViewProps<T> and default config
12
+ */
13
+ export declare function createSetupEntry<T extends WidgetConfigBase = WidgetConfigBase>(SetupViewComponent: React.ComponentType<SetupViewProps<T>>, defaultConfig: T): void;
14
+ //# sourceMappingURL=createSetupEntry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSetupEntry.d.ts","sourceRoot":"","sources":["../src/createSetupEntry.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,gBAAgB,EAAa,cAAc,EAAE,MAAM,SAAS,CAAC;AAI3E,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IAC5E,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;IACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAID;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EAC5E,kBAAkB,EAAE,KAAK,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAC1D,aAAa,EAAE,CAAC,QAoDjB"}
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import ReactDOM from "react-dom/client";
4
+ import { useParentMessaging } from "./useParentMessaging";
5
+ import { useWidgetConfig } from "./useWidgetConfig";
6
+ const DEFAULT_HEIGHT = 700;
7
+ /**
8
+ * Factory function to create a setup entry point
9
+ * Pass your SetupView component that accepts SetupViewProps<T> and default config
10
+ */
11
+ export function createSetupEntry(SetupViewComponent, defaultConfig) {
12
+ const InitSetupView = () => {
13
+ const { globalConfig, subscribe, sendMessage } = useParentMessaging();
14
+ const config = useWidgetConfig(globalConfig || defaultConfig, subscribe);
15
+ const handleConfigChange = React.useCallback((value) => {
16
+ sendMessage("set", { name: "config", value });
17
+ }, [sendMessage]);
18
+ const resize = React.useCallback((height) => {
19
+ sendMessage("resize", { height });
20
+ }, [sendMessage]);
21
+ const reinit = React.useCallback(() => {
22
+ sendMessage("ready");
23
+ }, [sendMessage]);
24
+ React.useEffect(() => {
25
+ // Notify parent that widget is ready and resize
26
+ sendMessage("resize", { height: DEFAULT_HEIGHT });
27
+ }, [sendMessage]);
28
+ if (!config) {
29
+ return _jsx("div", { className: "p-4", children: "Loading..." });
30
+ }
31
+ return (_jsx(SetupViewComponent, { config: config, onChange: handleConfigChange, onResize: resize, onReinit: reinit }));
32
+ };
33
+ // Render the component
34
+ ReactDOM.createRoot(document.getElementById("root")).render(_jsx(React.StrictMode, { children: _jsx(InitSetupView, {}) }));
35
+ }
36
+ //# sourceMappingURL=createSetupEntry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSetupEntry.js","sourceRoot":"","sources":["../src/createSetupEntry.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,kBAAkB,CAAC;AAExC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AASpD,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,kBAA0D,EAC1D,aAAgB;IAEhB,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,kBAAkB,EAAK,CAAC;QACzE,MAAM,MAAM,GAAG,eAAe,CAC5B,YAAY,IAAI,aAAa,EAC7B,SAAS,CACV,CAAC;QAEF,MAAM,kBAAkB,GAAG,KAAK,CAAC,WAAW,CAC1C,CAAC,KAAQ,EAAE,EAAE;YACX,WAAW,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAChD,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;QAEF,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAC9B,CAAC,MAAc,EAAE,EAAE;YACjB,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QACpC,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;QAEF,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;YACpC,WAAW,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QAElB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;YACnB,gDAAgD;YAChD,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;QACpD,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QAElB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,cAAK,SAAS,EAAC,KAAK,2BAAiB,CAAC;QAC/C,CAAC;QAED,OAAO,CACL,KAAC,kBAAkB,IACjB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAChB,CACH,CAAC;IACJ,CAAC,CAAC;IAEF,uBAAuB;IACvB,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAE,CAAC,CAAC,MAAM,CAC1D,KAAC,KAAK,CAAC,UAAU,cACf,KAAC,aAAa,KAAG,GACA,CACpB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Widget Framework
3
+ * Shared utilities for building OpenLearning widgets
4
+ */
5
+ export { createLearnerEntry, type LearnerEntryProps, } from "./createLearnerEntry";
6
+ export { createSetupEntry, type SetupEntryProps, } from "./createSetupEntry";
7
+ export { DevApp, type DevAppProps } from "./DevApp";
8
+ export { defineWidgetProject, type WidgetProjectConfig, } from "./setupProject";
9
+ export { useParentMessaging } from "./useParentMessaging";
10
+ export { useWidgetConfig } from "./useWidgetConfig";
11
+ export type { JSONValue, Attachment, WidgetConfigBase, LearnerViewProps, SetupViewProps, ParentMessage, ParentMessagingCallbacks, } from "./types";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,kBAAkB,EAClB,KAAK,iBAAiB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,gBAAgB,EAChB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EACL,mBAAmB,EACnB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EACV,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,wBAAwB,GACzB,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Widget Framework
3
+ * Shared utilities for building OpenLearning widgets
4
+ */
5
+ export { createLearnerEntry, } from "./createLearnerEntry";
6
+ export { createSetupEntry, } from "./createSetupEntry";
7
+ export { DevApp } from "./DevApp";
8
+ export { defineWidgetProject, } from "./setupProject";
9
+ export { useParentMessaging } from "./useParentMessaging";
10
+ export { useWidgetConfig } from "./useWidgetConfig";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,kBAAkB,GAEnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAoB,MAAM,UAAU,CAAC;AACpD,OAAO,EACL,mBAAmB,GAEpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type React from "react";
2
+ import type { WidgetConfigBase, LearnerViewProps, SetupViewProps } from "./types";
3
+ /**
4
+ * Configuration object that defines a widget project
5
+ * Create this once and import it in your entry files
6
+ */
7
+ export interface WidgetProjectConfig<T extends WidgetConfigBase = WidgetConfigBase> {
8
+ LearnerView: React.ComponentType<LearnerViewProps<T>>;
9
+ SetupView: React.ComponentType<SetupViewProps<T>>;
10
+ defaultConfig: T;
11
+ devMode?: boolean;
12
+ }
13
+ /**
14
+ * Creates a validated project configuration
15
+ * Use in a central config file (e.g., src/widget.config.ts)
16
+ */
17
+ export declare function defineWidgetProject<T extends WidgetConfigBase = WidgetConfigBase>(config: WidgetProjectConfig<T>): WidgetProjectConfig<T>;
18
+ //# sourceMappingURL=setupProject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setupProject.d.ts","sourceRoot":"","sources":["../src/setupProject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAElF;;;GAGG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IAChF,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EAC/E,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAC7B,mBAAmB,CAAC,CAAC,CAAC,CAExB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Creates a validated project configuration
3
+ * Use in a central config file (e.g., src/widget.config.ts)
4
+ */
5
+ export function defineWidgetProject(config) {
6
+ return config;
7
+ }
8
+ //# sourceMappingURL=setupProject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setupProject.js","sourceRoot":"","sources":["../src/setupProject.ts"],"names":[],"mappings":"AAcA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA8B;IAE9B,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Core widget types - projects extend these with their specific config types
3
+ */
4
+ export type JSONValue = string | number | boolean | null | {
5
+ [x: string]: JSONValue;
6
+ } | JSONValue[];
7
+ export interface Attachment {
8
+ url: string;
9
+ title: string;
10
+ contentType: string;
11
+ height: number;
12
+ }
13
+ /**
14
+ * Base interface for widget config
15
+ */
16
+ export type WidgetConfigBase = JSONValue;
17
+ /**
18
+ * Standard props for Learner View components
19
+ */
20
+ export interface LearnerViewProps<T extends WidgetConfigBase = WidgetConfigBase> {
21
+ config: T;
22
+ onSave?: (name: string, value: JSONValue) => void;
23
+ onShare?: (attachments: Attachment[], thumbnail: string) => void;
24
+ onComplete?: () => void;
25
+ onResize?: (height: number) => void;
26
+ onReinit?: () => void;
27
+ }
28
+ /**
29
+ * Standard props for Setup View components
30
+ */
31
+ export interface SetupViewProps<T extends WidgetConfigBase = WidgetConfigBase> {
32
+ config: T;
33
+ onChange?: (config: JSONValue) => void;
34
+ onResize?: (height: number) => void;
35
+ onReinit?: () => void;
36
+ }
37
+ /**
38
+ * Parent message types for widget communication
39
+ */
40
+ export interface ParentMessage {
41
+ action: "init" | "ready" | "resize" | "complete" | "share" | "set" | "error";
42
+ setup?: {
43
+ config: WidgetConfigBase;
44
+ };
45
+ height?: number;
46
+ name?: string;
47
+ value?: JSONValue;
48
+ attachments?: Attachment[];
49
+ thumbnail?: string;
50
+ }
51
+ /**
52
+ * Callbacks for parent messaging
53
+ */
54
+ export interface ParentMessagingCallbacks {
55
+ onResize?: (height: number) => void;
56
+ onConfigInit?: (config: WidgetConfigBase) => void;
57
+ }
58
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAC1B,SAAS,EAAE,CAAC;AAEhB,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IAC7E,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IAC3E,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EACF,MAAM,GACN,OAAO,GACP,QAAQ,GACR,UAAU,GACV,OAAO,GACP,KAAK,GACL,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,gBAAgB,CAAA;KAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACnD"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Core widget types - projects extend these with their specific config types
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,11 @@
1
+ import type { WidgetConfigBase } from "./types";
2
+ /**
3
+ * Hook to handle parent window messaging
4
+ * Manages config state and subscription pattern for widget communication
5
+ */
6
+ export declare function useParentMessaging<T extends WidgetConfigBase = WidgetConfigBase>(): {
7
+ globalConfig: T;
8
+ subscribe: (callback: (config: T) => void) => () => void;
9
+ sendMessage: (action: string, payload?: Record<string, unknown>) => void;
10
+ };
11
+ //# sourceMappingURL=useParentMessaging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useParentMessaging.d.ts","sourceRoot":"","sources":["../src/useParentMessaging.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,gBAAgB,EAAiB,MAAM,SAAS,CAAC;AAE1E;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;;0BA6C/B,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI;0BAWnB,MAAM,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;EASzF"}
@@ -0,0 +1,66 @@
1
+ import React from "react";
2
+ /**
3
+ * Hook to handle parent window messaging
4
+ * Manages config state and subscription pattern for widget communication
5
+ */
6
+ export function useParentMessaging() {
7
+ const globalConfigRef = React.useRef(null);
8
+ const subscribersRef = React.useRef(new Set());
9
+ const [, setTrigger] = React.useState({});
10
+ React.useEffect(() => {
11
+ const handleMessage = (event) => {
12
+ console.log("Received message:", event);
13
+ if (event.source !== window.parent)
14
+ return;
15
+ let eventData = null;
16
+ if (typeof event.data === "string") {
17
+ try {
18
+ eventData = JSON.parse(event.data);
19
+ }
20
+ catch {
21
+ return;
22
+ }
23
+ }
24
+ else if (event.data && typeof event.data === "object") {
25
+ eventData = event.data;
26
+ }
27
+ if (!eventData || eventData.action !== "init")
28
+ return;
29
+ const { setup } = eventData;
30
+ if (setup?.config) {
31
+ globalConfigRef.current = setup.config;
32
+ }
33
+ // Notify all subscribers with the new config
34
+ subscribersRef.current.forEach((callback) => {
35
+ if (globalConfigRef.current) {
36
+ callback(globalConfigRef.current);
37
+ }
38
+ });
39
+ // Trigger re-render to reflect new config
40
+ setTrigger({});
41
+ };
42
+ window.addEventListener("message", handleMessage);
43
+ return () => {
44
+ window.removeEventListener("message", handleMessage);
45
+ };
46
+ }, []);
47
+ const subscribe = React.useCallback((callback) => {
48
+ subscribersRef.current.add(callback);
49
+ // Call immediately if config already loaded
50
+ if (globalConfigRef.current) {
51
+ callback(globalConfigRef.current);
52
+ }
53
+ return () => {
54
+ subscribersRef.current.delete(callback);
55
+ };
56
+ }, []);
57
+ const sendMessage = React.useCallback((action, payload) => {
58
+ window.parent.postMessage({ action, ...payload }, "*");
59
+ }, []);
60
+ return {
61
+ globalConfig: globalConfigRef.current,
62
+ subscribe,
63
+ sendMessage,
64
+ };
65
+ }
66
+ //# sourceMappingURL=useParentMessaging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useParentMessaging.js","sourceRoot":"","sources":["../src/useParentMessaging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,eAAe,GAAG,KAAK,CAAC,MAAM,CAAW,IAAI,CAAC,CAAC;IACrD,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,GAAG,EAAuB,CAAC,CAAC;IACpE,MAAM,CAAC,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAE1C,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,aAAa,GAAG,CAAC,KAA4B,EAAE,EAAE;YACrD,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;YACxC,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;gBAAE,OAAO;YAE3C,IAAI,SAAS,GAAyB,IAAI,CAAC;YAC3C,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACnC,IAAI,CAAC;oBACH,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAkB,CAAC;gBACtD,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO;gBACT,CAAC;YACH,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACxD,SAAS,GAAG,KAAK,CAAC,IAAqB,CAAC;YAC1C,CAAC;YAED,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,MAAM;gBAAE,OAAO;YAEtD,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;YAC5B,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;gBAClB,eAAe,CAAC,OAAO,GAAG,KAAK,CAAC,MAAW,CAAC;YAC9C,CAAC;YAED,6CAA6C;YAC7C,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;gBAC1C,IAAI,eAAe,CAAC,OAAO,EAAE,CAAC;oBAC5B,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,0CAA0C;YAC1C,UAAU,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC,CAAC;QAEF,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAClD,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACvD,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,QAA6B,EAAE,EAAE;QACpE,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,4CAA4C;QAC5C,IAAI,eAAe,CAAC,OAAO,EAAE,CAAC;YAC5B,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,GAAG,EAAE;YACV,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,MAAc,EAAE,OAAiC,EAAE,EAAE;QAC1F,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,YAAY,EAAE,eAAe,CAAC,OAAO;QACrC,SAAS;QACT,WAAW;KACZ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { WidgetConfigBase } from "./types";
2
+ /**
3
+ * Hook to use widget config with subscription pattern
4
+ * Handles config state updates from parent messaging
5
+ */
6
+ export declare function useWidgetConfig<T extends WidgetConfigBase = WidgetConfigBase>(globalConfig: T | null, subscribe: (callback: (config: T) => void) => () => void): T;
7
+ //# sourceMappingURL=useWidgetConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWidgetConfig.d.ts","sourceRoot":"","sources":["../src/useWidgetConfig.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EAC3E,YAAY,EAAE,CAAC,GAAG,IAAI,EACtB,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,KAiBzD"}
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ /**
3
+ * Hook to use widget config with subscription pattern
4
+ * Handles config state updates from parent messaging
5
+ */
6
+ export function useWidgetConfig(globalConfig, subscribe) {
7
+ const [config, setConfig] = React.useState(globalConfig);
8
+ React.useEffect(() => {
9
+ if (globalConfig) {
10
+ setConfig(globalConfig);
11
+ }
12
+ const unsubscribe = subscribe((newConfig) => {
13
+ setConfig(newConfig);
14
+ });
15
+ return unsubscribe;
16
+ }, [globalConfig, subscribe]);
17
+ return config;
18
+ }
19
+ //# sourceMappingURL=useWidgetConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWidgetConfig.js","sourceRoot":"","sources":["../src/useWidgetConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,YAAsB,EACtB,SAAwD;IAExD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAW,YAAY,CAAC,CAAC;IAEnE,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,YAAY,EAAE,CAAC;YACjB,SAAS,CAAC,YAAY,CAAC,CAAC;QAC1B,CAAC;QAED,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,SAAY,EAAE,EAAE;YAC7C,SAAS,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC;IACrB,CAAC,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;IAE9B,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@openlearning/widget-framework",
3
+ "version": "1.0.0",
4
+ "description": "Framework for building OpenLearning widgets with parent-window messaging and configuration management",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "OpenLearning",
8
+ "homepage": "https://widgets.openlearning.com",
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "react": "^19.2.0",
22
+ "react-dom": "^19.2.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/react": "^19.2.5",
26
+ "typescript": "~5.9.3"
27
+ },
28
+ "scripts": {
29
+ "build": "tsc",
30
+ "dev": "tsc --watch"
31
+ }
32
+ }