@joycostudio/studio 0.1.2 → 0.1.3
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 +19 -2
- package/dist/{chunk-X4YLM5HA.js → chunk-OIMLF2CL.js} +21 -1
- package/dist/chunk-OIMLF2CL.js.map +1 -0
- package/dist/cli.js +9 -4
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +5 -2
- package/dist/client.js +4 -2
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -12
- package/dist/index.js.map +1 -1
- package/dist/{protocol-BrHDtNkL.d.ts → protocol-Dgj_7ibg.d.ts} +29 -13
- package/dist/react.d.ts +26 -10
- package/dist/react.js +77 -46
- package/dist/react.js.map +1 -1
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +10 -5
- package/dist/runtime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/chunk-X4YLM5HA.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
PlugZap,
|
|
12
12
|
Unplug
|
|
13
13
|
} from "lucide-react";
|
|
14
|
-
import { useEffect as
|
|
14
|
+
import { useEffect as useEffect5, useRef as useRef3, useState as useState8 } from "react";
|
|
15
15
|
|
|
16
16
|
// package.json
|
|
17
|
-
var version = "0.1.
|
|
17
|
+
var version = "0.1.3";
|
|
18
18
|
|
|
19
19
|
// src/client/studio.ts
|
|
20
20
|
import {
|
|
@@ -507,9 +507,7 @@ function usePinnedTools(studio) {
|
|
|
507
507
|
};
|
|
508
508
|
}, []);
|
|
509
509
|
const pinned = new Set(pins);
|
|
510
|
-
const tools = [...studio.
|
|
511
|
-
(a, b) => Number(pinned.has(b.definition.id)) - Number(pinned.has(a.definition.id))
|
|
512
|
-
);
|
|
510
|
+
const tools = [...studio.definitions].sort((a, b) => Number(pinned.has(b.id)) - Number(pinned.has(a.id)));
|
|
513
511
|
const togglePin = (id) => {
|
|
514
512
|
const next = pinned.has(id) ? pins.filter((pin) => pin !== id) : [...pins, id];
|
|
515
513
|
try {
|
|
@@ -612,6 +610,25 @@ var PreviewCanvas = forwardRef3(function PreviewCanvas2({ title = "Preview", exp
|
|
|
612
610
|
);
|
|
613
611
|
});
|
|
614
612
|
|
|
613
|
+
// src/react/session-flag.ts
|
|
614
|
+
import { useEffect as useEffect3, useState as useState5 } from "react";
|
|
615
|
+
function useSessionFlag(key) {
|
|
616
|
+
const [value, setValue] = useState5(() => {
|
|
617
|
+
try {
|
|
618
|
+
return sessionStorage.getItem(key) === "true";
|
|
619
|
+
} catch {
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
useEffect3(() => {
|
|
624
|
+
try {
|
|
625
|
+
sessionStorage.setItem(key, String(value));
|
|
626
|
+
} catch {
|
|
627
|
+
}
|
|
628
|
+
}, [key, value]);
|
|
629
|
+
return [value, setValue];
|
|
630
|
+
}
|
|
631
|
+
|
|
615
632
|
// src/react/ui/sidebar.tsx
|
|
616
633
|
import * as React2 from "react";
|
|
617
634
|
import { cva as cva2 } from "class-variance-authority";
|
|
@@ -1072,13 +1089,20 @@ function forwardShortcuts(frame) {
|
|
|
1072
1089
|
function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
1073
1090
|
useStudio(studio);
|
|
1074
1091
|
const { tools, pinned, togglePin } = usePinnedTools(studio);
|
|
1075
|
-
const [mounted, setMounted] =
|
|
1076
|
-
const [
|
|
1077
|
-
const [
|
|
1092
|
+
const [mounted, setMounted] = useState8(false);
|
|
1093
|
+
const [sidebarHidden, setSidebarHidden] = useSessionFlag("joyco-studio:sidebar-hidden");
|
|
1094
|
+
const [inspectorHidden, setInspectorHidden] = useSessionFlag("joyco-studio:inspector-hidden");
|
|
1095
|
+
const [canvasExpanded, setCanvasExpanded] = useSessionFlag("joyco-studio:canvas-expanded");
|
|
1096
|
+
const [selected, setSelected] = useState8(studio.definitions[0]?.id);
|
|
1078
1097
|
const preview = useRef3(null);
|
|
1098
|
+
const definition = studio.definitions.find((tool) => tool.id === selected);
|
|
1079
1099
|
const handle = studio.tools.find((tool) => tool.definition.id === selected);
|
|
1080
|
-
const Preview = previewComponent ?? (
|
|
1081
|
-
|
|
1100
|
+
const Preview = previewComponent ?? (definition?.previewLayout === "custom" ? "iframe" : PreviewCanvas);
|
|
1101
|
+
const hidden = { left: sidebarHidden, right: inspectorHidden || !handle };
|
|
1102
|
+
const show = { left: () => setSidebarHidden(false), right: () => setInspectorHidden(false) };
|
|
1103
|
+
const layout = useRef3(hidden);
|
|
1104
|
+
layout.current = hidden;
|
|
1105
|
+
useEffect5(() => {
|
|
1082
1106
|
const onKey = (event) => {
|
|
1083
1107
|
if (event.defaultPrevented || event.isComposing || event.altKey || !(event.metaKey || event.ctrlKey)) return;
|
|
1084
1108
|
if (event.key.toLowerCase() !== "b") return;
|
|
@@ -1089,7 +1113,9 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1089
1113
|
active.blur();
|
|
1090
1114
|
preview.current?.focus();
|
|
1091
1115
|
}
|
|
1092
|
-
|
|
1116
|
+
const hide = !layout.current.left || !layout.current.right;
|
|
1117
|
+
setSidebarHidden(hide);
|
|
1118
|
+
setInspectorHidden(hide);
|
|
1093
1119
|
};
|
|
1094
1120
|
window.addEventListener("keydown", onKey);
|
|
1095
1121
|
return () => window.removeEventListener("keydown", onKey);
|
|
@@ -1099,10 +1125,10 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1099
1125
|
handle.compare(showSaved);
|
|
1100
1126
|
postCompare(preview.current?.contentWindow, handle.definition.id, showSaved);
|
|
1101
1127
|
};
|
|
1102
|
-
|
|
1128
|
+
useEffect5(() => () => handle?.compare(false), [handle]);
|
|
1103
1129
|
const current = useRef3({ handle, compare });
|
|
1104
1130
|
current.current = { handle, compare };
|
|
1105
|
-
|
|
1131
|
+
useEffect5(() => {
|
|
1106
1132
|
const onKey = (event) => {
|
|
1107
1133
|
if (event.key !== COMPARE_KEY || editable(event.target) || event.repeat) return;
|
|
1108
1134
|
event.preventDefault();
|
|
@@ -1120,7 +1146,7 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1120
1146
|
removeEventListener("blur", release);
|
|
1121
1147
|
};
|
|
1122
1148
|
}, []);
|
|
1123
|
-
|
|
1149
|
+
useEffect5(() => {
|
|
1124
1150
|
const onKey = (event) => {
|
|
1125
1151
|
const action = event.defaultPrevented ? null : historyAction(event);
|
|
1126
1152
|
if (!action) return;
|
|
@@ -1130,10 +1156,10 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1130
1156
|
addEventListener("keydown", onKey);
|
|
1131
1157
|
return () => removeEventListener("keydown", onKey);
|
|
1132
1158
|
}, []);
|
|
1133
|
-
|
|
1159
|
+
useEffect5(() => {
|
|
1134
1160
|
const fromHash = () => {
|
|
1135
1161
|
const id = decodeURIComponent(location.hash.slice(1));
|
|
1136
|
-
if (studio.
|
|
1162
|
+
if (studio.definitions.some((tool) => tool.id === id)) setSelected(id);
|
|
1137
1163
|
};
|
|
1138
1164
|
setMounted(true);
|
|
1139
1165
|
fromHash();
|
|
@@ -1146,22 +1172,25 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1146
1172
|
SidebarProvider,
|
|
1147
1173
|
{
|
|
1148
1174
|
defaultOpen: sidebarOpen,
|
|
1149
|
-
"data-preview-layout": previewComponent ? "canvas" :
|
|
1175
|
+
"data-preview-layout": previewComponent ? "canvas" : definition?.previewLayout ?? "canvas",
|
|
1176
|
+
"data-sidebar-panel": hidden.left ? "hidden" : "shown",
|
|
1150
1177
|
className: "studio-workspace relative h-svh min-h-0 overflow-hidden text-xs",
|
|
1151
1178
|
children: [
|
|
1152
|
-
|
|
1179
|
+
definition?.preview ? /* @__PURE__ */ jsx13(
|
|
1153
1180
|
Preview,
|
|
1154
1181
|
{
|
|
1155
1182
|
"data-slot": "studio-preview",
|
|
1156
1183
|
ref: preview,
|
|
1157
|
-
src:
|
|
1158
|
-
title:
|
|
1159
|
-
onLoad: (event) => forwardShortcuts(event.currentTarget)
|
|
1184
|
+
src: definition.preview,
|
|
1185
|
+
title: definition.title ?? definition.id,
|
|
1186
|
+
onLoad: (event) => forwardShortcuts(event.currentTarget),
|
|
1187
|
+
...Preview === PreviewCanvas && { expanded: canvasExpanded, onExpandedChange: setCanvasExpanded }
|
|
1160
1188
|
},
|
|
1161
|
-
|
|
1162
|
-
) : /* @__PURE__ */ jsx13("div", { className: "absolute inset-0 grid place-items-center text-faint", children:
|
|
1163
|
-
|
|
1189
|
+
definition.id
|
|
1190
|
+
) : /* @__PURE__ */ jsx13("div", { className: "absolute inset-0 grid place-items-center text-faint", children: definition ? "This tool has no preview" : "No tools registered" }),
|
|
1191
|
+
["left", "right"].filter((side) => hidden[side] && (side === "left" || handle)).map((side) => {
|
|
1164
1192
|
const Chevron = side === "left" ? ChevronRight : ChevronLeft;
|
|
1193
|
+
const label = side === "left" ? "Show tools" : "Show inspector";
|
|
1165
1194
|
return /* @__PURE__ */ jsx13(
|
|
1166
1195
|
"div",
|
|
1167
1196
|
{
|
|
@@ -1175,8 +1204,9 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1175
1204
|
sideOffset: 8,
|
|
1176
1205
|
className: "flex items-center gap-2",
|
|
1177
1206
|
content: /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1178
|
-
|
|
1207
|
+
label,
|
|
1179
1208
|
" ",
|
|
1209
|
+
/* @__PURE__ */ jsx13("span", { className: "text-faint", children: "\xB7 both" }),
|
|
1180
1210
|
/* @__PURE__ */ jsxs7(KbdGroup, { children: [
|
|
1181
1211
|
/* @__PURE__ */ jsx13(Kbd, { children: "\u2318/Ctrl" }),
|
|
1182
1212
|
/* @__PURE__ */ jsx13(Kbd, { children: "B" })
|
|
@@ -1188,8 +1218,8 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1188
1218
|
"data-slot": "studio-panel-reveal",
|
|
1189
1219
|
variant: "ghost",
|
|
1190
1220
|
size: "icon",
|
|
1191
|
-
"aria-label":
|
|
1192
|
-
onClick:
|
|
1221
|
+
"aria-label": label,
|
|
1222
|
+
onClick: show[side],
|
|
1193
1223
|
className: cn(
|
|
1194
1224
|
"absolute top-1/2 h-16 w-6 -translate-y-1/2 cursor-pointer px-0 text-sidebar-foreground opacity-0 transition-[translate,opacity] duration-200 ease-out hover:bg-sidebar/95 hover:text-foreground focus:translate-x-0 focus:opacity-100 group-hover/edge:translate-x-0 group-hover/edge:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-x-0 [@media(hover:none)]:opacity-100",
|
|
1195
1225
|
side === "left" ? "left-1 -translate-x-[calc(100%+0.25rem)]" : "right-1 translate-x-[calc(100%+0.25rem)]"
|
|
@@ -1208,11 +1238,11 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1208
1238
|
{
|
|
1209
1239
|
collapsible: "icon",
|
|
1210
1240
|
variant: "floating",
|
|
1211
|
-
inert:
|
|
1212
|
-
"aria-hidden":
|
|
1241
|
+
inert: hidden.left,
|
|
1242
|
+
"aria-hidden": hidden.left,
|
|
1213
1243
|
className: cn(
|
|
1214
1244
|
"transition-[left,right,width,translate] duration-200 ease-out motion-reduce:transition-none",
|
|
1215
|
-
|
|
1245
|
+
hidden.left && "-translate-x-[calc(100%+1rem)]"
|
|
1216
1246
|
),
|
|
1217
1247
|
children: [
|
|
1218
1248
|
/* @__PURE__ */ jsx13(SidebarHeader, { className: "h-10 flex-row items-center overflow-hidden py-0 pr-0 pl-4 transition-[padding] duration-200 ease-out group-data-[collapsible=icon]:pl-[calc(1.5rem-0.875rem*352/144/2)] motion-reduce:transition-none", children: /* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-2.5 text-foreground", children: [
|
|
@@ -1223,20 +1253,21 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1223
1253
|
version
|
|
1224
1254
|
] })
|
|
1225
1255
|
] }) }),
|
|
1226
|
-
/* @__PURE__ */ jsx13(SidebarContent, { children: /* @__PURE__ */ jsx13(SidebarGroup, { children: /* @__PURE__ */ jsx13(SidebarMenu, { children: tools.map((
|
|
1227
|
-
const title =
|
|
1228
|
-
const isPinned = pinned.has(
|
|
1256
|
+
/* @__PURE__ */ jsx13(SidebarContent, { children: /* @__PURE__ */ jsx13(SidebarGroup, { children: /* @__PURE__ */ jsx13(SidebarMenu, { children: tools.map((tool) => {
|
|
1257
|
+
const title = tool.title ?? tool.id;
|
|
1258
|
+
const isPinned = pinned.has(tool.id);
|
|
1259
|
+
const { state, dirty } = studio.tools.find((handle2) => handle2.definition.id === tool.id) ?? {};
|
|
1229
1260
|
const pinLabel = `${isPinned ? "Unpin" : "Pin"} ${title}`;
|
|
1230
1261
|
return /* @__PURE__ */ jsxs7(SidebarMenuItem, { children: [
|
|
1231
1262
|
/* @__PURE__ */ jsxs7(
|
|
1232
1263
|
SidebarMenuButton,
|
|
1233
1264
|
{
|
|
1234
|
-
isActive:
|
|
1265
|
+
isActive: tool.id === selected,
|
|
1235
1266
|
tooltip: title,
|
|
1236
|
-
onClick: () => location.hash =
|
|
1267
|
+
onClick: () => location.hash = tool.id,
|
|
1237
1268
|
children: [
|
|
1238
1269
|
/* @__PURE__ */ jsxs7("span", { className: "relative", children: [
|
|
1239
|
-
/* @__PURE__ */ jsx13(ToolIcon, { icon:
|
|
1270
|
+
/* @__PURE__ */ jsx13(ToolIcon, { icon: tool.icon, className: "size-4" }),
|
|
1240
1271
|
dirty && /* @__PURE__ */ jsx13(
|
|
1241
1272
|
"span",
|
|
1242
1273
|
{
|
|
@@ -1259,7 +1290,7 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1259
1290
|
"aria-label": pinLabel,
|
|
1260
1291
|
"aria-pressed": isPinned,
|
|
1261
1292
|
showOnHover: !isPinned,
|
|
1262
|
-
onClick: () => togglePin(
|
|
1293
|
+
onClick: () => togglePin(tool.id),
|
|
1263
1294
|
className: cn(
|
|
1264
1295
|
"cursor-pointer [&>svg]:size-3 [@media(hover:none)]:opacity-100",
|
|
1265
1296
|
isPinned && "text-sidebar-primary"
|
|
@@ -1267,7 +1298,7 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1267
1298
|
children: /* @__PURE__ */ jsx13(Pin2, { "aria-hidden": true, fill: isPinned ? "currentColor" : "none" })
|
|
1268
1299
|
}
|
|
1269
1300
|
) })
|
|
1270
|
-
] },
|
|
1301
|
+
] }, tool.id);
|
|
1271
1302
|
}) }) }) }),
|
|
1272
1303
|
/* @__PURE__ */ jsx13(StudioFooter, { connection: studio.connection })
|
|
1273
1304
|
]
|
|
@@ -1277,11 +1308,11 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1277
1308
|
"aside",
|
|
1278
1309
|
{
|
|
1279
1310
|
"data-slot": "studio-inspector",
|
|
1280
|
-
inert:
|
|
1281
|
-
"aria-hidden":
|
|
1311
|
+
inert: hidden.right,
|
|
1312
|
+
"aria-hidden": hidden.right,
|
|
1282
1313
|
className: cn(
|
|
1283
1314
|
"absolute inset-y-2 right-2 z-10 flex w-(--studio-inspector-width) flex-col gap-1 p-1 transition-transform duration-200 ease-out motion-reduce:transition-none",
|
|
1284
|
-
|
|
1315
|
+
hidden.right && "translate-x-[calc(100%+1rem)]"
|
|
1285
1316
|
),
|
|
1286
1317
|
children: /* @__PURE__ */ jsx13(
|
|
1287
1318
|
Inspector,
|
|
@@ -1303,7 +1334,7 @@ function Studio({ studio, previewComponent, getConfigFileHref }) {
|
|
|
1303
1334
|
// src/react/command-menu.tsx
|
|
1304
1335
|
import { Pin as Pin3 } from "lucide-react";
|
|
1305
1336
|
import { Dialog } from "radix-ui";
|
|
1306
|
-
import { useEffect as
|
|
1337
|
+
import { useEffect as useEffect6, useRef as useRef4, useState as useState9 } from "react";
|
|
1307
1338
|
|
|
1308
1339
|
// src/react/ui/command.tsx
|
|
1309
1340
|
import * as React3 from "react";
|
|
@@ -1371,10 +1402,10 @@ function CommandItem({ className, ...props }) {
|
|
|
1371
1402
|
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1372
1403
|
function StudioCommandMenu({ studio, studioPath = "/studio", navigate }) {
|
|
1373
1404
|
const { tools, pinned } = usePinnedTools(studio);
|
|
1374
|
-
const [open, setOpen] =
|
|
1405
|
+
const [open, setOpen] = useState9(false);
|
|
1375
1406
|
const opener = useRef4(null);
|
|
1376
1407
|
const input = useRef4(null);
|
|
1377
|
-
|
|
1408
|
+
useEffect6(() => {
|
|
1378
1409
|
if (window.frameElement?.getAttribute("data-slot") === "studio-preview") return;
|
|
1379
1410
|
const onKey = (event) => {
|
|
1380
1411
|
if (event.defaultPrevented || event.isComposing || event.altKey || !(event.metaKey || event.ctrlKey)) return;
|
|
@@ -1425,8 +1456,8 @@ function StudioCommandMenu({ studio, studioPath = "/studio", navigate }) {
|
|
|
1425
1456
|
/* @__PURE__ */ jsxs9(Command, { label: "Studio tools", loop: true, vimBindings: false, children: [
|
|
1426
1457
|
/* @__PURE__ */ jsx15(CommandInput, { ref: input, placeholder: "Search tools\u2026" }),
|
|
1427
1458
|
/* @__PURE__ */ jsxs9(CommandList, { children: [
|
|
1428
|
-
/* @__PURE__ */ jsx15(CommandEmpty, { children: studio.
|
|
1429
|
-
tools.map((
|
|
1459
|
+
/* @__PURE__ */ jsx15(CommandEmpty, { children: studio.definitions.length ? "No tools found." : "No tools registered yet." }),
|
|
1460
|
+
tools.map((tool) => /* @__PURE__ */ jsxs9(
|
|
1430
1461
|
CommandItem,
|
|
1431
1462
|
{
|
|
1432
1463
|
value: tool.id,
|