@joycostudio/studio 0.1.4 → 0.1.5

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/dist/client.d.ts CHANGED
@@ -15,7 +15,7 @@ type ToolHandle<TConfig extends object = any> = {
15
15
  readonly definition: ToolDefinition<TConfig>;
16
16
  /** The live config. Writes sync to same-origin pages and, when connected, the runtime. */
17
17
  readonly config: TConfig;
18
- /** Runtime-owned state; null until the runtime answers (always null without one). */
18
+ /** Runtime-owned state; null while no runtime is connected or until it answers. */
19
19
  readonly state: ToolState<TConfig> | null;
20
20
  /** Bumps on every config change. Handy as a React snapshot. */
21
21
  readonly version: number;
@@ -25,7 +25,7 @@ type ToolHandle<TConfig extends object = any> = {
25
25
  controls(): DebugSchema;
26
26
  /** Xyz `Debuggable`: `debugManager.register(handle)` mounts this tool in the app's floating pane. */
27
27
  debug(): DebugFolder;
28
- /** The config on disk: the runtime's saved value or, until one answers, the bundled `initial`. */
28
+ /** The config on disk: the runtime's last reported saved value or, until one answers, the bundled `initial`. */
29
29
  readonly saved: TConfig;
30
30
  /** Dotted paths where the draft differs from `saved`. Tracked locally, so it works without a runtime too. */
31
31
  readonly changes: string[];
@@ -47,10 +47,15 @@ type ToolHandle<TConfig extends object = any> = {
47
47
  */
48
48
  undo(): boolean;
49
49
  redo(): boolean;
50
+ /** Persist the draft. Needs a connected runtime. */
50
51
  save(options?: {
51
52
  force?: boolean;
52
53
  }): Promise<Result<ToolState<TConfig>>>;
53
- discard(): Promise<Result<ToolState<TConfig>>>;
54
+ /**
55
+ * Reset the draft to `saved`, with or without a runtime, then sync it like any other edit.
56
+ * Undoable as its own step. Returns false when there is nothing to discard.
57
+ */
58
+ discard(): boolean;
54
59
  };
55
60
  type Studio = {
56
61
  /** Every registered tool in order, including preview-only ones. */
package/dist/client.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  createStudio,
3
3
  everyFrame,
4
4
  postCompare
5
- } from "./chunk-2RGQF5X5.js";
5
+ } from "./chunk-ZH3NEN4V.js";
6
6
  import "./chunk-DEJYGBPJ.js";
7
7
  export {
8
8
  createStudio,
package/dist/next.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createStudio
3
- } from "./chunk-2RGQF5X5.js";
3
+ } from "./chunk-ZH3NEN4V.js";
4
4
  import "./chunk-DEJYGBPJ.js";
5
5
 
6
6
  // src/next.ts
package/dist/react.d.ts CHANGED
@@ -93,7 +93,7 @@ type ToolHandle<TConfig extends object = any> = {
93
93
  readonly definition: ToolDefinition<TConfig>;
94
94
  /** The live config. Writes sync to same-origin pages and, when connected, the runtime. */
95
95
  readonly config: TConfig;
96
- /** Runtime-owned state; null until the runtime answers (always null without one). */
96
+ /** Runtime-owned state; null while no runtime is connected or until it answers. */
97
97
  readonly state: ToolState<TConfig> | null;
98
98
  /** Bumps on every config change. Handy as a React snapshot. */
99
99
  readonly version: number;
@@ -103,7 +103,7 @@ type ToolHandle<TConfig extends object = any> = {
103
103
  controls(): DebugSchema;
104
104
  /** Xyz `Debuggable`: `debugManager.register(handle)` mounts this tool in the app's floating pane. */
105
105
  debug(): DebugFolder;
106
- /** The config on disk: the runtime's saved value or, until one answers, the bundled `initial`. */
106
+ /** The config on disk: the runtime's last reported saved value or, until one answers, the bundled `initial`. */
107
107
  readonly saved: TConfig;
108
108
  /** Dotted paths where the draft differs from `saved`. Tracked locally, so it works without a runtime too. */
109
109
  readonly changes: string[];
@@ -125,10 +125,15 @@ type ToolHandle<TConfig extends object = any> = {
125
125
  */
126
126
  undo(): boolean;
127
127
  redo(): boolean;
128
+ /** Persist the draft. Needs a connected runtime. */
128
129
  save(options?: {
129
130
  force?: boolean;
130
131
  }): Promise<Result<ToolState<TConfig>>>;
131
- discard(): Promise<Result<ToolState<TConfig>>>;
132
+ /**
133
+ * Reset the draft to `saved`, with or without a runtime, then sync it like any other edit.
134
+ * Undoable as its own step. Returns false when there is nothing to discard.
135
+ */
136
+ discard(): boolean;
132
137
  };
133
138
  type Studio$1 = {
134
139
  /** Every registered tool in order, including preview-only ones. */
package/dist/react.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  import { useEffect as useEffect5, useRef as useRef3, useState as useState9 } from "react";
15
15
 
16
16
  // package.json
17
- var version = "0.1.4";
17
+ var version = "0.1.5";
18
18
 
19
19
  // src/client/studio.ts
20
20
  import {
@@ -409,7 +409,7 @@ function describe(studio, handle) {
409
409
  if (studio.connection.phase !== "connected") return { tone: "text-faint", text: "Not persisting" };
410
410
  if (!state) return { tone: "text-destructive", text: "Restart studio dev" };
411
411
  if (state.conflict) return { tone: "text-destructive", text: "Changed on disk" };
412
- if (state.dirty) return { tone: "text-warning", text: "Unsaved" };
412
+ if (handle.dirty) return { tone: "text-warning", text: "Unsaved" };
413
413
  return { tone: "text-success", text: state.saved.hash ? "Saved" : "Not on disk yet" };
414
414
  }
415
415
  function adoptTweakpaneStyles(container) {
@@ -429,8 +429,10 @@ function Inspector({
429
429
  const container = useRef(null);
430
430
  const pane = useRef(null);
431
431
  const [failure, setFailure] = useState2(null);
432
- const run = (action) => void action.then((result) => setFailure(result.ok ? null : result.message ?? result.error));
433
- const save = (force = false) => run(handle.save({ force }));
432
+ const { definition, state } = handle;
433
+ const canDiscard = handle.dirty && !handle.comparing;
434
+ const canSave = canDiscard && !!state;
435
+ const save = (force = false) => void handle.save({ force }).then((result) => setFailure(result.ok ? null : result.message ?? result.error));
434
436
  useEffect(() => {
435
437
  let disposed = false;
436
438
  let teardown = () => {
@@ -461,7 +463,7 @@ function Inspector({
461
463
  const onKeyDown = (event) => {
462
464
  if (event.key !== "s" || !(event.metaKey || event.ctrlKey)) return;
463
465
  event.preventDefault();
464
- if (handle.state?.dirty) save();
466
+ if (canSave) save();
465
467
  };
466
468
  addEventListener("keydown", onKeyDown);
467
469
  return () => removeEventListener("keydown", onKeyDown);
@@ -469,10 +471,8 @@ function Inspector({
469
471
  useEffect(() => {
470
472
  if (pane.current) pane.current.disabled = handle.comparing;
471
473
  });
472
- const { definition, state } = handle;
473
474
  const ConfigFile = fileHref ? "a" : "span";
474
475
  const status = describe(studio, handle);
475
- const editable2 = studio.connection.phase === "connected" && !!state?.dirty && !handle.comparing;
476
476
  const changes = handle.changes.map(
477
477
  (path) => path.split(".").map((key) => key.charAt(0).toUpperCase() + key.slice(1)).join(" \u203A ")
478
478
  );
@@ -549,12 +549,15 @@ function Inspector({
549
549
  variant: "secondary",
550
550
  size: "sm",
551
551
  className: "flex-1",
552
- disabled: !editable2,
553
- onClick: () => run(handle.discard()),
552
+ disabled: !canDiscard,
553
+ onClick: () => {
554
+ setFailure(null);
555
+ handle.discard();
556
+ },
554
557
  children: "Discard"
555
558
  }
556
559
  ),
557
- state?.conflict ? /* @__PURE__ */ jsx8(Button, { variant: "destructive", size: "sm", className: "flex-1", onClick: () => save(true), children: "Overwrite file" }) : /* @__PURE__ */ jsxs2(Button, { size: "sm", className: "flex-1", disabled: !editable2, onClick: () => save(), children: [
560
+ state?.conflict ? /* @__PURE__ */ jsx8(Button, { variant: "destructive", size: "sm", className: "flex-1", onClick: () => save(true), children: "Overwrite file" }) : /* @__PURE__ */ jsxs2(Button, { size: "sm", className: "flex-1", disabled: !canSave, onClick: () => save(), children: [
558
561
  "Save",
559
562
  /* @__PURE__ */ jsxs2(KbdGroup, { children: [
560
563
  /* @__PURE__ */ jsx8(Kbd, { children: "\u2318" }),