@superblocksteam/library 2.0.74-next.2 → 2.0.75-next.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/dist/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as consoleLogAttributes, t as early_console_buffer_default } from "../early-console-buffer-D4wVuyBf.js";
2
- import { A as useSuperblocksProfiles, B as PropsCategory, C as addNewPromise, D as getAppMode, E as SuperblocksContextProvider, F as iframeMessageHandler, H as createPropertiesPanelDefinition, I as isEmbeddedBySuperblocksFirstParty, L as isEditMode, M as sendNotification, N as colors$1, O as useSuperblocksContext, P as editorBridge, R as createManagedPropsList, S as api_hmr_tracker_default, T as resolveById, U as getEditStore, V as Section, _ as root_store_default, a as FixWithClarkButton, b as createIframeSpan, c as ErrorContent, d as ErrorMessage, f as ErrorStack, g as StyledClarkIcon, h as SecondaryButton, i as getWidgetRectAnchorName, j as useSuperblocksUser, k as useSuperblocksGroups, l as ErrorDetails, m as ErrorTitle, n as useJSXContext, o as ActionsContainer, p as ErrorSummary, r as getWidgetAnchorName, s as ErrorContainer, u as ErrorIconContainer, v as startEditorSync, w as rejectById, x as getContextFromTraceHeaders, y as generateId, z as Prop } from "../jsx-wrapper-DpoYDtf8.js";
2
+ import { A as useSuperblocksProfiles, B as PropsCategory, C as addNewPromise, D as getAppMode, E as SuperblocksContextProvider, F as iframeMessageHandler, H as createPropertiesPanelDefinition, I as isEmbeddedBySuperblocksFirstParty, L as isEditMode, M as sendNotification, N as colors$1, O as useSuperblocksContext, P as editorBridge, R as createManagedPropsList, S as api_hmr_tracker_default, T as resolveById, U as getEditStore, V as Section, _ as root_store_default, a as FixWithClarkButton, b as createIframeSpan, c as ErrorContent, d as ErrorMessage, f as ErrorStack, g as StyledClarkIcon, h as SecondaryButton, i as getWidgetRectAnchorName, j as useSuperblocksUser, k as useSuperblocksGroups, l as ErrorDetails, m as ErrorTitle, n as useJSXContext, o as ActionsContainer, p as ErrorSummary, r as getWidgetAnchorName, s as ErrorContainer, u as ErrorIconContainer, v as startEditorSync, w as rejectById, x as getContextFromTraceHeaders, y as generateId, z as Prop } from "../jsx-wrapper-Dp_WgQK7.js";
3
3
  import { n as initTracerProviderWithOrigin } from "../utils-Clb3lSiX.js";
4
4
  import { action, autorun, computed, makeAutoObservable, makeObservable, observable, reaction, when } from "mobx";
5
5
  import { Dim, NATIVE_COMPONENT_TYPES, NO_SELECT_ATTRIBUTE, Property, Property as Property$1, SELECTOR_ID_ATTRIBUTE, SOURCE_ID_ATTRIBUTE, generateSourceId, getBindingIdentifier } from "@superblocksteam/library-shared";
@@ -862,11 +862,13 @@ function useApiStateful(name) {
862
862
  run: useCallback(async (inputs) => {
863
863
  const apiPath = getApiPath(name);
864
864
  const editMode = isEditMode();
865
- return (await root_store_default.apis.runApiByPath({
865
+ const result = await root_store_default.apis.runApiByPath({
866
866
  path: apiPath,
867
867
  inputs: inputs ?? {},
868
868
  ...editMode ? { injectedCallerId: sourceId } : {}
869
- })).data;
869
+ });
870
+ if (result?.error != null) console.error(`[useApi] [${name}]`, result.error);
871
+ return result.data;
870
872
  }, [name, sourceId]),
871
873
  cancel: useCallback(async () => {
872
874
  await root_store_default.apis.cancelApi(name);
@@ -874,6 +876,130 @@ function useApiStateful(name) {
874
876
  };
875
877
  }
876
878
 
879
+ //#endregion
880
+ //#region src/lib/internal-details/embed-store.ts
881
+ /**
882
+ * Store for managing embed properties and events.
883
+ * Used when the library is embedded in an external application (third-party embedding).
884
+ *
885
+ * Properties can be set by the parent window via postMessage, and events can be
886
+ * emitted back to the parent window.
887
+ */
888
+ var EmbedStore = class {
889
+ properties = {};
890
+ constructor() {
891
+ makeAutoObservable(this);
892
+ }
893
+ /**
894
+ * Update the embed properties. Called when the parent window sends updated properties.
895
+ */
896
+ setProperties(properties) {
897
+ this.properties = properties;
898
+ }
899
+ /**
900
+ * Emit an event to the parent window.
901
+ * The parent can listen for these events using window.addEventListener("message", ...).
902
+ */
903
+ emitEvent(eventName, payload = {}) {
904
+ if (typeof window === "undefined" || window.parent === window) return;
905
+ window.parent.postMessage({
906
+ type: "embed-emit-event",
907
+ payload: {
908
+ eventName,
909
+ payload
910
+ }
911
+ }, "*");
912
+ }
913
+ };
914
+ const embedStore = new EmbedStore();
915
+
916
+ //#endregion
917
+ //#region src/lib/internal-details/use-embed-message-listeners.ts
918
+ /**
919
+ * Hook that sets up common message listeners for embedded apps.
920
+ * Used by both edit-mode and deployed-mode EmbedWrapper components.
921
+ */
922
+ function useEmbedMessageListeners(navigate, superblocksContext) {
923
+ useEffect(() => {
924
+ const globalSyncListener = (event) => {
925
+ const { global } = event.data.payload;
926
+ superblocksContext.updateContext(global);
927
+ };
928
+ iframeMessageHandler.addEventListener("sb-global-sync", globalSyncListener);
929
+ const navigateToListener = async (event) => {
930
+ const { route, routeParams, queryParams } = event.data.payload;
931
+ const eventSearch = new URLSearchParams(queryParams);
932
+ const nextSearch = new URLSearchParams(window.location.search);
933
+ for (const [key, value] of eventSearch.entries()) nextSearch.set(key, value);
934
+ await navigate({
935
+ pathname: generatePath(route, routeParams),
936
+ search: nextSearch.toString()
937
+ });
938
+ };
939
+ iframeMessageHandler.addEventListener("route-change", navigateToListener);
940
+ const embedPropertyChangeListener = (event) => {
941
+ const { properties } = event.data.payload;
942
+ embedStore.setProperties(properties);
943
+ };
944
+ iframeMessageHandler.addEventListener("embed-property-change", embedPropertyChangeListener);
945
+ const embedTriggerEventListener = (event) => {
946
+ const { eventName, payload } = event.data.payload;
947
+ window.dispatchEvent(new CustomEvent(`superblocks:${eventName}`, { detail: payload }));
948
+ };
949
+ iframeMessageHandler.addEventListener("embed-trigger-event", embedTriggerEventListener);
950
+ return () => {
951
+ iframeMessageHandler.removeEventListener("sb-global-sync", globalSyncListener);
952
+ iframeMessageHandler.removeEventListener("route-change", navigateToListener);
953
+ iframeMessageHandler.removeEventListener("embed-property-change", embedPropertyChangeListener);
954
+ iframeMessageHandler.removeEventListener("embed-trigger-event", embedTriggerEventListener);
955
+ };
956
+ }, [navigate, superblocksContext]);
957
+ }
958
+
959
+ //#endregion
960
+ //#region src/lib/internal-details/utils/link-modifiers-interceptor.ts
961
+ /**
962
+ * Intercepts cmd/ctrl/shift+click and middle-click on local links inside an iframe
963
+ * to open them in a new tab using the parent URL.
964
+ *
965
+ * When `isEmbedMode` is true, modified clicks are converted into normal in-iframe
966
+ * navigation (no new tab).
967
+ */
968
+ function linkModifierInterceptor({ isEmbedMode = false, isEditMode: isEditMode$1 = false } = {}) {
969
+ if (typeof window === "undefined") return () => {};
970
+ if (window === window.parent) return () => {};
971
+ const handleClick = (ev) => {
972
+ const isMiddleClick = ev.button === 1;
973
+ const isModifierClick = ev.button === 0 && (ev.metaKey || ev.ctrlKey || ev.shiftKey);
974
+ if (isEditMode$1) {
975
+ if (!(ev.button === 0 && ev.shiftKey)) return;
976
+ } else if (!isMiddleClick && !isModifierClick) return;
977
+ if (ev.defaultPrevented) return;
978
+ const target = ev.target;
979
+ if (!(target instanceof Element)) return;
980
+ const anchor = target.closest?.("a[href]");
981
+ if (!(anchor instanceof HTMLAnchorElement)) return;
982
+ const href = anchor.getAttribute("href");
983
+ if (!href) return;
984
+ if (href.startsWith("#")) return;
985
+ if (href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//")) return;
986
+ const appId = root_store_default.applicationId;
987
+ if (!appId) return;
988
+ ev.preventDefault();
989
+ ev.stopPropagation();
990
+ const resolvedUrl = new URL(href, window.location.href);
991
+ const targetPath = resolvedUrl.pathname + resolvedUrl.search + resolvedUrl.hash;
992
+ if (isEmbedMode) {
993
+ anchor.click();
994
+ return;
995
+ }
996
+ const parentUrl = `/code-mode/applications/${isEditMode$1 ? "edit/" : ""}${appId}${targetPath}`;
997
+ editorBridge.navigateTo(parentUrl, true);
998
+ };
999
+ window.addEventListener("click", handleClick, true);
1000
+ return () => window.removeEventListener("click", handleClick, true);
1001
+ }
1002
+
877
1003
  //#endregion
878
1004
  //#region src/edit-mode/build-error-notification.tsx
879
1005
  const ModalOverlay = styled(Dialog.Overlay)`
@@ -2690,6 +2816,24 @@ const useObserverMemo = (fn, deps) => {
2690
2816
  return computed(fn);
2691
2817
  }, deps).get();
2692
2818
  };
2819
+ /**
2820
+ * Like useObserverMemo, but does not require the component to be wrapped in an observer.
2821
+ * It is recommended to use useObserverMemo instead.
2822
+ * @see useObserverMemo
2823
+ *
2824
+ * Note: This implementation uses MobX reactions to track both observable changes and
2825
+ * dependency changes.
2826
+ */
2827
+ const useStandaloneObserverMemo = (fn, deps) => {
2828
+ const fnRef = useRef(fn);
2829
+ fnRef.current = fn;
2830
+ const [result, setResult] = useState(fnRef.current);
2831
+ useEffect(() => reaction(() => fnRef.current(), setResult, {
2832
+ fireImmediately: true,
2833
+ name: "useStandaloneObserverMemo"
2834
+ }), deps);
2835
+ return result;
2836
+ };
2693
2837
 
2694
2838
  //#endregion
2695
2839
  //#region src/lib/user-facing/layers.ts
@@ -3285,6 +3429,9 @@ const IframeConnected = observer(function IframeConnected$1(props) {
3285
3429
  console.debug("[internal] [iframe-wrappers] sending ready");
3286
3430
  editorBridge.sendReady();
3287
3431
  }, []);
3432
+ useEffect(() => {
3433
+ return linkModifierInterceptor({ isEditMode: true });
3434
+ }, []);
3288
3435
  useEffect(() => {
3289
3436
  const handleDragStart = () => {};
3290
3437
  iframeMessageHandler.addEventListener("dragstart", handleDragStart);
@@ -3598,28 +3745,7 @@ const EmbedWrapper = (props) => {
3598
3745
  } catch {}
3599
3746
  };
3600
3747
  }, []);
3601
- useEffect(() => {
3602
- const globalSyncListener = (event) => {
3603
- const { global } = event.data.payload;
3604
- superblocksContext.updateContext(global);
3605
- };
3606
- iframeMessageHandler.addEventListener("sb-global-sync", globalSyncListener);
3607
- const navigateToListener = async (event) => {
3608
- const { route, routeParams, queryParams } = event.data.payload;
3609
- const eventSearch = new URLSearchParams(queryParams);
3610
- const nextSearch = new URLSearchParams(window.location.search);
3611
- for (const [key, value] of eventSearch.entries()) nextSearch.set(key, value);
3612
- await navigate({
3613
- pathname: generatePath(route, routeParams),
3614
- search: nextSearch.toString()
3615
- });
3616
- };
3617
- iframeMessageHandler.addEventListener("route-change", navigateToListener);
3618
- return () => {
3619
- iframeMessageHandler.removeEventListener("sb-global-sync", globalSyncListener);
3620
- iframeMessageHandler.removeEventListener("route-change", navigateToListener);
3621
- };
3622
- }, [navigate, superblocksContext]);
3748
+ useEmbedMessageListeners(navigate, superblocksContext);
3623
3749
  useEffect(() => {
3624
3750
  const messageListener = (event) => {
3625
3751
  if (event.data?.type === "parent-action-batch" && event.data.payload) event.data.payload.forEach((action$1) => {
@@ -4228,28 +4354,11 @@ const EmbedWrapper$1 = (props) => {
4228
4354
  }
4229
4355
  };
4230
4356
  iframeMessageHandler.addEventListener("sb-bootstrap-response", bootstrapResponseListener);
4231
- const globalSyncListener = (event) => {
4232
- const { global } = event.data.payload;
4233
- superblocksContext.updateContext(global);
4234
- };
4235
- iframeMessageHandler.addEventListener("sb-global-sync", globalSyncListener);
4236
- const navigateToListener = async (event) => {
4237
- const { route, routeParams, queryParams } = event.data.payload;
4238
- const eventSearch = new URLSearchParams(queryParams);
4239
- const nextSearch = new URLSearchParams(window.location.search);
4240
- for (const [key, value] of eventSearch.entries()) nextSearch.set(key, value);
4241
- await navigate({
4242
- pathname: generatePath(route, routeParams),
4243
- search: nextSearch.toString()
4244
- });
4245
- };
4246
- iframeMessageHandler.addEventListener("route-change", navigateToListener);
4247
4357
  return () => {
4248
4358
  iframeMessageHandler.removeEventListener("sb-bootstrap-response", bootstrapResponseListener);
4249
- iframeMessageHandler.removeEventListener("sb-global-sync", globalSyncListener);
4250
- iframeMessageHandler.removeEventListener("route-change", navigateToListener);
4251
4359
  };
4252
- }, [navigate, superblocksContext]);
4360
+ }, []);
4361
+ useEmbedMessageListeners(navigate, superblocksContext);
4253
4362
  useEffect(() => {
4254
4363
  const messageListener = (event) => {
4255
4364
  if (event.data?.type === "parent-action-batch" && event.data.payload) event.data.payload.forEach((action$1) => {
@@ -4263,6 +4372,9 @@ const EmbedWrapper$1 = (props) => {
4263
4372
  window.addEventListener("message", messageListener);
4264
4373
  return () => window.removeEventListener("message", messageListener);
4265
4374
  }, []);
4375
+ useEffect(() => {
4376
+ return linkModifierInterceptor({ isEmbedMode: new URLSearchParams(window.location.search).get("embed_mode") === "true" });
4377
+ }, []);
4266
4378
  if (!isLoaded && error) return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", { children: "There was an error logging in to Superblocks." }), /* @__PURE__ */ jsx("p", { children: error })] });
4267
4379
  if (!root_store_default.apis.isInitialized() && !isLoaded) {
4268
4380
  if (!isRetrievingToken.current && window.parent !== window.self) {
@@ -4384,7 +4496,7 @@ API executions and editor features will be unavailable.
4384
4496
  return;
4385
4497
  }
4386
4498
  }, 1e3);
4387
- }, 1e4);
4499
+ }, 2e4);
4388
4500
 
4389
4501
  //#endregion
4390
4502
  //#region src/lib/user-facing/styling/styles.ts
@@ -5521,11 +5633,171 @@ async function logoutIntegrations() {
5521
5633
  if (logoutResult?.errors && logoutResult.errors.length > 0) console.error("Logout returned with errors", logoutResult.errors);
5522
5634
  }
5523
5635
 
5636
+ //#endregion
5637
+ //#region src/lib/user-facing/embed.ts
5638
+ /**
5639
+ * Emit a custom event to the external embedder.
5640
+ * This is used when the library is embedded in an iframe
5641
+ * to communicate events back to the parent application.
5642
+ *
5643
+ * @param eventName - The name of the event to emit
5644
+ * @param payload - Optional payload data to send with the event
5645
+ *
5646
+ * @example
5647
+ * ```ts
5648
+ * import { Superblocks } from "@superblocksteam/library";
5649
+ *
5650
+ * // Emit a simple event
5651
+ * Superblocks.emitEvent("formSubmitted");
5652
+ *
5653
+ * // Emit an event with payload
5654
+ * Superblocks.emitEvent("userSelected", { userId: "123", name: "John" });
5655
+ * ```
5656
+ */
5657
+ function emitEvent(eventName, payload = {}) {
5658
+ embedStore.emitEvent(eventName, payload);
5659
+ }
5660
+ /**
5661
+ * Get the current embed properties passed from the external embedder.
5662
+ *
5663
+ * @returns The current embed properties object
5664
+ *
5665
+ * @example
5666
+ * ```ts
5667
+ * import { Superblocks } from "@superblocksteam/library";
5668
+ *
5669
+ * const props = Superblocks.getEmbedProperties();
5670
+ * console.log(props.userId);
5671
+ * ```
5672
+ */
5673
+ function getEmbedProperties() {
5674
+ return embedStore.properties;
5675
+ }
5676
+ /**
5677
+ * The Superblocks object provides utilities for interacting with
5678
+ * the embedding context when the library is embedded in an iframe.
5679
+ */
5680
+ const Superblocks = {
5681
+ emitEvent,
5682
+ getEmbedProperties
5683
+ };
5684
+
5685
+ //#endregion
5686
+ //#region src/lib/hooks/use-embed-properties.ts
5687
+ /**
5688
+ * React hook for accessing embed properties passed from the external embedder.
5689
+ * Automatically re-renders when properties change.
5690
+ *
5691
+ * @returns The current embed properties object (reactive)
5692
+ *
5693
+ * @example
5694
+ * ```tsx
5695
+ * import { useEmbedProperties } from "@superblocksteam/library";
5696
+ *
5697
+ * function MyComponent() {
5698
+ * const properties = useEmbedProperties();
5699
+ *
5700
+ * // Access properties passed from the embedder
5701
+ * const userId = properties.userId as string;
5702
+ * const theme = properties.theme as "light" | "dark";
5703
+ *
5704
+ * return <div>User: {userId}, Theme: {theme}</div>;
5705
+ * }
5706
+ * ```
5707
+ */
5708
+ function useEmbedProperties() {
5709
+ return useStandaloneObserverMemo(() => embedStore.properties, []);
5710
+ }
5711
+
5712
+ //#endregion
5713
+ //#region src/lib/hooks/use-embed-event.ts
5714
+ /**
5715
+ * React hook for listening to events triggered by the external embedder.
5716
+ * The handler will be called whenever the embedder triggers the specified event.
5717
+ *
5718
+ * @param eventName - The name of the event to listen for
5719
+ * @param handler - Callback function invoked when the event is triggered
5720
+ *
5721
+ * @example
5722
+ * ```tsx
5723
+ * import { useEmbedEvent } from "@superblocksteam/library";
5724
+ *
5725
+ * function MyComponent() {
5726
+ * useEmbedEvent("refreshData", (payload) => {
5727
+ * console.log("Embedder requested refresh:", payload);
5728
+ * // Refetch data, reset state, etc.
5729
+ * });
5730
+ *
5731
+ * useEmbedEvent("themeChange", (payload) => {
5732
+ * const { theme } = payload as { theme: "light" | "dark" };
5733
+ * setTheme(theme);
5734
+ * });
5735
+ *
5736
+ * return <div>Listening for events...</div>;
5737
+ * }
5738
+ * ```
5739
+ */
5740
+ function useEmbedEvent(eventName, handler) {
5741
+ const handlerRef = useRef(handler);
5742
+ handlerRef.current = handler;
5743
+ useEffect(() => {
5744
+ const listener = (event) => {
5745
+ const customEvent = event;
5746
+ handlerRef.current(customEvent.detail ?? {});
5747
+ };
5748
+ window.addEventListener(`superblocks:${eventName}`, listener);
5749
+ return () => {
5750
+ window.removeEventListener(`superblocks:${eventName}`, listener);
5751
+ };
5752
+ }, [eventName]);
5753
+ }
5754
+
5755
+ //#endregion
5756
+ //#region src/lib/hooks/use-emit-embed-event.ts
5757
+ /**
5758
+ * React hook that returns a function to emit events to the external embedder.
5759
+ * Use this to communicate actions or state changes back to the parent application.
5760
+ *
5761
+ * @returns A function to emit events to the embedder
5762
+ *
5763
+ * @example
5764
+ * ```tsx
5765
+ * import { useEmitEmbedEvent } from "@superblocksteam/library";
5766
+ *
5767
+ * function MyComponent() {
5768
+ * const emitEvent = useEmitEmbedEvent();
5769
+ *
5770
+ * const handleFormSubmit = (data: FormData) => {
5771
+ * emitEvent("formSubmitted", {
5772
+ * formId: "contact-form",
5773
+ * timestamp: Date.now(),
5774
+ * data,
5775
+ * });
5776
+ * };
5777
+ *
5778
+ * const handleRowClick = (row: { id: string; name: string }) => {
5779
+ * emitEvent("rowSelected", { rowId: row.id, rowName: row.name });
5780
+ * };
5781
+ *
5782
+ * return (
5783
+ * <button onClick={() => emitEvent("buttonClicked", { action: "save" })}>
5784
+ * Save
5785
+ * </button>
5786
+ * );
5787
+ * }
5788
+ * ```
5789
+ */
5790
+ function useEmitEmbedEvent() {
5791
+ return useCallback((eventName, payload = {}) => {
5792
+ embedStore.emitEvent(eventName, payload);
5793
+ }, []);
5794
+ }
5795
+
5524
5796
  //#endregion
5525
5797
  //#region src/lib/index.ts
5526
5798
  early_console_buffer_default.getInstance().patchEarly();
5527
5799
  registerHtmlElements();
5528
5800
 
5529
5801
  //#endregion
5530
- export { App, PageNotFound, Prop, Property, PropsCategory, RouteLoadError, Section, sb_provider_default as SuperblocksProvider, getAppMode, logoutIntegrations, registerComponent, tailwindStylesCategory, useApiStateful as useApi, useSuperblocksGroups, useSuperblocksProfiles, useSuperblocksUser };
5802
+ export { App, PageNotFound, Prop, Property, PropsCategory, RouteLoadError, Section, Superblocks, sb_provider_default as SuperblocksProvider, embedStore, getAppMode, logoutIntegrations, registerComponent, tailwindStylesCategory, useApiStateful as useApi, useEmbedEvent, useEmbedProperties, useEmitEmbedEvent, useSuperblocksGroups, useSuperblocksProfiles, useSuperblocksUser };
5531
5803
  //# sourceMappingURL=index.js.map