@rozenite/controls-plugin 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +16 -0
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/LICENSE +20 -0
- package/README.md +118 -0
- package/dist/assets/panel-B5zz0XK3.css +1 -0
- package/dist/assets/panel-OL0XQF_c.js +17 -0
- package/dist/panel.html +31 -0
- package/dist/react-native.cjs +1 -0
- package/dist/react-native.d.ts +2 -0
- package/dist/react-native.js +8 -0
- package/dist/rozenite.config.d.ts +7 -0
- package/dist/rozenite.json +1 -0
- package/dist/src/__tests__/serialization.test.d.ts +1 -0
- package/dist/src/react-native/useRozeniteControlsPlugin.d.ts +3 -0
- package/dist/src/shared/messaging.d.ts +35 -0
- package/dist/src/shared/serialization.d.ts +22 -0
- package/dist/src/shared/types.d.ts +67 -0
- package/dist/src/ui/panel.d.ts +1 -0
- package/dist/useRozeniteControlsPlugin.cjs +1 -0
- package/dist/useRozeniteControlsPlugin.js +226 -0
- package/package.json +38 -0
- package/postcss.config.js +6 -0
- package/react-native.d.ts +19 -0
- package/react-native.ts +25 -0
- package/rozenite.config.ts +8 -0
- package/src/__tests__/serialization.test.ts +210 -0
- package/src/react-native/useRozeniteControlsPlugin.ts +215 -0
- package/src/shared/messaging.ts +45 -0
- package/src/shared/serialization.ts +153 -0
- package/src/shared/types.ts +103 -0
- package/src/ui/globals.css +86 -0
- package/src/ui/panel.tsx +501 -0
- package/tailwind.config.ts +53 -0
- package/tsconfig.json +36 -0
- package/vite.config.ts +23 -0
package/dist/panel.html
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>panel Panel</title>
|
|
7
|
+
<style>
|
|
8
|
+
html,
|
|
9
|
+
body {
|
|
10
|
+
height: 100%;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body {
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#root {
|
|
18
|
+
display: flex;
|
|
19
|
+
height: 100%;
|
|
20
|
+
}
|
|
21
|
+
</style>
|
|
22
|
+
<script>
|
|
23
|
+
var __ROZENITE_PANEL__ = true;
|
|
24
|
+
</script>
|
|
25
|
+
<script type="module" crossorigin src="./assets/panel-OL0XQF_c.js"></script>
|
|
26
|
+
<link rel="stylesheet" crossorigin href="./assets/panel-B5zz0XK3.css">
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<div id="root"></div>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=e=>e;exports.useRozeniteControlsPlugin=void 0;const n=process.env.NODE_ENV!=="production",t=typeof window>"u";n&&!t?exports.useRozeniteControlsPlugin=require("./useRozeniteControlsPlugin.cjs").useRozeniteControlsPlugin:exports.useRozeniteControlsPlugin=()=>null;exports.createSection=o;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { createSection, type ControlsButtonItem, type ControlsInputItem, type ControlsItem, type ControlsSelectItem, type ControlsSelectOption, type ControlsSection, type ControlsTextItem, type ControlsToggleItem, type ControlsValidationResult, type RozeniteControlsPluginOptions, } from './src/shared/types';
|
|
2
|
+
export declare let useRozeniteControlsPlugin: typeof import('./src/react-native/useRozeniteControlsPlugin').useRozeniteControlsPlugin;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const i = (n) => n;
|
|
2
|
+
let e;
|
|
3
|
+
const o = process.env.NODE_ENV !== "production", t = typeof window > "u";
|
|
4
|
+
o && !t ? e = require("./useRozeniteControlsPlugin.js").useRozeniteControlsPlugin : e = () => null;
|
|
5
|
+
export {
|
|
6
|
+
i as createSection,
|
|
7
|
+
e as useRozeniteControlsPlugin
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"@rozenite/controls-plugin","version":"0.0.0","description":"Device-owned controls for Rozenite.","panels":[{"name":"Controls","source":"/panel.html"}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ControlsEventMap } from '../shared/messaging';
|
|
2
|
+
import { RozeniteControlsPluginOptions } from '../shared/types';
|
|
3
|
+
export declare const useRozeniteControlsPlugin: ({ sections, }: RozeniteControlsPluginOptions) => import('../../../plugin-bridge/src/index.ts').RozeniteDevToolsClient<ControlsEventMap> | null;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ControlsSectionSnapshot } from './types';
|
|
2
|
+
export type ControlsSnapshotEvent = {
|
|
3
|
+
type: 'snapshot';
|
|
4
|
+
sections: ControlsSectionSnapshot[];
|
|
5
|
+
};
|
|
6
|
+
export type ControlsGetSnapshotEvent = {
|
|
7
|
+
type: 'get-snapshot';
|
|
8
|
+
};
|
|
9
|
+
export type ControlsUpdateRequestEvent = {
|
|
10
|
+
type: 'update-request';
|
|
11
|
+
requestId: string;
|
|
12
|
+
sectionId: string;
|
|
13
|
+
itemId: string;
|
|
14
|
+
value: boolean | string;
|
|
15
|
+
};
|
|
16
|
+
export type ControlsUpdateResultEvent = {
|
|
17
|
+
type: 'update-result';
|
|
18
|
+
requestId: string;
|
|
19
|
+
sectionId: string;
|
|
20
|
+
itemId: string;
|
|
21
|
+
status: 'ok' | 'error';
|
|
22
|
+
message?: string;
|
|
23
|
+
};
|
|
24
|
+
export type ControlsInvokeActionEvent = {
|
|
25
|
+
type: 'invoke-action';
|
|
26
|
+
sectionId: string;
|
|
27
|
+
itemId: string;
|
|
28
|
+
action: 'press';
|
|
29
|
+
};
|
|
30
|
+
export type ControlsEvent = ControlsSnapshotEvent | ControlsGetSnapshotEvent | ControlsUpdateRequestEvent | ControlsUpdateResultEvent | ControlsInvokeActionEvent;
|
|
31
|
+
export type ControlsEventMap = {
|
|
32
|
+
[K in ControlsEvent['type']]: Extract<ControlsEvent, {
|
|
33
|
+
type: K;
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ControlsButtonItem, ControlsInputItem, ControlsMutableItemBase, ControlsSelectItem, ControlsSection, ControlsSectionSnapshot, ControlsToggleItem, ControlsValidationResult } from './types';
|
|
2
|
+
export type ActionRegistryEntry = {
|
|
3
|
+
type: 'toggle';
|
|
4
|
+
validate?: ControlsToggleItem['validate'];
|
|
5
|
+
onUpdate: ControlsToggleItem['onUpdate'];
|
|
6
|
+
} | {
|
|
7
|
+
type: 'button';
|
|
8
|
+
onPress: ControlsButtonItem['onPress'];
|
|
9
|
+
} | {
|
|
10
|
+
type: 'select';
|
|
11
|
+
validate?: ControlsSelectItem['validate'];
|
|
12
|
+
onUpdate: ControlsSelectItem['onUpdate'];
|
|
13
|
+
} | {
|
|
14
|
+
type: 'input';
|
|
15
|
+
validate?: ControlsInputItem['validate'];
|
|
16
|
+
onUpdate: ControlsInputItem['onUpdate'];
|
|
17
|
+
};
|
|
18
|
+
declare const validateValue: <TValue>(validate: ControlsMutableItemBase<TValue>["validate"], value: TValue) => ControlsValidationResult;
|
|
19
|
+
export declare const serializeSections: (sections: ControlsSection[]) => ControlsSectionSnapshot[];
|
|
20
|
+
export declare const buildActionRegistry: (sections: ControlsSection[]) => Map<string, ActionRegistryEntry>;
|
|
21
|
+
export declare const getActionRegistryKey: (sectionId: string, itemId: string) => string;
|
|
22
|
+
export { validateValue };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type ControlsTextItem = {
|
|
2
|
+
id: string;
|
|
3
|
+
type: 'text';
|
|
4
|
+
title: string;
|
|
5
|
+
value: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
};
|
|
8
|
+
export type ControlsValidationResult = {
|
|
9
|
+
valid: true;
|
|
10
|
+
} | {
|
|
11
|
+
valid: false;
|
|
12
|
+
message: string;
|
|
13
|
+
};
|
|
14
|
+
export type ControlsMutableItemBase<TValue> = {
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
value: TValue;
|
|
18
|
+
description?: string;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
validate?: (nextValue: TValue) => ControlsValidationResult;
|
|
21
|
+
onUpdate: (nextValue: TValue) => void | Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
export type ControlsToggleItem = ControlsMutableItemBase<boolean> & {
|
|
24
|
+
type: 'toggle';
|
|
25
|
+
};
|
|
26
|
+
export type ControlsButtonItem = {
|
|
27
|
+
id: string;
|
|
28
|
+
type: 'button';
|
|
29
|
+
title: string;
|
|
30
|
+
actionLabel?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
onPress: () => void | Promise<void>;
|
|
34
|
+
};
|
|
35
|
+
export type ControlsSelectOption = {
|
|
36
|
+
label: string;
|
|
37
|
+
value: string;
|
|
38
|
+
};
|
|
39
|
+
export type ControlsSelectItem = ControlsMutableItemBase<string> & {
|
|
40
|
+
type: 'select';
|
|
41
|
+
options: ControlsSelectOption[];
|
|
42
|
+
};
|
|
43
|
+
export type ControlsInputItem = ControlsMutableItemBase<string> & {
|
|
44
|
+
type: 'input';
|
|
45
|
+
placeholder?: string;
|
|
46
|
+
applyLabel?: string;
|
|
47
|
+
};
|
|
48
|
+
export type ControlsItem = ControlsTextItem | ControlsToggleItem | ControlsButtonItem | ControlsSelectItem | ControlsInputItem;
|
|
49
|
+
export type ControlsSection = {
|
|
50
|
+
id: string;
|
|
51
|
+
title: string;
|
|
52
|
+
description?: string;
|
|
53
|
+
items: ControlsItem[];
|
|
54
|
+
};
|
|
55
|
+
export type ControlsTextItemSnapshot = Omit<ControlsTextItem, never>;
|
|
56
|
+
export type ControlsToggleItemSnapshot = Omit<ControlsToggleItem, 'validate' | 'onUpdate'>;
|
|
57
|
+
export type ControlsButtonItemSnapshot = Omit<ControlsButtonItem, 'onPress'>;
|
|
58
|
+
export type ControlsSelectItemSnapshot = Omit<ControlsSelectItem, 'validate' | 'onUpdate'>;
|
|
59
|
+
export type ControlsInputItemSnapshot = Omit<ControlsInputItem, 'validate' | 'onUpdate'>;
|
|
60
|
+
export type ControlsItemSnapshot = ControlsTextItemSnapshot | ControlsToggleItemSnapshot | ControlsButtonItemSnapshot | ControlsSelectItemSnapshot | ControlsInputItemSnapshot;
|
|
61
|
+
export type ControlsSectionSnapshot = Omit<ControlsSection, 'items'> & {
|
|
62
|
+
items: ControlsItemSnapshot[];
|
|
63
|
+
};
|
|
64
|
+
export type RozeniteControlsPluginOptions = {
|
|
65
|
+
sections: ControlsSection[];
|
|
66
|
+
};
|
|
67
|
+
export declare const createSection: <TSection extends ControlsSection>(section: TSection) => TSection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function ControlsPanel(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("@rozenite/plugin-bridge"),i=require("react"),g=(e,t)=>e?e(t):{valid:!0},R=e=>e.type==="text"?e:e.type==="toggle"?{id:e.id,type:e.type,title:e.title,value:e.value,description:e.description,disabled:e.disabled}:e.type==="button"?{id:e.id,type:e.type,title:e.title,actionLabel:e.actionLabel,description:e.description,disabled:e.disabled}:e.type==="select"?{id:e.id,type:e.type,title:e.title,value:e.value,options:e.options,description:e.description,disabled:e.disabled}:{id:e.id,type:e.type,title:e.title,value:e.value,placeholder:e.placeholder,applyLabel:e.applyLabel,description:e.description,disabled:e.disabled},U=e=>e.map(t=>({id:t.id,title:t.title,description:t.description,items:t.items.map(R)})),P=e=>{const t=new Map;return e.forEach(u=>{u.items.forEach(n=>{const l=`${u.id}:${n.id}`;n.type==="toggle"&&t.set(l,{type:"toggle",validate:n.validate,onUpdate:n.onUpdate}),n.type==="button"&&t.set(l,{type:"button",onPress:n.onPress}),n.type==="select"&&t.set(l,{type:"select",validate:n.validate,onUpdate:n.onUpdate}),n.type==="input"&&t.set(l,{type:"input",validate:n.validate,onUpdate:n.onUpdate})})}),t},f=(e,t)=>`${e}:${t}`,z=({sections:e})=>{const t=$.useRozeniteDevToolsClient({pluginId:"@rozenite/controls-plugin"}),u=i.useMemo(()=>U(e),[e]),n=i.useMemo(()=>P(e),[e]),l=i.useRef(n);return i.useEffect(()=>{l.current=n},[n]),i.useEffect(()=>{t&&t.send("snapshot",{type:"snapshot",sections:u})},[t,u]),i.useEffect(()=>{if(!t)return;const v=async({requestId:s,sectionId:r,itemId:o,value:p})=>{const d=f(r,o),a=l.current.get(d);if(!a||a.type==="button"){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:"Update target not found."});return}try{if(a.type==="toggle"){if(typeof p!="boolean"){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:"Invalid toggle value."});return}const y=g(a.validate,p);if(!y.valid){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:y.message});return}await a.onUpdate(p),t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"ok"});return}if(typeof p!="string"){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:`Invalid ${a.type} value.`});return}const c=g(a.validate,p);if(!c.valid){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:c.message});return}await a.onUpdate(p),t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"ok"})}catch(c){console.warn(`[Rozenite] Controls Plugin: Update failed for ${r}/${o}.`,c),t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:"Update failed on the device."})}},b=async({sectionId:s,itemId:r,action:o})=>{if(o!=="press"){console.warn(`[Rozenite] Controls Plugin: Unsupported action "${o}" for ${s}/${r}.`);return}const p=f(s,r),d=l.current.get(p);if(!d){console.warn(`[Rozenite] Controls Plugin: Action target not found for ${s}/${r}.`);return}try{if(d.type!=="button"){console.warn(`[Rozenite] Controls Plugin: Invalid press action payload for ${s}/${r}.`);return}await d.onPress()}catch(a){console.warn(`[Rozenite] Controls Plugin: Action failed for ${s}/${r}.`,a)}},h=[t.onMessage("get-snapshot",()=>{t.send("snapshot",{type:"snapshot",sections:u})}),t.onMessage("update-request",s=>{v(s)}),t.onMessage("invoke-action",s=>{b(s)})];return()=>{h.forEach(s=>s.remove())}},[t,u]),t};exports.useRozeniteControlsPlugin=z;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { useRozeniteDevToolsClient as R } from "@rozenite/plugin-bridge";
|
|
2
|
+
import { useMemo as f, useRef as U, useEffect as y } from "react";
|
|
3
|
+
const g = (e, t) => e ? e(t) : { valid: !0 }, w = (e) => e.type === "text" ? e : e.type === "toggle" ? {
|
|
4
|
+
id: e.id,
|
|
5
|
+
type: e.type,
|
|
6
|
+
title: e.title,
|
|
7
|
+
value: e.value,
|
|
8
|
+
description: e.description,
|
|
9
|
+
disabled: e.disabled
|
|
10
|
+
} : e.type === "button" ? {
|
|
11
|
+
id: e.id,
|
|
12
|
+
type: e.type,
|
|
13
|
+
title: e.title,
|
|
14
|
+
actionLabel: e.actionLabel,
|
|
15
|
+
description: e.description,
|
|
16
|
+
disabled: e.disabled
|
|
17
|
+
} : e.type === "select" ? {
|
|
18
|
+
id: e.id,
|
|
19
|
+
type: e.type,
|
|
20
|
+
title: e.title,
|
|
21
|
+
value: e.value,
|
|
22
|
+
options: e.options,
|
|
23
|
+
description: e.description,
|
|
24
|
+
disabled: e.disabled
|
|
25
|
+
} : {
|
|
26
|
+
id: e.id,
|
|
27
|
+
type: e.type,
|
|
28
|
+
title: e.title,
|
|
29
|
+
value: e.value,
|
|
30
|
+
placeholder: e.placeholder,
|
|
31
|
+
applyLabel: e.applyLabel,
|
|
32
|
+
description: e.description,
|
|
33
|
+
disabled: e.disabled
|
|
34
|
+
}, z = (e) => e.map((t) => ({
|
|
35
|
+
id: t.id,
|
|
36
|
+
title: t.title,
|
|
37
|
+
description: t.description,
|
|
38
|
+
items: t.items.map(w)
|
|
39
|
+
})), P = (e) => {
|
|
40
|
+
const t = /* @__PURE__ */ new Map();
|
|
41
|
+
return e.forEach((u) => {
|
|
42
|
+
u.items.forEach((n) => {
|
|
43
|
+
const p = `${u.id}:${n.id}`;
|
|
44
|
+
n.type === "toggle" && t.set(p, {
|
|
45
|
+
type: "toggle",
|
|
46
|
+
validate: n.validate,
|
|
47
|
+
onUpdate: n.onUpdate
|
|
48
|
+
}), n.type === "button" && t.set(p, {
|
|
49
|
+
type: "button",
|
|
50
|
+
onPress: n.onPress
|
|
51
|
+
}), n.type === "select" && t.set(p, {
|
|
52
|
+
type: "select",
|
|
53
|
+
validate: n.validate,
|
|
54
|
+
onUpdate: n.onUpdate
|
|
55
|
+
}), n.type === "input" && t.set(p, {
|
|
56
|
+
type: "input",
|
|
57
|
+
validate: n.validate,
|
|
58
|
+
onUpdate: n.onUpdate
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}), t;
|
|
62
|
+
}, v = (e, t) => `${e}:${t}`, A = ({
|
|
63
|
+
sections: e
|
|
64
|
+
}) => {
|
|
65
|
+
const t = R({
|
|
66
|
+
pluginId: "@rozenite/controls-plugin"
|
|
67
|
+
}), u = f(() => z(e), [e]), n = f(() => P(e), [e]), p = U(n);
|
|
68
|
+
return y(() => {
|
|
69
|
+
p.current = n;
|
|
70
|
+
}, [n]), y(() => {
|
|
71
|
+
t && t.send("snapshot", {
|
|
72
|
+
type: "snapshot",
|
|
73
|
+
sections: u
|
|
74
|
+
});
|
|
75
|
+
}, [t, u]), y(() => {
|
|
76
|
+
if (!t)
|
|
77
|
+
return;
|
|
78
|
+
const b = async ({
|
|
79
|
+
requestId: s,
|
|
80
|
+
sectionId: r,
|
|
81
|
+
itemId: o,
|
|
82
|
+
value: l
|
|
83
|
+
}) => {
|
|
84
|
+
const d = v(r, o), a = p.current.get(d);
|
|
85
|
+
if (!a || a.type === "button") {
|
|
86
|
+
t.send("update-result", {
|
|
87
|
+
type: "update-result",
|
|
88
|
+
requestId: s,
|
|
89
|
+
sectionId: r,
|
|
90
|
+
itemId: o,
|
|
91
|
+
status: "error",
|
|
92
|
+
message: "Update target not found."
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
if (a.type === "toggle") {
|
|
98
|
+
if (typeof l != "boolean") {
|
|
99
|
+
t.send("update-result", {
|
|
100
|
+
type: "update-result",
|
|
101
|
+
requestId: s,
|
|
102
|
+
sectionId: r,
|
|
103
|
+
itemId: o,
|
|
104
|
+
status: "error",
|
|
105
|
+
message: "Invalid toggle value."
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const c = g(a.validate, l);
|
|
110
|
+
if (!c.valid) {
|
|
111
|
+
t.send("update-result", {
|
|
112
|
+
type: "update-result",
|
|
113
|
+
requestId: s,
|
|
114
|
+
sectionId: r,
|
|
115
|
+
itemId: o,
|
|
116
|
+
status: "error",
|
|
117
|
+
message: c.message
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
await a.onUpdate(l), t.send("update-result", {
|
|
122
|
+
type: "update-result",
|
|
123
|
+
requestId: s,
|
|
124
|
+
sectionId: r,
|
|
125
|
+
itemId: o,
|
|
126
|
+
status: "ok"
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (typeof l != "string") {
|
|
131
|
+
t.send("update-result", {
|
|
132
|
+
type: "update-result",
|
|
133
|
+
requestId: s,
|
|
134
|
+
sectionId: r,
|
|
135
|
+
itemId: o,
|
|
136
|
+
status: "error",
|
|
137
|
+
message: `Invalid ${a.type} value.`
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const i = g(a.validate, l);
|
|
142
|
+
if (!i.valid) {
|
|
143
|
+
t.send("update-result", {
|
|
144
|
+
type: "update-result",
|
|
145
|
+
requestId: s,
|
|
146
|
+
sectionId: r,
|
|
147
|
+
itemId: o,
|
|
148
|
+
status: "error",
|
|
149
|
+
message: i.message
|
|
150
|
+
});
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
await a.onUpdate(l), t.send("update-result", {
|
|
154
|
+
type: "update-result",
|
|
155
|
+
requestId: s,
|
|
156
|
+
sectionId: r,
|
|
157
|
+
itemId: o,
|
|
158
|
+
status: "ok"
|
|
159
|
+
});
|
|
160
|
+
} catch (i) {
|
|
161
|
+
console.warn(
|
|
162
|
+
`[Rozenite] Controls Plugin: Update failed for ${r}/${o}.`,
|
|
163
|
+
i
|
|
164
|
+
), t.send("update-result", {
|
|
165
|
+
type: "update-result",
|
|
166
|
+
requestId: s,
|
|
167
|
+
sectionId: r,
|
|
168
|
+
itemId: o,
|
|
169
|
+
status: "error",
|
|
170
|
+
message: "Update failed on the device."
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}, h = async ({
|
|
174
|
+
sectionId: s,
|
|
175
|
+
itemId: r,
|
|
176
|
+
action: o
|
|
177
|
+
}) => {
|
|
178
|
+
if (o !== "press") {
|
|
179
|
+
console.warn(
|
|
180
|
+
`[Rozenite] Controls Plugin: Unsupported action "${o}" for ${s}/${r}.`
|
|
181
|
+
);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const l = v(s, r), d = p.current.get(l);
|
|
185
|
+
if (!d) {
|
|
186
|
+
console.warn(
|
|
187
|
+
`[Rozenite] Controls Plugin: Action target not found for ${s}/${r}.`
|
|
188
|
+
);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
if (d.type !== "button") {
|
|
193
|
+
console.warn(
|
|
194
|
+
`[Rozenite] Controls Plugin: Invalid press action payload for ${s}/${r}.`
|
|
195
|
+
);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
await d.onPress();
|
|
199
|
+
} catch (a) {
|
|
200
|
+
console.warn(
|
|
201
|
+
`[Rozenite] Controls Plugin: Action failed for ${s}/${r}.`,
|
|
202
|
+
a
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}, $ = [
|
|
206
|
+
t.onMessage("get-snapshot", () => {
|
|
207
|
+
t.send("snapshot", {
|
|
208
|
+
type: "snapshot",
|
|
209
|
+
sections: u
|
|
210
|
+
});
|
|
211
|
+
}),
|
|
212
|
+
t.onMessage("update-request", (s) => {
|
|
213
|
+
b(s);
|
|
214
|
+
}),
|
|
215
|
+
t.onMessage("invoke-action", (s) => {
|
|
216
|
+
h(s);
|
|
217
|
+
})
|
|
218
|
+
];
|
|
219
|
+
return () => {
|
|
220
|
+
$.forEach((s) => s.remove());
|
|
221
|
+
};
|
|
222
|
+
}, [t, u]), t;
|
|
223
|
+
};
|
|
224
|
+
export {
|
|
225
|
+
A as useRozeniteControlsPlugin
|
|
226
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rozenite/controls-plugin",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "A Rozenite plugin for exposing app-defined controls directly in React Native DevTools.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/react-native.cjs",
|
|
7
|
+
"module": "./dist/react-native.js",
|
|
8
|
+
"types": "./dist/react-native.d.ts",
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@rozenite/plugin-bridge": "1.4.0"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@types/react": "~19.2.2",
|
|
14
|
+
"autoprefixer": "^10.4.21",
|
|
15
|
+
"postcss": "^8.5.6",
|
|
16
|
+
"react": "19.2.0",
|
|
17
|
+
"react-dom": "19.2.0",
|
|
18
|
+
"react-native": "0.83.1",
|
|
19
|
+
"react-native-web": "^0.21.2",
|
|
20
|
+
"tailwindcss": "^3.4.17",
|
|
21
|
+
"tailwindcss-animate": "^1.0.7",
|
|
22
|
+
"typescript": "~5.9.3",
|
|
23
|
+
"vite": "^7.3.1",
|
|
24
|
+
"@rozenite/vite-plugin": "1.4.0",
|
|
25
|
+
"rozenite": "1.4.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": "*",
|
|
29
|
+
"react-native": "*"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "rozenite build",
|
|
34
|
+
"dev": "rozenite dev",
|
|
35
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
36
|
+
"lint": "eslint ."
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createSection,
|
|
3
|
+
type ControlsButtonItem,
|
|
4
|
+
type ControlsInputItem,
|
|
5
|
+
type ControlsItem,
|
|
6
|
+
type ControlsSelectItem,
|
|
7
|
+
type ControlsSelectOption,
|
|
8
|
+
type ControlsSection,
|
|
9
|
+
type ControlsTextItem,
|
|
10
|
+
type ControlsToggleItem,
|
|
11
|
+
type ControlsValidationResult,
|
|
12
|
+
type RozeniteControlsPluginOptions,
|
|
13
|
+
} from './src/shared/types';
|
|
14
|
+
|
|
15
|
+
export declare const useRozeniteControlsPlugin: (
|
|
16
|
+
options: import('./src/shared/types').RozeniteControlsPluginOptions
|
|
17
|
+
) => import('@rozenite/plugin-bridge').RozeniteDevToolsClient<
|
|
18
|
+
import('./src/shared/messaging').ControlsEventMap
|
|
19
|
+
> | null;
|
package/react-native.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createSection,
|
|
3
|
+
type ControlsButtonItem,
|
|
4
|
+
type ControlsInputItem,
|
|
5
|
+
type ControlsItem,
|
|
6
|
+
type ControlsSelectItem,
|
|
7
|
+
type ControlsSelectOption,
|
|
8
|
+
type ControlsSection,
|
|
9
|
+
type ControlsTextItem,
|
|
10
|
+
type ControlsToggleItem,
|
|
11
|
+
type ControlsValidationResult,
|
|
12
|
+
type RozeniteControlsPluginOptions,
|
|
13
|
+
} from './src/shared/types';
|
|
14
|
+
|
|
15
|
+
export let useRozeniteControlsPlugin: typeof import('./src/react-native/useRozeniteControlsPlugin').useRozeniteControlsPlugin;
|
|
16
|
+
|
|
17
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
18
|
+
const isServer = typeof window === 'undefined';
|
|
19
|
+
|
|
20
|
+
if (isDev && !isServer) {
|
|
21
|
+
useRozeniteControlsPlugin =
|
|
22
|
+
require('./src/react-native/useRozeniteControlsPlugin').useRozeniteControlsPlugin;
|
|
23
|
+
} else {
|
|
24
|
+
useRozeniteControlsPlugin = () => null;
|
|
25
|
+
}
|