@jxsuite/studio 0.13.0 → 0.15.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.
Files changed (38) hide show
  1. package/dist/studio.js +467 -625
  2. package/dist/studio.js.map +37 -37
  3. package/package.json +1 -1
  4. package/src/canvas/canvas-live-render.js +25 -0
  5. package/src/canvas/canvas-render.js +20 -2
  6. package/src/canvas/canvas-utils.js +1 -2
  7. package/src/editor/component-inline-edit.js +1 -3
  8. package/src/editor/content-inline-edit.js +1 -3
  9. package/src/editor/context-menu.js +73 -35
  10. package/src/editor/insertion-helper.js +0 -1
  11. package/src/editor/shortcuts.js +39 -45
  12. package/src/files/file-ops.js +57 -108
  13. package/src/files/files.js +13 -8
  14. package/src/panels/activity-bar.js +6 -4
  15. package/src/panels/canvas-dnd.js +4 -10
  16. package/src/panels/dnd.js +45 -7
  17. package/src/panels/editors.js +14 -16
  18. package/src/panels/elements-panel.js +13 -13
  19. package/src/panels/git-panel.js +2 -1
  20. package/src/panels/layers-panel.js +11 -12
  21. package/src/panels/left-panel.js +2 -2
  22. package/src/panels/panel-events.js +19 -25
  23. package/src/panels/preview-render.js +7 -3
  24. package/src/panels/pseudo-preview.js +9 -8
  25. package/src/panels/statusbar.js +8 -16
  26. package/src/panels/style-inputs.js +2 -3
  27. package/src/panels/style-utils.js +8 -6
  28. package/src/panels/stylebook-layers-panel.js +5 -5
  29. package/src/panels/stylebook-panel.js +16 -16
  30. package/src/panels/toolbar.js +2 -2
  31. package/src/state.js +2 -3
  32. package/src/store.js +2 -133
  33. package/src/studio.js +111 -239
  34. package/src/tabs/tab.js +19 -4
  35. package/src/tabs/transact.js +19 -1
  36. package/src/ui/color-selector.js +4 -5
  37. package/src/view.js +3 -0
  38. package/src/workspace/workspace.js +5 -0
package/src/state.js CHANGED
@@ -211,7 +211,6 @@ export function createState(doc) {
211
211
  mode: "component", // 'component' | 'content'
212
212
  content: { frontmatter: {} }, // frontmatter metadata for .md files
213
213
  ui: {
214
- leftTab: "layers", // 'files' | 'layers' | 'blocks' | 'state' | 'data'
215
214
  rightTab: "properties", // 'properties' | 'events' | 'style'
216
215
  zoom: 1,
217
216
  activeMedia: null, // '--md' | null (base) — focused canvas/breakpoint
@@ -377,7 +376,7 @@ export function pushDocument(state, doc, documentPath) {
377
376
  const newState = createState(doc);
378
377
  newState.documentStack = [...(state.documentStack || []), frame];
379
378
  newState.documentPath = documentPath;
380
- newState.ui = { ...state.ui, leftTab: "layers", activeMedia: null, activeSelector: null };
379
+ newState.ui = { ...state.ui, activeMedia: null, activeSelector: null };
381
380
  return newState;
382
381
  }
383
382
 
@@ -395,6 +394,6 @@ export function popDocument(state) {
395
394
  ...state,
396
395
  ...frame,
397
396
  documentStack: stack,
398
- ui: { ...state.ui, leftTab: "layers" },
397
+ ui: { ...state.ui },
399
398
  };
400
399
  }
package/src/store.js CHANGED
@@ -12,10 +12,6 @@ import { activeTab } from "./workspace/workspace.js";
12
12
 
13
13
  export {
14
14
  createState,
15
- selectNode,
16
- hoverNode,
17
- pushDocument,
18
- popDocument,
19
15
  getNodeAtPath,
20
16
  flattenTree,
21
17
  nodeLabel,
@@ -27,8 +23,6 @@ export {
27
23
  projectState,
28
24
  setProjectState,
29
25
  updateFrontmatter,
30
- toFlat,
31
- fromFlat,
32
26
  } from "./state.js";
33
27
 
34
28
  // ─── DOM shortcuts & element refs ────────────────────────────────────────────
@@ -213,85 +207,7 @@ export function renderOnly(...names) {
213
207
  }
214
208
  }
215
209
 
216
- // ─── Update dispatch (late-bound) ────────────────────────────────────────────
217
- // studio.js registers the real update implementation via setUpdateFn() during bootstrap.
218
- // This allows extracted modules to import `update` from store.js without circular deps.
219
-
220
- /** @type {(state: import("./state.js").StudioState) => void} */
221
- let _updateFn = () => {
222
- throw new Error("update() called before setUpdateFn() — bootstrap not complete");
223
- };
224
-
225
- /** @type {() => import("./state.js").StudioState | null} */
226
- let _getStateFn = () => null;
227
-
228
- /**
229
- * Register the update implementation. Called by studio.js at module load time.
230
- *
231
- * @param {(state: import("./state.js").StudioState) => void} fn
232
- */
233
- export function setUpdateFn(fn) {
234
- _updateFn = fn;
235
- }
236
-
237
- /**
238
- * Register the state getter. Called by studio.js at module load time.
239
- *
240
- * @param {() => import("./state.js").StudioState} fn — returns current S
241
- */
242
- export function setGetStateFn(fn) {
243
- _getStateFn = fn;
244
- }
245
-
246
- /**
247
- * Get the current state (live, not stale). Synthesized from the active tab's reactive state.
248
- *
249
- * @returns {import("./state.js").StudioState}
250
- */
251
- export function getState() {
252
- const tab = activeTab.value;
253
- if (tab) {
254
- return /** @type {any} */ ({
255
- document: tab.doc.document,
256
- mode: tab.doc.mode,
257
- dirty: tab.doc.dirty,
258
- handlersSource: tab.doc.handlersSource,
259
- content: tab.doc.content,
260
- documentPath: tab.documentPath,
261
- fileHandle: tab.fileHandle,
262
- selection: tab.session.selection,
263
- hover: tab.session.hover,
264
- clipboard: tab.session.clipboard,
265
- ui: tab.session.ui,
266
- canvas: tab.session.canvas,
267
- documentStack: tab.session.documentStack,
268
- });
269
- }
270
- return /** @type {any} */ (_getStateFn());
271
- }
272
-
273
- /**
274
- * Dispatch a state update + selective re-render.
275
- *
276
- * @param {import("./state.js").StudioState} newState
277
- */
278
- export function update(newState) {
279
- _updateFn(newState);
280
- }
281
-
282
- // ─── Session dispatch (late-bound) ──────────────────────────────────────────
283
- // Lightweight dispatcher for session-only changes (selection, hover, ui).
284
- // Does NOT trigger autosave middleware or push history.
285
-
286
- /** @type {(patch: object) => void} */
287
- let _updateSessionFn = () => {
288
- throw new Error("updateSession() called before setUpdateSessionFn() — bootstrap not complete");
289
- };
290
-
291
- /** @param {(patch: object) => void} fn */
292
- export function setUpdateSessionFn(fn) {
293
- _updateSessionFn = fn;
294
- }
210
+ // ─── Session dispatch ──────────────────────────────────────────────────────
295
211
 
296
212
  /**
297
213
  * Dispatch a session-only state update (selection, hover, ui). Writes directly to reactive tab.
@@ -316,11 +232,10 @@ export function updateSession(patch) {
316
232
  }
317
233
  }
318
234
  }
319
- _updateSessionFn(patch);
320
235
  }
321
236
 
322
237
  /**
323
- * Update a single UI field. Routes through session dispatch.
238
+ * Update a single UI field.
324
239
  *
325
240
  * @param {string} field
326
241
  * @param {unknown} value
@@ -330,7 +245,6 @@ export function updateUi(field, value) {
330
245
  if (tab) {
331
246
  /** @type {any} */ (tab.session.ui)[field] = value;
332
247
  }
333
- _updateSessionFn({ ui: { [field]: value } });
334
248
  }
335
249
 
336
250
  /**
@@ -345,49 +259,4 @@ export function updateCanvas(patch) {
345
259
  /** @type {any} */ (tab.session.canvas)[k] = v;
346
260
  }
347
261
  }
348
- _updateSessionFn({ canvas: patch });
349
- }
350
-
351
- /** @type {((state: import("./state.js").StudioState) => void)[]} */
352
- const _updateMiddleware = [];
353
-
354
- /**
355
- * Register middleware that runs after every update().
356
- *
357
- * @param {(state: import("./state.js").StudioState) => void} fn — receives (state) after core
358
- * update
359
- */
360
- export function addUpdateMiddleware(fn) {
361
- _updateMiddleware.push(fn);
362
- }
363
-
364
- /**
365
- * Run all registered update middleware.
366
- *
367
- * @param {import("./state.js").StudioState} state
368
- */
369
- export function runUpdateMiddleware(state) {
370
- for (const mw of _updateMiddleware) mw(state);
371
- }
372
-
373
- /** @type {((prevDoc: object, prevSel: import("./state.js").JxPath | null) => void)[]} */
374
- const _postRenderHooks = [];
375
-
376
- /**
377
- * Register a hook that runs after renders in update().
378
- *
379
- * @param {(prevDoc: object, prevSel: import("./state.js").JxPath | null) => void} fn
380
- */
381
- export function addPostRenderHook(fn) {
382
- _postRenderHooks.push(fn);
383
- }
384
-
385
- /**
386
- * Run all registered post-render hooks.
387
- *
388
- * @param {object} prevDoc
389
- * @param {import("./state.js").JxPath | null} prevSel
390
- */
391
- export function runPostRenderHooks(prevDoc, prevSel) {
392
- for (const hook of _postRenderHooks) hook(prevDoc, prevSel);
393
262
  }