@elite-dangerous-plugin-framework/react 0.0.1-pre1

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/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # @elite-dangerous-plugin-framework/react
2
+
3
+ This contains helpers for creating React-based EDPF plugins.
4
+
5
+ ## Getting Started
6
+
7
+ TODO
@@ -0,0 +1,18 @@
1
+ //#region rolldown:runtime
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, symbols) => {
4
+ let target = {};
5
+ for (var name in all) {
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ }
11
+ if (symbols) {
12
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ }
14
+ return target;
15
+ };
16
+
17
+ //#endregion
18
+ export { __exportAll };
@@ -0,0 +1,2 @@
1
+ import { index_d_exports } from "./v1alpha/index.js";
2
+ export { index_d_exports as V1Alpha };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { v1alpha_exports } from "./v1alpha/index.js";
2
+
3
+ export { v1alpha_exports as V1Alpha };
@@ -0,0 +1,35 @@
1
+ import { PluginContextV1Alpha, PluginSettingsContextV1Alpha } from "@elite-dangerous-plugin-framework/core/v1alpha";
2
+ import * as react0 from "react";
3
+
4
+ //#region src/v1alpha/context.d.ts
5
+ /**
6
+ * Context that exposes a `PluginContext` instance passed from EDPF. This is only present on the main Plugin Element (→ not on settings, overlay, etc).
7
+ *
8
+ * This specific context shall only be used for Plugins that use the `v1alpha` manifest version.
9
+ *
10
+ * Use `useContext(PluginContext)` to get the instance. The instance is guaranteed to never be null if used within `makePluginV1Alpha`.
11
+ *
12
+ *
13
+ */
14
+ declare const PluginContext: react0.Context<PluginContextV1Alpha>;
15
+ /**
16
+ * Helper for getting the plugin context via a hook
17
+ */
18
+ declare function usePluginContext(): PluginContextV1Alpha;
19
+ /**
20
+ * Context that exposes a `SettingsContext` instance passed from EDPF. This is only present on the settings Element.
21
+ *
22
+ * This specific context shall only be used for Plugins that use the `v1alpha` manifest version.
23
+ *
24
+ * Use `useContext(SettingsContext)` to get the instance. The instance is guaranteed to never be null if used within `makePluginV1Alpha`.
25
+ *
26
+ *
27
+ */
28
+ declare const SettingsContext: react0.Context<PluginSettingsContextV1Alpha>;
29
+ /**
30
+ * Helper for getting the settings context via a hook
31
+ */
32
+ declare function useSettingsContext(): PluginSettingsContextV1Alpha;
33
+ //#endregion
34
+ export { PluginContext, SettingsContext, usePluginContext, useSettingsContext };
35
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { createContext, useContext } from "react";
2
+
3
+ //#region src/v1alpha/context.ts
4
+ /**
5
+ * Context that exposes a `PluginContext` instance passed from EDPF. This is only present on the main Plugin Element (→ not on settings, overlay, etc).
6
+ *
7
+ * This specific context shall only be used for Plugins that use the `v1alpha` manifest version.
8
+ *
9
+ * Use `useContext(PluginContext)` to get the instance. The instance is guaranteed to never be null if used within `makePluginV1Alpha`.
10
+ *
11
+ *
12
+ */
13
+ const PluginContext = createContext(null);
14
+ /**
15
+ * Helper for getting the plugin context via a hook
16
+ */
17
+ function usePluginContext() {
18
+ return useContext(PluginContext);
19
+ }
20
+ /**
21
+ * Context that exposes a `SettingsContext` instance passed from EDPF. This is only present on the settings Element.
22
+ *
23
+ * This specific context shall only be used for Plugins that use the `v1alpha` manifest version.
24
+ *
25
+ * Use `useContext(SettingsContext)` to get the instance. The instance is guaranteed to never be null if used within `makePluginV1Alpha`.
26
+ *
27
+ *
28
+ */
29
+ const SettingsContext = createContext(null);
30
+ /**
31
+ * Helper for getting the settings context via a hook
32
+ */
33
+ function useSettingsContext() {
34
+ return useContext(SettingsContext);
35
+ }
36
+
37
+ //#endregion
38
+ export { PluginContext, SettingsContext, usePluginContext, useSettingsContext };
39
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../src/v1alpha/context.ts"],"sourcesContent":["import {\n PluginSettingsContextV1Alpha,\n type PluginContextV1Alpha,\n} from \"@elite-dangerous-plugin-framework/core/v1alpha\";\nimport { createContext, useContext } from \"react\";\n\n/**\n * Context that exposes a `PluginContext` instance passed from EDPF. This is only present on the main Plugin Element (→ not on settings, overlay, etc).\n *\n * This specific context shall only be used for Plugins that use the `v1alpha` manifest version.\n *\n * Use `useContext(PluginContext)` to get the instance. The instance is guaranteed to never be null if used within `makePluginV1Alpha`.\n *\n *\n */\nexport const PluginContext = createContext<PluginContextV1Alpha>(null!);\n\n/**\n * Helper for getting the plugin context via a hook\n */\nexport function usePluginContext() {\n return useContext(PluginContext);\n}\n\n/**\n * Context that exposes a `SettingsContext` instance passed from EDPF. This is only present on the settings Element.\n *\n * This specific context shall only be used for Plugins that use the `v1alpha` manifest version.\n *\n * Use `useContext(SettingsContext)` to get the instance. The instance is guaranteed to never be null if used within `makePluginV1Alpha`.\n *\n *\n */\nexport const SettingsContext = createContext<PluginSettingsContextV1Alpha>(\n null!,\n);\n\n/**\n * Helper for getting the settings context via a hook\n */\nexport function useSettingsContext() {\n return useContext(SettingsContext);\n}\n"],"mappings":";;;;;;;;;;;;AAeA,MAAa,gBAAgB,cAAoC,KAAM;;;;AAKvE,SAAgB,mBAAmB;AACjC,QAAO,WAAW,cAAc;;;;;;;;;;;AAYlC,MAAa,kBAAkB,cAC7B,KACD;;;;AAKD,SAAgB,qBAAqB;AACnC,QAAO,WAAW,gBAAgB"}
@@ -0,0 +1,3 @@
1
+ import { useBundledResource } from "./useBundledResource.js";
2
+ import { useJournalEvents } from "./useJournalEvents.js";
3
+ import { usePluginSetting, useTranslation } from "./usePluginSetting.js";
@@ -0,0 +1,3 @@
1
+ import { useBundledResource } from "./useBundledResource.js";
2
+ import { useJournalEvents } from "./useJournalEvents.js";
3
+ import { usePluginSetting, useTranslation } from "./usePluginSetting.js";
@@ -0,0 +1,9 @@
1
+ //#region src/v1alpha/hooks/useBundledResource.d.ts
2
+ /**
3
+ * This is a simple hook that will give you the asset name to use. It essentially just prepends the path to the asset server
4
+ * @param pathInFrontendDir the relative path to your plugin's `frontend` folder.
5
+ */
6
+ declare function useBundledResource(pathInFrontendDir: string): string;
7
+ //#endregion
8
+ export { useBundledResource };
9
+ //# sourceMappingURL=useBundledResource.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { PluginContext } from "../context.js";
2
+ import { useContext } from "react";
3
+
4
+ //#region src/v1alpha/hooks/useBundledResource.ts
5
+ /**
6
+ * This is a simple hook that will give you the asset name to use. It essentially just prepends the path to the asset server
7
+ * @param pathInFrontendDir the relative path to your plugin's `frontend` folder.
8
+ */
9
+ function useBundledResource(pathInFrontendDir) {
10
+ const ctx = useContext(PluginContext);
11
+ if (pathInFrontendDir.startsWith("/")) pathInFrontendDir = pathInFrontendDir.substring(1);
12
+ return ctx.assetsBase + pathInFrontendDir;
13
+ }
14
+
15
+ //#endregion
16
+ export { useBundledResource };
17
+ //# sourceMappingURL=useBundledResource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBundledResource.js","names":[],"sources":["../../../src/v1alpha/hooks/useBundledResource.ts"],"sourcesContent":["import { useContext } from \"react\";\nimport { PluginContext } from \"../context.js\";\n\n/**\n * This is a simple hook that will give you the asset name to use. It essentially just prepends the path to the asset server\n * @param pathInFrontendDir the relative path to your plugin's `frontend` folder.\n */\nexport function useBundledResource(pathInFrontendDir: string): string {\n const ctx = useContext(PluginContext);\n if (pathInFrontendDir.startsWith(\"/\")) {\n pathInFrontendDir = pathInFrontendDir.substring(1);\n }\n return ctx.assetsBase + pathInFrontendDir;\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,mBAAmB,mBAAmC;CACpE,MAAM,MAAM,WAAW,cAAc;AACrC,KAAI,kBAAkB,WAAW,IAAI,CACnC,qBAAoB,kBAAkB,UAAU,EAAE;AAEpD,QAAO,IAAI,aAAa"}
@@ -0,0 +1,46 @@
1
+ import { JournalEvent, JournalEvent_BI } from "@elite-dangerous-plugin-framework/journal";
2
+
3
+ //#region src/v1alpha/hooks/useJournalEvents.d.ts
4
+ type Mode = "raw" | "jsonBigint" | "jsonSimple";
5
+ type ResponseTypeByMode = {
6
+ raw: string;
7
+ jsonBigint: JournalEvent_BI;
8
+ jsonSimple: JournalEvent;
9
+ };
10
+ /**
11
+ * This hook accepts a callback that is invoked whenever the plugin receives a batch of new journal items.
12
+ * Do note multiple CMDR's files are send in separate batches.
13
+ *
14
+ * Note that you must provide a `mode`. The mode will determine how the journal items are transformed before being passed to the callback.
15
+ * - `raw` - events are not altered at all and not parsed at all. Each event is a `string`.
16
+ * - `jsonBigint` - events are converted and get strong typing. Integer numbers are parsed as BigInt's
17
+ * - `jsonSimple` - events are converted and get strong typing. Parsing is done using the regular `JSON.parse`
18
+ *
19
+ * If you need help choosing:
20
+ * - do you rely on IDs in your plugin? → pick `jsonBigint`
21
+ * - else, pick `jsonSimple`
22
+ * - if you have some very odd use case where you need to event as string, do pick `raw`
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * function Example() {
27
+ * const [lastEventName, setLastEventName] = useState("");
28
+ * useJournalEvents("jsonSimple", ({ events }) =>
29
+ * setLastEventName(events[events.length - 1].event),
30
+ * );
31
+ *
32
+ * return <div>Last event name: {lastEventName ?? "(awaiting first event)"}</div>
33
+ * }
34
+ * ```
35
+ *
36
+ * @param mode one of `raw` | `jsonBigint` | `jsonSimple`. See function-block comment for more info
37
+ * @param cb The callback invoked whenever a new batch of journals is received. Do note that you get different typings based on the mode you pick!
38
+ */
39
+ declare function useJournalEvents<T extends Mode>(mode: T, cb: (payload: {
40
+ events: ResponseTypeByMode[T][];
41
+ cmdr: string;
42
+ file: string;
43
+ }) => void): undefined;
44
+ //#endregion
45
+ export { useJournalEvents };
46
+ //# sourceMappingURL=useJournalEvents.d.ts.map
@@ -0,0 +1,69 @@
1
+ import { PluginContext } from "../context.js";
2
+ import { useContext, useEffect, useRef } from "react";
3
+ import { parseWithBigInt, parseWithLossyIntegers } from "@elite-dangerous-plugin-framework/journal";
4
+
5
+ //#region src/v1alpha/hooks/useJournalEvents.ts
6
+ /**
7
+ * This hook accepts a callback that is invoked whenever the plugin receives a batch of new journal items.
8
+ * Do note multiple CMDR's files are send in separate batches.
9
+ *
10
+ * Note that you must provide a `mode`. The mode will determine how the journal items are transformed before being passed to the callback.
11
+ * - `raw` - events are not altered at all and not parsed at all. Each event is a `string`.
12
+ * - `jsonBigint` - events are converted and get strong typing. Integer numbers are parsed as BigInt's
13
+ * - `jsonSimple` - events are converted and get strong typing. Parsing is done using the regular `JSON.parse`
14
+ *
15
+ * If you need help choosing:
16
+ * - do you rely on IDs in your plugin? → pick `jsonBigint`
17
+ * - else, pick `jsonSimple`
18
+ * - if you have some very odd use case where you need to event as string, do pick `raw`
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * function Example() {
23
+ * const [lastEventName, setLastEventName] = useState("");
24
+ * useJournalEvents("jsonSimple", ({ events }) =>
25
+ * setLastEventName(events[events.length - 1].event),
26
+ * );
27
+ *
28
+ * return <div>Last event name: {lastEventName ?? "(awaiting first event)"}</div>
29
+ * }
30
+ * ```
31
+ *
32
+ * @param mode one of `raw` | `jsonBigint` | `jsonSimple`. See function-block comment for more info
33
+ * @param cb The callback invoked whenever a new batch of journals is received. Do note that you get different typings based on the mode you pick!
34
+ */
35
+ function useJournalEvents(mode, cb) {
36
+ const ctx = useContext(PluginContext);
37
+ const cbRef = useRef(cb);
38
+ useEffect(() => {
39
+ cbRef.current = cb;
40
+ }, [cb]);
41
+ useEffect(() => {
42
+ if (!ctx) return;
43
+ return ctx.registerEventListener((evs) => {
44
+ if (evs.length === 0) return;
45
+ const { cmdr, file } = evs[0];
46
+ let events;
47
+ switch (mode) {
48
+ case "raw":
49
+ events = evs.map((e) => e.event);
50
+ break;
51
+ case "jsonBigint":
52
+ events = evs.map((e) => parseWithBigInt(e.event));
53
+ break;
54
+ case "jsonSimple":
55
+ events = evs.map((e) => parseWithLossyIntegers(e.event));
56
+ break;
57
+ }
58
+ cbRef.current({
59
+ events,
60
+ cmdr,
61
+ file
62
+ });
63
+ });
64
+ }, [ctx, mode]);
65
+ }
66
+
67
+ //#endregion
68
+ export { useJournalEvents };
69
+ //# sourceMappingURL=useJournalEvents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useJournalEvents.js","names":[],"sources":["../../../src/v1alpha/hooks/useJournalEvents.ts"],"sourcesContent":["import { useContext, useEffect, useRef } from \"react\";\nimport { PluginContext } from \"../context.js\";\nimport {\n JournalEvent,\n JournalEvent_BI,\n parseWithBigInt,\n parseWithLossyIntegers,\n} from \"@elite-dangerous-plugin-framework/journal\";\n\ntype Mode = \"raw\" | \"jsonBigint\" | \"jsonSimple\";\ntype ResponseTypeByMode = {\n raw: string;\n jsonBigint: JournalEvent_BI;\n jsonSimple: JournalEvent;\n};\n\n/**\n * This hook accepts a callback that is invoked whenever the plugin receives a batch of new journal items.\n * Do note multiple CMDR's files are send in separate batches.\n *\n * Note that you must provide a `mode`. The mode will determine how the journal items are transformed before being passed to the callback.\n * - `raw` - events are not altered at all and not parsed at all. Each event is a `string`.\n * - `jsonBigint` - events are converted and get strong typing. Integer numbers are parsed as BigInt's\n * - `jsonSimple` - events are converted and get strong typing. Parsing is done using the regular `JSON.parse`\n *\n * If you need help choosing:\n * - do you rely on IDs in your plugin? → pick `jsonBigint`\n * - else, pick `jsonSimple`\n * - if you have some very odd use case where you need to event as string, do pick `raw`\n *\n * @example\n * ```tsx\n * function Example() {\n * const [lastEventName, setLastEventName] = useState(\"\");\n * useJournalEvents(\"jsonSimple\", ({ events }) =>\n * setLastEventName(events[events.length - 1].event),\n * );\n *\n * return <div>Last event name: {lastEventName ?? \"(awaiting first event)\"}</div>\n * }\n * ```\n *\n * @param mode one of `raw` | `jsonBigint` | `jsonSimple`. See function-block comment for more info\n * @param cb The callback invoked whenever a new batch of journals is received. Do note that you get different typings based on the mode you pick!\n */\nexport function useJournalEvents<T extends Mode>(\n mode: T,\n cb: (payload: {\n events: ResponseTypeByMode[T][];\n cmdr: string;\n file: string;\n }) => void,\n): undefined {\n const ctx = useContext(PluginContext);\n\n // Keep latest callback without re-subscribing\n const cbRef = useRef(cb);\n useEffect(() => {\n cbRef.current = cb;\n }, [cb]);\n\n useEffect(() => {\n if (!ctx) return;\n\n const unsubscribe = ctx.registerEventListener((evs) => {\n if (evs.length === 0) return;\n\n const { cmdr, file } = evs[0];\n\n let events: JournalEvent[] | JournalEvent_BI[] | string[];\n switch (mode) {\n case \"raw\":\n events = evs.map((e) => e.event);\n break;\n case \"jsonBigint\":\n events = evs.map((e) => parseWithBigInt(e.event));\n break;\n case \"jsonSimple\":\n events = evs.map((e) => parseWithLossyIntegers(e.event));\n break;\n }\n\n cbRef.current({ events: events as any, cmdr, file });\n });\n\n return unsubscribe;\n }, [ctx, mode]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,SAAgB,iBACd,MACA,IAKW;CACX,MAAM,MAAM,WAAW,cAAc;CAGrC,MAAM,QAAQ,OAAO,GAAG;AACxB,iBAAgB;AACd,QAAM,UAAU;IACf,CAAC,GAAG,CAAC;AAER,iBAAgB;AACd,MAAI,CAAC,IAAK;AAuBV,SArBoB,IAAI,uBAAuB,QAAQ;AACrD,OAAI,IAAI,WAAW,EAAG;GAEtB,MAAM,EAAE,MAAM,SAAS,IAAI;GAE3B,IAAI;AACJ,WAAQ,MAAR;IACE,KAAK;AACH,cAAS,IAAI,KAAK,MAAM,EAAE,MAAM;AAChC;IACF,KAAK;AACH,cAAS,IAAI,KAAK,MAAM,gBAAgB,EAAE,MAAM,CAAC;AACjD;IACF,KAAK;AACH,cAAS,IAAI,KAAK,MAAM,uBAAuB,EAAE,MAAM,CAAC;AACxD;;AAGJ,SAAM,QAAQ;IAAU;IAAe;IAAM;IAAM,CAAC;IACpD;IAGD,CAAC,KAAK,KAAK,CAAC"}
@@ -0,0 +1,47 @@
1
+ //#region src/v1alpha/hooks/usePluginSetting.d.ts
2
+ /**
3
+ * Fetch and listen for updates on a specific setting. Also exposes a callback to write a setting, which is only possible if the first segment is identical to the plugin ID (=it's the plugin's own setting)
4
+ * @param pluginKey a setting key. You can omit the plugin ID. So `pluginname.some.key` and `.some.key` are identical. You can also listen to other plugin's settings, **if** they are public (identified by the last segment being Uppercase).
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * interface SettingValues {
9
+ * preferredShipSite: "coriolis" | "edsy";
10
+ * preferredSystemSite: "inara" | "spansh" | "edsm";
11
+ * }
12
+ *
13
+ * function Example() {
14
+ * // we dont write in this example
15
+ * const [settings, _, isLoaded] =
16
+ * usePluginSetting<SettingValues>(".preferredTooling");
17
+ *
18
+ * if (!isLoaded) {
19
+ * return <div>Loading…</div>;
20
+ * }
21
+ * if (!settings) {
22
+ * return <div>No setting set…</div>;
23
+ * }
24
+ *
25
+ * return (
26
+ * <div>
27
+ * Preferred Ship Site: {settings.preferredShipSite}, System Site:{" "}
28
+ * {settings.preferredSystemSite}
29
+ * </div>
30
+ * );
31
+ * }
32
+ * ```
33
+ *
34
+ * @returns a tuple containing the setting, the write callback to invoke, and a bool if it has finished the initial load (to differentiate between fetching and fetched but missing).
35
+ */
36
+ declare function usePluginSetting<T = any>(pluginKey: string): readonly [T | undefined, (val: T | undefined) => void, boolean];
37
+ type Locale = "en" | "es" | "fr" | "de" | "pt" | "it" | "ja" | "ko" | "zh" | "ru";
38
+ /**
39
+ * Wrapper that gets you the currently selected language. Use this if you are providing translations.
40
+ * You cannot change the locale from the plugin as the setting belongs to the bundled `core` plugin. Instead, users must change it in the settings pane.
41
+ *
42
+ * @returns a tuple of `[currentLocale, initialLoadComplete]`
43
+ */
44
+ declare function useTranslation(): [Locale | undefined, boolean];
45
+ //#endregion
46
+ export { usePluginSetting, useTranslation };
47
+ //# sourceMappingURL=usePluginSetting.d.ts.map
@@ -0,0 +1,93 @@
1
+ import { PluginContext } from "../context.js";
2
+ import { useContext, useEffect, useState } from "react";
3
+
4
+ //#region src/v1alpha/hooks/usePluginSetting.tsx
5
+ /**
6
+ * Fetch and listen for updates on a specific setting. Also exposes a callback to write a setting, which is only possible if the first segment is identical to the plugin ID (=it's the plugin's own setting)
7
+ * @param pluginKey a setting key. You can omit the plugin ID. So `pluginname.some.key` and `.some.key` are identical. You can also listen to other plugin's settings, **if** they are public (identified by the last segment being Uppercase).
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * interface SettingValues {
12
+ * preferredShipSite: "coriolis" | "edsy";
13
+ * preferredSystemSite: "inara" | "spansh" | "edsm";
14
+ * }
15
+ *
16
+ * function Example() {
17
+ * // we dont write in this example
18
+ * const [settings, _, isLoaded] =
19
+ * usePluginSetting<SettingValues>(".preferredTooling");
20
+ *
21
+ * if (!isLoaded) {
22
+ * return <div>Loading…</div>;
23
+ * }
24
+ * if (!settings) {
25
+ * return <div>No setting set…</div>;
26
+ * }
27
+ *
28
+ * return (
29
+ * <div>
30
+ * Preferred Ship Site: {settings.preferredShipSite}, System Site:{" "}
31
+ * {settings.preferredSystemSite}
32
+ * </div>
33
+ * );
34
+ * }
35
+ * ```
36
+ *
37
+ * @returns a tuple containing the setting, the write callback to invoke, and a bool if it has finished the initial load (to differentiate between fetching and fetched but missing).
38
+ */
39
+ function usePluginSetting(pluginKey) {
40
+ const [state, setState] = useState(void 0);
41
+ const [finishedLoading, setFinishedLoading] = useState(false);
42
+ const ctx = useContext(PluginContext);
43
+ const normalizedPluginKey = pluginKey.startsWith(".") ? ctx.pluginMeta.id + pluginKey : pluginKey;
44
+ useEffect(() => {
45
+ ctx.Capabilities.Settings.getSetting(normalizedPluginKey).then((e) => {
46
+ setState(e);
47
+ setFinishedLoading(true);
48
+ }).catch((err) => {
49
+ console.error(`Your Hook to get the setting ${normalizedPluginKey} has failed. This is likely because it is invalid. Please make sure you either access a public setting from a different plugin, or, when accessing an internal setting, make sure the format is correct. Do note you can omit the plugin id and just start with a dot`, {
50
+ err,
51
+ normalizedPluginKey,
52
+ pluginKey
53
+ });
54
+ throw err;
55
+ });
56
+ return ctx.Capabilities.Settings.registerSettingsChangedListener((k, v) => {
57
+ if (k !== normalizedPluginKey) return;
58
+ setState(v);
59
+ });
60
+ });
61
+ const writeSetting = (val) => {
62
+ ctx.Capabilities.Settings.writeSetting(normalizedPluginKey, val).then((e) => {
63
+ setState(e);
64
+ }).catch((err) => {
65
+ console.error(`Your Hook tried to write ${normalizedPluginKey} and failed. This is likely because you are trying to write another plugin's settings, which is not permitted.`, {
66
+ err,
67
+ normalizedPluginKey,
68
+ pluginKey,
69
+ ownPluginId: ctx.pluginMeta.id
70
+ });
71
+ throw err;
72
+ });
73
+ };
74
+ return [
75
+ state,
76
+ writeSetting,
77
+ finishedLoading
78
+ ];
79
+ }
80
+ /**
81
+ * Wrapper that gets you the currently selected language. Use this if you are providing translations.
82
+ * You cannot change the locale from the plugin as the setting belongs to the bundled `core` plugin. Instead, users must change it in the settings pane.
83
+ *
84
+ * @returns a tuple of `[currentLocale, initialLoadComplete]`
85
+ */
86
+ function useTranslation() {
87
+ const [lang, _, loaded] = usePluginSetting("core.Locale");
88
+ return [lang, loaded];
89
+ }
90
+
91
+ //#endregion
92
+ export { usePluginSetting, useTranslation };
93
+ //# sourceMappingURL=usePluginSetting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePluginSetting.js","names":[],"sources":["../../../src/v1alpha/hooks/usePluginSetting.tsx"],"sourcesContent":["import { memo, useContext, useEffect, useState } from \"react\";\nimport { PluginContext } from \"../context.js\";\n\n/**\n * Fetch and listen for updates on a specific setting. Also exposes a callback to write a setting, which is only possible if the first segment is identical to the plugin ID (=it's the plugin's own setting)\n * @param pluginKey a setting key. You can omit the plugin ID. So `pluginname.some.key` and `.some.key` are identical. You can also listen to other plugin's settings, **if** they are public (identified by the last segment being Uppercase).\n *\n * @example\n * ```tsx\n * interface SettingValues {\n * preferredShipSite: \"coriolis\" | \"edsy\";\n * preferredSystemSite: \"inara\" | \"spansh\" | \"edsm\";\n * }\n *\n * function Example() {\n * // we dont write in this example\n * const [settings, _, isLoaded] =\n * usePluginSetting<SettingValues>(\".preferredTooling\");\n *\n * if (!isLoaded) {\n * return <div>Loading…</div>;\n * }\n * if (!settings) {\n * return <div>No setting set…</div>;\n * }\n *\n * return (\n * <div>\n * Preferred Ship Site: {settings.preferredShipSite}, System Site:{\" \"}\n * {settings.preferredSystemSite}\n * </div>\n * );\n * }\n * ```\n *\n * @returns a tuple containing the setting, the write callback to invoke, and a bool if it has finished the initial load (to differentiate between fetching and fetched but missing).\n */\nexport function usePluginSetting<T = any>(pluginKey: string) {\n const [state, setState] = useState<T | undefined>(undefined);\n const [finishedLoading, setFinishedLoading] = useState(false);\n const ctx = useContext(PluginContext);\n\n const normalizedPluginKey = pluginKey.startsWith(\".\")\n ? ctx.pluginMeta.id + pluginKey\n : pluginKey;\n\n useEffect(() => {\n // fetch initial state immediately\n ctx.Capabilities.Settings.getSetting(normalizedPluginKey)\n .then((e) => {\n setState(e as any);\n setFinishedLoading(true);\n })\n .catch((err) => {\n console.error(\n `Your Hook to get the setting ${normalizedPluginKey} has failed. This is likely because it is invalid. Please make sure you either access a public setting from a different plugin, or, when accessing an internal setting, make sure the format is correct. Do note you can omit the plugin id and just start with a dot`,\n { err, normalizedPluginKey, pluginKey },\n );\n throw err;\n });\n\n return ctx.Capabilities.Settings.registerSettingsChangedListener((k, v) => {\n if (k !== normalizedPluginKey) {\n // this is a setting update not captured by this hook\n return;\n }\n setState(v as any);\n });\n });\n\n const writeSetting = (val: T | undefined) => {\n ctx.Capabilities.Settings.writeSetting(normalizedPluginKey, val)\n .then((e) => {\n setState(e);\n })\n .catch((err) => {\n console.error(\n `Your Hook tried to write ${normalizedPluginKey} and failed. This is likely because you are trying to write another plugin's settings, which is not permitted.`,\n {\n err,\n normalizedPluginKey,\n pluginKey,\n ownPluginId: ctx.pluginMeta.id,\n },\n );\n throw err;\n });\n };\n\n return [state, writeSetting, finishedLoading] as const;\n}\n\ntype Locale =\n | \"en\"\n | \"es\"\n | \"fr\"\n | \"de\"\n | \"pt\"\n | \"it\"\n | \"ja\"\n | \"ko\"\n | \"zh\"\n | \"ru\";\n/**\n * Wrapper that gets you the currently selected language. Use this if you are providing translations.\n * You cannot change the locale from the plugin as the setting belongs to the bundled `core` plugin. Instead, users must change it in the settings pane.\n *\n * @returns a tuple of `[currentLocale, initialLoadComplete]`\n */\nexport function useTranslation(): [Locale | undefined, boolean] {\n const [lang, _, loaded] = usePluginSetting<Locale>(\"core.Locale\");\n return [lang, loaded];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,iBAA0B,WAAmB;CAC3D,MAAM,CAAC,OAAO,YAAY,SAAwB,OAAU;CAC5D,MAAM,CAAC,iBAAiB,sBAAsB,SAAS,MAAM;CAC7D,MAAM,MAAM,WAAW,cAAc;CAErC,MAAM,sBAAsB,UAAU,WAAW,IAAI,GACjD,IAAI,WAAW,KAAK,YACpB;AAEJ,iBAAgB;AAEd,MAAI,aAAa,SAAS,WAAW,oBAAoB,CACtD,MAAM,MAAM;AACX,YAAS,EAAS;AAClB,sBAAmB,KAAK;IACxB,CACD,OAAO,QAAQ;AACd,WAAQ,MACN,gCAAgC,oBAAoB,wQACpD;IAAE;IAAK;IAAqB;IAAW,CACxC;AACD,SAAM;IACN;AAEJ,SAAO,IAAI,aAAa,SAAS,iCAAiC,GAAG,MAAM;AACzE,OAAI,MAAM,oBAER;AAEF,YAAS,EAAS;IAClB;GACF;CAEF,MAAM,gBAAgB,QAAuB;AAC3C,MAAI,aAAa,SAAS,aAAa,qBAAqB,IAAI,CAC7D,MAAM,MAAM;AACX,YAAS,EAAE;IACX,CACD,OAAO,QAAQ;AACd,WAAQ,MACN,4BAA4B,oBAAoB,iHAChD;IACE;IACA;IACA;IACA,aAAa,IAAI,WAAW;IAC7B,CACF;AACD,SAAM;IACN;;AAGN,QAAO;EAAC;EAAO;EAAc;EAAgB;;;;;;;;AAoB/C,SAAgB,iBAAgD;CAC9D,MAAM,CAAC,MAAM,GAAG,UAAU,iBAAyB,cAAc;AACjE,QAAO,CAAC,MAAM,OAAO"}
@@ -0,0 +1,25 @@
1
+ import { PluginContext, SettingsContext, usePluginContext, useSettingsContext } from "./context.js";
2
+ import { useBundledResource } from "./hooks/useBundledResource.js";
3
+ import { useJournalEvents } from "./hooks/useJournalEvents.js";
4
+ import { usePluginSetting, useTranslation } from "./hooks/usePluginSetting.js";
5
+ import "./hooks/index.js";
6
+ import { EDPFPluginElementV1Alpha, EDPFPluginSettingsElementV1Alpha } from "@elite-dangerous-plugin-framework/core/v1alpha";
7
+ import { ReactNode } from "react";
8
+
9
+ //#region src/v1alpha/index.d.ts
10
+ declare namespace index_d_exports {
11
+ export { PluginContext, SettingsContext, makePluginV1Alpha, makeSettingsV1Alpha, useBundledResource, useJournalEvents, usePluginContext, usePluginSetting, useSettingsContext, useTranslation };
12
+ }
13
+ /**
14
+ * This creates a Plugin class definition, as expected by EDPF. You should export the response from your index.tsx as the `default` export.
15
+ * This Helper already registers a shutdown listener and correctly unmounts the React root element.
16
+ */
17
+ declare function makePluginV1Alpha(inner: ReactNode): new () => EDPFPluginElementV1Alpha;
18
+ /**
19
+ * This creates a Settings class definition, as expected by EDPF. You should export the response from your index.tsx as the `settings` export.
20
+ * This Helper already registers a shutdown listener and correctly unmounts the React root element.
21
+ */
22
+ declare function makeSettingsV1Alpha(inner: ReactNode): new () => EDPFPluginSettingsElementV1Alpha;
23
+ //#endregion
24
+ export { PluginContext, SettingsContext, index_d_exports, makePluginV1Alpha, makeSettingsV1Alpha, useBundledResource, useJournalEvents, usePluginContext, usePluginSetting, useSettingsContext, useTranslation };
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,63 @@
1
+ import { __exportAll } from "../_virtual/rolldown_runtime.js";
2
+ import { PluginContext, SettingsContext, usePluginContext, useSettingsContext } from "./context.js";
3
+ import { useBundledResource } from "./hooks/useBundledResource.js";
4
+ import { useJournalEvents } from "./hooks/useJournalEvents.js";
5
+ import { usePluginSetting, useTranslation } from "./hooks/usePluginSetting.js";
6
+ import "./hooks/index.js";
7
+ import { EDPFPluginElementV1Alpha, EDPFPluginSettingsElementV1Alpha } from "@elite-dangerous-plugin-framework/core/v1alpha";
8
+ import ReactDOM from "react-dom/client";
9
+ import { jsx } from "react/jsx-runtime";
10
+
11
+ //#region src/v1alpha/index.tsx
12
+ var v1alpha_exports = /* @__PURE__ */ __exportAll({
13
+ PluginContext: () => PluginContext,
14
+ SettingsContext: () => SettingsContext,
15
+ makePluginV1Alpha: () => makePluginV1Alpha,
16
+ makeSettingsV1Alpha: () => makeSettingsV1Alpha,
17
+ useBundledResource: () => useBundledResource,
18
+ useJournalEvents: () => useJournalEvents,
19
+ usePluginContext: () => usePluginContext,
20
+ usePluginSetting: () => usePluginSetting,
21
+ useSettingsContext: () => useSettingsContext,
22
+ useTranslation: () => useTranslation
23
+ });
24
+ /**
25
+ * This creates a Plugin class definition, as expected by EDPF. You should export the response from your index.tsx as the `default` export.
26
+ * This Helper already registers a shutdown listener and correctly unmounts the React root element.
27
+ */
28
+ function makePluginV1Alpha(inner) {
29
+ return class extends EDPFPluginElementV1Alpha {
30
+ initPlugin(ctx) {
31
+ const root = ReactDOM.createRoot(this);
32
+ ctx.registerShutdownListener(async () => {
33
+ root.unmount();
34
+ });
35
+ root.render(/* @__PURE__ */ jsx(PluginContext.Provider, {
36
+ value: ctx,
37
+ children: inner
38
+ }));
39
+ }
40
+ };
41
+ }
42
+ /**
43
+ * This creates a Settings class definition, as expected by EDPF. You should export the response from your index.tsx as the `settings` export.
44
+ * This Helper already registers a shutdown listener and correctly unmounts the React root element.
45
+ */
46
+ function makeSettingsV1Alpha(inner) {
47
+ return class extends EDPFPluginSettingsElementV1Alpha {
48
+ initSettings(ctx) {
49
+ const root = ReactDOM.createRoot(this);
50
+ ctx.registerShutdownListener(async () => {
51
+ root.unmount();
52
+ });
53
+ root.render(/* @__PURE__ */ jsx(SettingsContext.Provider, {
54
+ value: ctx,
55
+ children: inner
56
+ }));
57
+ }
58
+ };
59
+ }
60
+
61
+ //#endregion
62
+ export { PluginContext, SettingsContext, makePluginV1Alpha, makeSettingsV1Alpha, useBundledResource, useJournalEvents, usePluginContext, usePluginSetting, useSettingsContext, useTranslation, v1alpha_exports };
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/v1alpha/index.tsx"],"sourcesContent":["import {\n PluginContextV1Alpha,\n EDPFPluginElementV1Alpha,\n EDPFPluginSettingsElementV1Alpha,\n PluginSettingsContextV1Alpha,\n} from \"@elite-dangerous-plugin-framework/core/v1alpha\";\n\nimport { type ReactNode } from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport { PluginContext, SettingsContext } from \"./context.js\";\n\n/**\n * This creates a Plugin class definition, as expected by EDPF. You should export the response from your index.tsx as the `default` export.\n * This Helper already registers a shutdown listener and correctly unmounts the React root element.\n */\nexport function makePluginV1Alpha(\n inner: ReactNode,\n): new () => EDPFPluginElementV1Alpha {\n return class extends EDPFPluginElementV1Alpha {\n initPlugin(ctx: PluginContextV1Alpha): void {\n const root = ReactDOM.createRoot(this);\n ctx.registerShutdownListener(async () => {\n root.unmount();\n });\n root.render(\n <PluginContext.Provider value={ctx}>{inner}</PluginContext.Provider>,\n );\n }\n };\n}\n\n/**\n * This creates a Settings class definition, as expected by EDPF. You should export the response from your index.tsx as the `settings` export.\n * This Helper already registers a shutdown listener and correctly unmounts the React root element.\n */\nexport function makeSettingsV1Alpha(\n inner: ReactNode,\n): new () => EDPFPluginSettingsElementV1Alpha {\n return class extends EDPFPluginSettingsElementV1Alpha {\n initSettings(ctx: PluginSettingsContextV1Alpha): void {\n const root = ReactDOM.createRoot(this);\n ctx.registerShutdownListener(async () => {\n root.unmount();\n });\n root.render(\n <SettingsContext.Provider value={ctx}>\n {inner}\n </SettingsContext.Provider>,\n );\n }\n };\n}\n\nexport * from \"./context.js\";\nexport * from \"./hooks/index.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,SAAgB,kBACd,OACoC;AACpC,QAAO,cAAc,yBAAyB;EAC5C,WAAW,KAAiC;GAC1C,MAAM,OAAO,SAAS,WAAW,KAAK;AACtC,OAAI,yBAAyB,YAAY;AACvC,SAAK,SAAS;KACd;AACF,QAAK,OACH,oBAAC,cAAc;IAAS,OAAO;cAAM;KAA+B,CACrE;;;;;;;;AASP,SAAgB,oBACd,OAC4C;AAC5C,QAAO,cAAc,iCAAiC;EACpD,aAAa,KAAyC;GACpD,MAAM,OAAO,SAAS,WAAW,KAAK;AACtC,OAAI,yBAAyB,YAAY;AACvC,SAAK,SAAS;KACd;AACF,QAAK,OACH,oBAAC,gBAAgB;IAAS,OAAO;cAC9B;KACwB,CAC5B"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "devDependencies": {
3
+ "@elite-dangerous-plugin-framework/journal": "^0.20260201.2",
4
+ "@types/react": "^19.2.10",
5
+ "@types/react-dom": "^19.2.3",
6
+ "react": "^19.2.4",
7
+ "react-dom": "^19.2.4"
8
+ },
9
+ "private": false,
10
+ "name": "@elite-dangerous-plugin-framework/react",
11
+ "description": "Abstractions and Helpers that make writing React-based EDPF Plugins a breeze",
12
+ "workspaces": [
13
+ "packages/*"
14
+ ],
15
+ "type": "module",
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsdown",
22
+ "pretty": "prettier src -w"
23
+ },
24
+ "types": "dist/index.d.ts",
25
+ "exports": {
26
+ ".": "./dist/index.js",
27
+ "./v1alpha": "./dist/v1alpha/index.js",
28
+ "./package.json": "./package.json"
29
+ },
30
+ "peerDependencies": {
31
+ "@elite-dangerous-plugin-framework/journal": ">=0.20260201.2",
32
+ "react": ">=18",
33
+ "react-dom": ">=18"
34
+ },
35
+ "publishConfig": {
36
+ "provenance": false,
37
+ "access": "public"
38
+ },
39
+ "version": "0.0.1-pre1",
40
+ "dependencies": {
41
+ "@elite-dangerous-plugin-framework/core": "^0.0.1-pre1"
42
+ },
43
+ "gitHead": "c7919bb37e1b55eadd413bd0e8ceda64adabdf23"
44
+ }