@json-render/solid 0.16.0 → 0.18.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/dist/index.mjs CHANGED
@@ -195,7 +195,7 @@ import { insert as _$insert } from "solid-js/web";
195
195
  import { addEventListener as _$addEventListener } from "solid-js/web";
196
196
  import { createComponent as _$createComponent4 } from "solid-js/web";
197
197
  import { createContext as createContext4, useContext as useContext4, createSignal as createSignal3 } from "solid-js";
198
- import { resolveAction, executeAction } from "@json-render/core";
198
+ import { resolveAction, executeAction, nextActionDispatchId, notifyActionDispatch, notifyActionSettle } from "@json-render/core";
199
199
 
200
200
  // src/contexts/validation.tsx
201
201
  import { createComponent as _$createComponent3 } from "solid-js/web";
@@ -431,146 +431,172 @@ function ActionProvider(props) {
431
431
  };
432
432
  const execute = async (binding) => {
433
433
  const resolved = resolveAction(binding, getSnapshot());
434
- if (resolved.action === "setState" && resolved.params) {
435
- const statePath = resolved.params.statePath;
436
- const value = resolved.params.value;
437
- if (statePath) {
438
- set(statePath, value);
439
- }
440
- return;
441
- }
442
- if (resolved.action === "pushState" && resolved.params) {
443
- const statePath = resolved.params.statePath;
444
- const rawValue = resolved.params.value;
445
- if (statePath) {
446
- const resolvedValue = deepResolveValue(rawValue, get);
447
- const arr = get(statePath) ?? [];
448
- set(statePath, [...arr, resolvedValue]);
449
- const clearStatePath = resolved.params.clearStatePath;
450
- if (clearStatePath) {
451
- set(clearStatePath, "");
434
+ const dispatchId = nextActionDispatchId();
435
+ const dispatchedAt = Date.now();
436
+ notifyActionDispatch({
437
+ id: dispatchId,
438
+ name: resolved.action,
439
+ params: resolved.params,
440
+ at: dispatchedAt
441
+ });
442
+ let __ok = true;
443
+ let __error = void 0;
444
+ try {
445
+ if (resolved.action === "setState" && resolved.params) {
446
+ const statePath = resolved.params.statePath;
447
+ const value = resolved.params.value;
448
+ if (statePath) {
449
+ set(statePath, value);
452
450
  }
451
+ return;
453
452
  }
454
- return;
455
- }
456
- if (resolved.action === "removeState" && resolved.params) {
457
- const statePath = resolved.params.statePath;
458
- const index = resolved.params.index;
459
- if (statePath !== void 0 && index !== void 0) {
460
- const arr = get(statePath) ?? [];
461
- set(statePath, arr.filter((_, i) => i !== index));
462
- }
463
- return;
464
- }
465
- if (resolved.action === "push" && resolved.params) {
466
- const screen = resolved.params.screen;
467
- if (screen) {
468
- const currentScreen = get("/currentScreen");
469
- const navStack = get("/navStack") ?? [];
470
- if (currentScreen) {
471
- set("/navStack", [...navStack, currentScreen]);
472
- } else {
473
- set("/navStack", [...navStack, ""]);
453
+ if (resolved.action === "pushState" && resolved.params) {
454
+ const statePath = resolved.params.statePath;
455
+ const rawValue = resolved.params.value;
456
+ if (statePath) {
457
+ const resolvedValue = deepResolveValue(rawValue, get);
458
+ const arr = get(statePath) ?? [];
459
+ set(statePath, [...arr, resolvedValue]);
460
+ const clearStatePath = resolved.params.clearStatePath;
461
+ if (clearStatePath) {
462
+ set(clearStatePath, "");
463
+ }
474
464
  }
475
- set("/currentScreen", screen);
465
+ return;
476
466
  }
477
- return;
478
- }
479
- if (resolved.action === "pop") {
480
- const navStack = get("/navStack") ?? [];
481
- if (navStack.length > 0) {
482
- const previousScreen = navStack[navStack.length - 1];
483
- set("/navStack", navStack.slice(0, -1));
484
- if (previousScreen) {
485
- set("/currentScreen", previousScreen);
486
- } else {
487
- set("/currentScreen", void 0);
467
+ if (resolved.action === "removeState" && resolved.params) {
468
+ const statePath = resolved.params.statePath;
469
+ const index = resolved.params.index;
470
+ if (statePath !== void 0 && index !== void 0) {
471
+ const arr = get(statePath) ?? [];
472
+ set(statePath, arr.filter((_, i) => i !== index));
488
473
  }
474
+ return;
489
475
  }
490
- return;
491
- }
492
- if (resolved.action === "validateForm") {
493
- const validateAll = validation?.validateAll;
494
- if (!validateAll) {
495
- console.warn("validateForm action was dispatched but no ValidationProvider is connected. Ensure ValidationProvider is rendered inside the provider tree.");
476
+ if (resolved.action === "push" && resolved.params) {
477
+ const screen = resolved.params.screen;
478
+ if (screen) {
479
+ const currentScreen = get("/currentScreen");
480
+ const navStack = get("/navStack") ?? [];
481
+ if (currentScreen) {
482
+ set("/navStack", [...navStack, currentScreen]);
483
+ } else {
484
+ set("/navStack", [...navStack, ""]);
485
+ }
486
+ set("/currentScreen", screen);
487
+ }
496
488
  return;
497
489
  }
498
- const valid = validateAll();
499
- const errors = {};
500
- for (const [path, fs] of Object.entries(validation.fieldStates)) {
501
- if (fs.result && !fs.result.valid) {
502
- errors[path] = fs.result.errors;
490
+ if (resolved.action === "pop") {
491
+ const navStack = get("/navStack") ?? [];
492
+ if (navStack.length > 0) {
493
+ const previousScreen = navStack[navStack.length - 1];
494
+ set("/navStack", navStack.slice(0, -1));
495
+ if (previousScreen) {
496
+ set("/currentScreen", previousScreen);
497
+ } else {
498
+ set("/currentScreen", void 0);
499
+ }
503
500
  }
501
+ return;
504
502
  }
505
- const statePath = resolved.params?.statePath || "/formValidation";
506
- set(statePath, {
507
- valid,
508
- errors
509
- });
510
- return;
511
- }
512
- const handler = handlers()[resolved.action];
513
- if (!handler) {
514
- console.warn(`No handler registered for action: ${resolved.action}`);
515
- return;
516
- }
517
- if (resolved.confirm) {
518
- return new Promise((resolve, reject) => {
519
- setPendingConfirmation({
520
- action: resolved,
521
- handler,
522
- resolve: () => {
523
- setPendingConfirmation(null);
524
- resolve();
525
- },
526
- reject: () => {
527
- setPendingConfirmation(null);
528
- reject(new Error("Action cancelled"));
503
+ if (resolved.action === "validateForm") {
504
+ const validateAll = validation?.validateAll;
505
+ if (!validateAll) {
506
+ console.warn("validateForm action was dispatched but no ValidationProvider is connected. Ensure ValidationProvider is rendered inside the provider tree.");
507
+ return;
508
+ }
509
+ const valid = validateAll();
510
+ const errors = {};
511
+ for (const [path, fs] of Object.entries(validation.fieldStates)) {
512
+ if (fs.result && !fs.result.valid) {
513
+ errors[path] = fs.result.errors;
529
514
  }
515
+ }
516
+ const statePath = resolved.params?.statePath || "/formValidation";
517
+ set(statePath, {
518
+ valid,
519
+ errors
530
520
  });
531
- }).then(async () => {
532
- setLoadingActions((prev) => new Set(prev).add(resolved.action));
533
- try {
534
- await executeAction({
521
+ return;
522
+ }
523
+ const handler = handlers()[resolved.action];
524
+ if (!handler) {
525
+ console.warn(`No handler registered for action: ${resolved.action}`);
526
+ return;
527
+ }
528
+ if (resolved.confirm) {
529
+ return new Promise((resolve, reject) => {
530
+ setPendingConfirmation({
535
531
  action: resolved,
536
532
  handler,
537
- setState: set,
538
- navigate: props.navigate,
539
- executeAction: async (name) => {
540
- const subBinding = {
541
- action: name
542
- };
543
- await execute(subBinding);
533
+ resolve: () => {
534
+ setPendingConfirmation(null);
535
+ resolve();
536
+ },
537
+ reject: () => {
538
+ setPendingConfirmation(null);
539
+ reject(new Error("Action cancelled"));
544
540
  }
545
541
  });
546
- } finally {
547
- setLoadingActions((prev) => {
548
- const next = new Set(prev);
549
- next.delete(resolved.action);
550
- return next;
551
- });
552
- }
553
- });
554
- }
555
- setLoadingActions((prev) => new Set(prev).add(resolved.action));
556
- try {
557
- await executeAction({
558
- action: resolved,
559
- handler,
560
- setState: set,
561
- navigate: props.navigate,
562
- executeAction: async (name) => {
563
- const subBinding = {
564
- action: name
565
- };
566
- await execute(subBinding);
567
- }
568
- });
542
+ }).then(async () => {
543
+ setLoadingActions((prev) => new Set(prev).add(resolved.action));
544
+ try {
545
+ await executeAction({
546
+ action: resolved,
547
+ handler,
548
+ setState: set,
549
+ navigate: props.navigate,
550
+ executeAction: async (name) => {
551
+ const subBinding = {
552
+ action: name
553
+ };
554
+ await execute(subBinding);
555
+ }
556
+ });
557
+ } finally {
558
+ setLoadingActions((prev) => {
559
+ const next = new Set(prev);
560
+ next.delete(resolved.action);
561
+ return next;
562
+ });
563
+ }
564
+ });
565
+ }
566
+ setLoadingActions((prev) => new Set(prev).add(resolved.action));
567
+ try {
568
+ await executeAction({
569
+ action: resolved,
570
+ handler,
571
+ setState: set,
572
+ navigate: props.navigate,
573
+ executeAction: async (name) => {
574
+ const subBinding = {
575
+ action: name
576
+ };
577
+ await execute(subBinding);
578
+ }
579
+ });
580
+ } finally {
581
+ setLoadingActions((prev) => {
582
+ const next = new Set(prev);
583
+ next.delete(resolved.action);
584
+ return next;
585
+ });
586
+ }
587
+ } catch (err) {
588
+ __ok = false;
589
+ __error = err;
590
+ throw err;
569
591
  } finally {
570
- setLoadingActions((prev) => {
571
- const next = new Set(prev);
572
- next.delete(resolved.action);
573
- return next;
592
+ const now = Date.now();
593
+ notifyActionSettle({
594
+ id: dispatchId,
595
+ name: resolved.action,
596
+ ok: __ok,
597
+ at: now,
598
+ durationMs: now - dispatchedAt,
599
+ error: __error
574
600
  });
575
601
  }
576
602
  };
@@ -662,15 +688,26 @@ function useRepeatScope() {
662
688
  import { createStateStore as createStateStore2 } from "@json-render/core";
663
689
 
664
690
  // src/renderer.tsx
691
+ import { template as _$template2 } from "solid-js/web";
692
+ import { setAttribute as _$setAttribute } from "solid-js/web";
693
+ import { effect as _$effect2 } from "solid-js/web";
694
+ import { insert as _$insert2 } from "solid-js/web";
665
695
  import { memo as _$memo2 } from "solid-js/web";
666
696
  import { createComponent as _$createComponent6 } from "solid-js/web";
667
- import { createContext as createContext6, useContext as useContext6, createMemo as createMemo3, createEffect as createEffect3, onCleanup as onCleanup2, ErrorBoundary, Show, For } from "solid-js";
668
- import { resolveElementProps, resolveBindings, resolveActionParam, evaluateVisibility as evaluateVisibility2, getByPath as getByPath2 } from "@json-render/core";
697
+ import { createContext as createContext6, useContext as useContext6, createMemo as createMemo3, createEffect as createEffect3, createSignal as createSignal4, onCleanup as onCleanup2, ErrorBoundary, Show, For } from "solid-js";
698
+ import { resolveElementProps, resolveBindings, resolveActionParam, evaluateVisibility as evaluateVisibility2, getByPath as getByPath2, isDevtoolsActive, subscribeDevtoolsActive } from "@json-render/core";
699
+ var _tmpl$2 = /* @__PURE__ */ _$template2(`<span style=display:contents>`);
669
700
  var EMPTY_FUNCTIONS = {};
670
701
  var FunctionsContext = createContext6(EMPTY_FUNCTIONS);
671
702
  function useFunctions() {
672
703
  return useContext6(FunctionsContext) ?? EMPTY_FUNCTIONS;
673
704
  }
705
+ function useDevtoolsActive() {
706
+ const [active, setActive] = createSignal4(isDevtoolsActive());
707
+ const unsub = subscribeDevtoolsActive(() => setActive(isDevtoolsActive()));
708
+ onCleanup2(unsub);
709
+ return active;
710
+ }
674
711
  function ElementRenderer(props) {
675
712
  const repeatScope = useRepeatScope();
676
713
  const {
@@ -811,6 +848,9 @@ function ElementRenderer(props) {
811
848
  get resolvedElement() {
812
849
  return resolvedElement();
813
850
  },
851
+ get elementKey() {
852
+ return props.elementKey;
853
+ },
814
854
  get spec() {
815
855
  return props.spec;
816
856
  },
@@ -835,6 +875,7 @@ function ElementRenderer(props) {
835
875
  });
836
876
  }
837
877
  function ElementRendererContent(props) {
878
+ const devtoolsActive = useDevtoolsActive();
838
879
  const Comp = () => props.registry[props.resolvedElement.type] ?? props.fallback;
839
880
  return _$createComponent6(Show, {
840
881
  get when() {
@@ -882,6 +923,7 @@ function ElementRendererContent(props) {
882
923
  get element() {
883
924
  return el();
884
925
  },
926
+ elementKey: childKey,
885
927
  get spec() {
886
928
  return props.spec;
887
929
  },
@@ -898,7 +940,7 @@ function ElementRendererContent(props) {
898
940
  });
899
941
  }
900
942
  });
901
- return _$createComponent6(Component, {
943
+ const rendered = _$createComponent6(Component, {
902
944
  get element() {
903
945
  return props.resolvedElement;
904
946
  },
@@ -918,6 +960,18 @@ function ElementRendererContent(props) {
918
960
  return children();
919
961
  }
920
962
  });
963
+ return _$createComponent6(Show, {
964
+ get when() {
965
+ return _$memo2(() => !!devtoolsActive())() && props.elementKey;
966
+ },
967
+ fallback: rendered,
968
+ get children() {
969
+ var _el$ = _tmpl$2();
970
+ _$insert2(_el$, rendered);
971
+ _$effect2(() => _$setAttribute(_el$, "data-jr-key", props.elementKey));
972
+ return _el$;
973
+ }
974
+ });
921
975
  }
922
976
  });
923
977
  }
@@ -999,6 +1053,9 @@ function Renderer(props) {
999
1053
  get element() {
1000
1054
  return el();
1001
1055
  },
1056
+ get elementKey() {
1057
+ return props.spec.root;
1058
+ },
1002
1059
  get spec() {
1003
1060
  return props.spec;
1004
1061
  },
@@ -1189,7 +1246,7 @@ function createRenderer(catalog, components) {
1189
1246
  }
1190
1247
 
1191
1248
  // src/hooks.ts
1192
- import { createSignal as createSignal4, onCleanup as onCleanup3, createMemo as createMemo4 } from "solid-js";
1249
+ import { createSignal as createSignal5, onCleanup as onCleanup3, createMemo as createMemo4 } from "solid-js";
1193
1250
  import {
1194
1251
  setByPath,
1195
1252
  getByPath as getByPath3,
@@ -1333,11 +1390,11 @@ function applyPatch(spec, patch) {
1333
1390
  return newSpec;
1334
1391
  }
1335
1392
  function useUIStream(options) {
1336
- const [spec, setSpec] = createSignal4(null);
1337
- const [isStreaming, setIsStreaming] = createSignal4(false);
1338
- const [error, setError] = createSignal4(null);
1339
- const [usage, setUsage] = createSignal4(null);
1340
- const [rawLines, setRawLines] = createSignal4([]);
1393
+ const [spec, setSpec] = createSignal5(null);
1394
+ const [isStreaming, setIsStreaming] = createSignal5(false);
1395
+ const [error, setError] = createSignal5(null);
1396
+ const [usage, setUsage] = createSignal5(null);
1397
+ const [rawLines, setRawLines] = createSignal5([]);
1341
1398
  let abortController = null;
1342
1399
  const clear = () => {
1343
1400
  setSpec(null);
@@ -1554,9 +1611,9 @@ function generateChatId() {
1554
1611
  return `msg-${Date.now()}-${chatMessageIdCounter}`;
1555
1612
  }
1556
1613
  function useChatUI(options) {
1557
- const [messages, setMessages] = createSignal4([]);
1558
- const [isStreaming, setIsStreaming] = createSignal4(false);
1559
- const [error, setError] = createSignal4(null);
1614
+ const [messages, setMessages] = createSignal5([]);
1615
+ const [isStreaming, setIsStreaming] = createSignal5(false);
1616
+ const [error, setError] = createSignal5(null);
1560
1617
  let abortController = null;
1561
1618
  const clear = () => {
1562
1619
  setMessages([]);