@calimero-network/mero-react 4.2.0 → 4.3.1

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 CHANGED
@@ -292,7 +292,7 @@ Helpers: `defaultMeroTheme` (the full default palette), `resolveMeroTheme(partia
292
292
 
293
293
  | Prop | Type | Default | Notes |
294
294
  |------|------|---------|-------|
295
- | `connectionType` | `ConnectionType \| CustomConnectionConfig` | `RemoteAndLocal` | Which options the embedded LoginModal shows. `Custom` skips the modal. |
295
+ | `connectionType` | `ConnectionType \| CustomConnectionConfig` | `Remote` | `Custom` connects straight to the given URL, skipping the modal. Every other value opens the LoginModal (node discovery + manual URL entry). |
296
296
  | `theme` | `MeroTheme` | — | Partial token override. |
297
297
  | `logoOnly` | `boolean` | `false` | Render only the Calimero logo (square button). The label is still announced via `aria-label`. |
298
298
  | `label` | `string \| { connect?, connected?, reconnecting? }` | — | Override default labels. Bare string targets the disconnected state. |
@@ -305,10 +305,10 @@ AppMode.SingleContext // 'single-context'
305
305
  AppMode.MultiContext // 'multi-context'
306
306
  AppMode.Admin // 'admin'
307
307
 
308
- ConnectionType.RemoteAndLocal // 'remote-and-local'
309
- ConnectionType.Remote // 'remote'
310
- ConnectionType.Local // 'local'
311
- ConnectionType.Custom // 'custom'
308
+ ConnectionType.Remote // 'remote' — opens the LoginModal (discovery + manual URL)
309
+ ConnectionType.Custom // 'custom' — skip the modal, connect to a fixed URL
310
+ ConnectionType.RemoteAndLocal // deprecated, same as Remote
311
+ ConnectionType.Local // deprecated, same as Remote
312
312
  ```
313
313
 
314
314
  ## Types
package/dist/index.cjs CHANGED
@@ -200,9 +200,18 @@ var isBrowser = typeof window !== "undefined";
200
200
  function getPermissionsForMode(mode) {
201
201
  switch (mode) {
202
202
  case "single-context" /* SingleContext */:
203
- return ["context:execute"];
203
+ return ["context:execute", "context:list", "application:list", "blob", "context:alias"];
204
204
  case "multi-context" /* MultiContext */:
205
- return ["context:create", "context:list", "context:execute"];
205
+ return [
206
+ "context:create",
207
+ "context:list",
208
+ "context:execute",
209
+ "application:list",
210
+ "namespace",
211
+ "group",
212
+ "blob",
213
+ "context:alias"
214
+ ];
206
215
  case "admin" /* Admin */:
207
216
  return ["admin"];
208
217
  default:
@@ -579,7 +588,6 @@ function themeToCssVars(theme) {
579
588
  function cssVar(theme, key) {
580
589
  return `var(${MERO_CSS_VARS[key]}, ${theme[key]})`;
581
590
  }
582
- var DEFAULT_LOCAL_NODE_URL = "http://node1.127.0.0.1.nip.io";
583
591
  var CUSTOM_SELECTION = "__custom__";
584
592
  function isValidUrl(urlString) {
585
593
  if (!urlString || urlString.trim() === "") {
@@ -697,29 +705,6 @@ function buildStyles(t) {
697
705
  fontSize: "0.875rem",
698
706
  textAlign: "center"
699
707
  },
700
- radioGroup: {
701
- display: "flex",
702
- gap: "0.75rem",
703
- marginBottom: "1rem",
704
- justifyContent: "center"
705
- },
706
- radioLabel: {
707
- display: "flex",
708
- alignItems: "center",
709
- gap: "0.5rem",
710
- color: text,
711
- cursor: "pointer",
712
- padding: "0.5rem 1rem",
713
- borderRadius: radius,
714
- border: `1px solid ${border}`,
715
- backgroundColor: bgSecondary,
716
- transition: "all 0.15s ease"
717
- },
718
- radioLabelActive: {
719
- border: `1px solid ${accent}`,
720
- backgroundColor: accentGlow,
721
- color: text
722
- },
723
708
  radioList: {
724
709
  display: "flex",
725
710
  flexDirection: "column",
@@ -782,29 +767,6 @@ function buildStyles(t) {
782
767
  marginBottom: "1rem",
783
768
  boxSizing: "border-box"
784
769
  },
785
- localInfo: {
786
- color: textSecondary,
787
- fontSize: "0.875rem",
788
- textAlign: "center",
789
- padding: "0.75rem",
790
- backgroundColor: bgSecondary,
791
- borderRadius: radius,
792
- marginBottom: "1rem",
793
- border: `1px solid ${border}`
794
- },
795
- localInfoCode: {
796
- color: accent
797
- },
798
- noNodeInfo: {
799
- color: textSecondary,
800
- fontSize: "0.875rem",
801
- textAlign: "center",
802
- padding: "0.75rem",
803
- backgroundColor: bgSecondary,
804
- borderRadius: radius,
805
- marginBottom: "1rem",
806
- border: `1px solid ${border}`
807
- },
808
770
  toolbar: {
809
771
  display: "flex",
810
772
  justifyContent: "center",
@@ -875,12 +837,10 @@ function buildStyles(t) {
875
837
  function LoginModal({
876
838
  onConnect,
877
839
  onClose,
878
- connectionType,
879
840
  isOpen,
880
841
  theme,
881
842
  localNodePorts = DEFAULT_LOCAL_NODE_PORTS
882
843
  }) {
883
- const [nodeType, setNodeType] = react.useState("local");
884
844
  const [selected, setSelected] = react.useState(CUSTOM_SELECTION);
885
845
  const [discovered, setDiscovered] = react.useState([]);
886
846
  const [discovering, setDiscovering] = react.useState(false);
@@ -893,27 +853,16 @@ function LoginModal({
893
853
  () => theme ? themeToCssVars(resolved) : void 0,
894
854
  [theme, resolved]
895
855
  );
896
- const shouldShowLocal = connectionType === "remote-and-local" /* RemoteAndLocal */ || connectionType === "local" /* Local */;
897
- const shouldShowRemote = connectionType === "remote-and-local" /* RemoteAndLocal */ || connectionType === "remote" /* Remote */;
898
- const shouldShowRadioGroup = shouldShowLocal && shouldShowRemote;
899
856
  react.useEffect(() => {
900
857
  const savedUrl = localStorage.getItem("mero:node_url");
901
858
  if (savedUrl) {
902
859
  setCustomUrl(savedUrl);
903
860
  }
904
861
  }, []);
905
- react.useEffect(() => {
906
- if (connectionType === "local" /* Local */) {
907
- setNodeType("local");
908
- } else if (connectionType === "remote" /* Remote */) {
909
- setNodeType("remote");
910
- }
911
- }, [connectionType]);
912
862
  const [scanNonce, setScanNonce] = react.useState(0);
913
863
  const portsKey = react.useMemo(() => localNodePorts.join(","), [localNodePorts]);
914
- const remoteActive = isOpen && shouldShowRemote && nodeType === "remote";
915
864
  react.useEffect(() => {
916
- if (!remoteActive) {
865
+ if (!isOpen) {
917
866
  return;
918
867
  }
919
868
  const controller = new AbortController();
@@ -934,16 +883,16 @@ function LoginModal({
934
883
  active = false;
935
884
  controller.abort();
936
885
  };
937
- }, [remoteActive, portsKey, scanNonce]);
886
+ }, [isOpen, portsKey, scanNonce]);
938
887
  const isCustom = selected === CUSTOM_SELECTION;
939
888
  const hasDiscovered = discovered.length > 0;
940
- const canConnect = !loading && (nodeType === "local" ? true : discovering ? false : isCustom ? isValidUrl(customUrl) : true);
889
+ const canConnect = !loading && !discovering && (isCustom ? isValidUrl(customUrl) : true);
941
890
  const canConnectRef = react.useRef(canConnect);
942
891
  canConnectRef.current = canConnect;
943
892
  const handleConnect = react.useCallback(async () => {
944
- const targetUrl = nodeType === "local" ? DEFAULT_LOCAL_NODE_URL : selected === CUSTOM_SELECTION ? customUrl : selected;
945
- const usingDiscovered = nodeType === "remote" && selected !== CUSTOM_SELECTION;
946
- if (nodeType === "remote" && !usingDiscovered && !isValidUrl(targetUrl)) {
893
+ const usingDiscovered = selected !== CUSTOM_SELECTION;
894
+ const targetUrl = usingDiscovered ? selected : customUrl;
895
+ if (!usingDiscovered && !isValidUrl(targetUrl)) {
947
896
  return;
948
897
  }
949
898
  const normalizedUrl = targetUrl.replace(/\/+$/, "");
@@ -968,7 +917,7 @@ function LoginModal({
968
917
  setError("Failed to connect. Please check the URL and try again.");
969
918
  setLoading(false);
970
919
  }
971
- }, [nodeType, selected, customUrl, onConnect]);
920
+ }, [selected, customUrl, onConnect]);
972
921
  if (!isOpen) {
973
922
  return null;
974
923
  }
@@ -1018,7 +967,7 @@ function LoginModal({
1018
967
  )
1019
968
  );
1020
969
  };
1021
- const renderRemoteView = () => {
970
+ const renderNodeSection = () => {
1022
971
  if (discovering) {
1023
972
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.discovering, "data-testid": "node-discovering", children: [
1024
973
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.spinnerSmall }),
@@ -1026,7 +975,7 @@ function LoginModal({
1026
975
  ] });
1027
976
  }
1028
977
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1029
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles.info, children: hasDiscovered ? "Select a discovered node, or enter a node URL manually." : "No local node found. Enter a node URL to continue." }),
978
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles.info, children: hasDiscovered ? "Select your Calimero node to continue." : "No local node found. Enter a node URL to continue." }),
1030
979
  hasDiscovered && /* @__PURE__ */ jsxRuntime.jsxs(
1031
980
  "div",
1032
981
  {
@@ -1086,64 +1035,8 @@ function LoginModal({
1086
1035
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Connecting to node..." }),
1087
1036
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.spinner })
1088
1037
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1089
- shouldShowRadioGroup && /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles.info, children: "Select your Calimero node type to continue." }),
1090
1038
  error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles.error, children: error }),
1091
- shouldShowRadioGroup && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.radioGroup, children: [
1092
- /* @__PURE__ */ jsxRuntime.jsxs(
1093
- "label",
1094
- {
1095
- "data-testid": "node-type-local",
1096
- style: {
1097
- ...styles.radioLabel,
1098
- ...nodeType === "local" ? styles.radioLabelActive : {}
1099
- },
1100
- onClick: () => setNodeType("local"),
1101
- children: [
1102
- /* @__PURE__ */ jsxRuntime.jsx(
1103
- "input",
1104
- {
1105
- type: "radio",
1106
- value: "local",
1107
- checked: nodeType === "local",
1108
- onChange: () => setNodeType("local"),
1109
- style: { display: "none" }
1110
- }
1111
- ),
1112
- "Local"
1113
- ]
1114
- }
1115
- ),
1116
- /* @__PURE__ */ jsxRuntime.jsxs(
1117
- "label",
1118
- {
1119
- "data-testid": "node-type-remote",
1120
- style: {
1121
- ...styles.radioLabel,
1122
- ...nodeType === "remote" ? styles.radioLabelActive : {}
1123
- },
1124
- onClick: () => setNodeType("remote"),
1125
- children: [
1126
- /* @__PURE__ */ jsxRuntime.jsx(
1127
- "input",
1128
- {
1129
- type: "radio",
1130
- value: "remote",
1131
- checked: nodeType === "remote",
1132
- onChange: () => setNodeType("remote"),
1133
- style: { display: "none" }
1134
- }
1135
- ),
1136
- "Remote"
1137
- ]
1138
- }
1139
- )
1140
- ] }),
1141
- nodeType === "local" && shouldShowLocal && /* @__PURE__ */ jsxRuntime.jsxs("p", { style: styles.localInfo, children: [
1142
- "Using default local node: ",
1143
- /* @__PURE__ */ jsxRuntime.jsx("br", {}),
1144
- /* @__PURE__ */ jsxRuntime.jsx("code", { style: styles.localInfoCode, children: DEFAULT_LOCAL_NODE_URL })
1145
- ] }),
1146
- nodeType === "remote" && shouldShowRemote && renderRemoteView(),
1039
+ renderNodeSection(),
1147
1040
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.buttonGroup, children: /* @__PURE__ */ jsxRuntime.jsx(
1148
1041
  "button",
1149
1042
  {
@@ -1163,7 +1056,7 @@ function LoginModal({
1163
1056
  return reactDom.createPortal(modalContent, document.body);
1164
1057
  }
1165
1058
  function ConnectButton({
1166
- connectionType = "remote-and-local" /* RemoteAndLocal */,
1059
+ connectionType = "remote" /* Remote */,
1167
1060
  className,
1168
1061
  style,
1169
1062
  theme,
@@ -1314,7 +1207,6 @@ function ConnectButton({
1314
1207
  isOpen: isModalOpen,
1315
1208
  onConnect: handleModalConnect,
1316
1209
  onClose: () => setIsModalOpen(false),
1317
- connectionType: typeof connectionType === "object" ? "remote-and-local" /* RemoteAndLocal */ : connectionType,
1318
1210
  theme: resolvedTheme ?? theme
1319
1211
  }
1320
1212
  )