@select-org/select-post-builder 1.1.2 → 1.1.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.
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import React__default, { createContext, useContext, useCallback, useMemo, useLayoutEffect, useState, forwardRef, createElement, useEffect, useRef, Component, useImperativeHandle } from "react";
2
+ import React__default, { createContext, useContext, useLayoutEffect, useState, forwardRef, createElement, useEffect, useMemo, useRef, Component, useCallback, useImperativeHandle } from "react";
3
3
  import * as ReactDOM from "react-dom";
4
4
  import ReactDOM__default from "react-dom";
5
5
  import { jsx, Fragment as Fragment$1, jsxs } from "react/jsx-runtime";
@@ -2053,19 +2053,12 @@ validators$1.transitional = function transitional(validator2, version, message)
2053
2053
  }
2054
2054
  if (version && !deprecatedWarnings[opt]) {
2055
2055
  deprecatedWarnings[opt] = true;
2056
- console.warn(
2057
- formatMessage(
2058
- opt,
2059
- " has been deprecated since v" + version + " and will be removed in the near future"
2060
- )
2061
- );
2062
2056
  }
2063
2057
  return validator2 ? validator2(value, opt, opts) : true;
2064
2058
  };
2065
2059
  };
2066
2060
  validators$1.spelling = function spelling(correctSpelling) {
2067
2061
  return (value, opt) => {
2068
- console.warn(`${opt} is likely a misspelling of ${correctSpelling}`);
2069
2062
  return true;
2070
2063
  };
2071
2064
  };
@@ -3924,7 +3917,6 @@ const Toaster$1 = /* @__PURE__ */ React__default.forwardRef(function Toaster(pro
3924
3917
  setActualTheme("light");
3925
3918
  }
3926
3919
  } catch (e) {
3927
- console.error(e);
3928
3920
  }
3929
3921
  });
3930
3922
  }
@@ -4592,46 +4584,6 @@ const useAnalyticsLogEvent = () => {
4592
4584
  const { logEvent } = usePostBuilder();
4593
4585
  return logEvent;
4594
4586
  };
4595
- const PostBuilderProvider = ({
4596
- children,
4597
- apiBaseURL,
4598
- authToken,
4599
- toI18N,
4600
- i18nKeys,
4601
- logEvent
4602
- }) => {
4603
- const t = useCallback(
4604
- (key, fallback) => {
4605
- const message = toI18N(i18nKeys[key]);
4606
- if (message) return message;
4607
- return fallback || key;
4608
- },
4609
- [toI18N, i18nKeys]
4610
- );
4611
- const api = useMemo(() => {
4612
- const core = new CoreApi(apiBaseURL.core, authToken, toI18N);
4613
- const mfs = new MFSApi(apiBaseURL.mfs, authToken, toI18N);
4614
- const fileStore = new FilestoreApi(apiBaseURL.fileStore, authToken, toI18N);
4615
- core.initApi();
4616
- mfs.initApi();
4617
- fileStore.initApi();
4618
- return {
4619
- core,
4620
- mfs,
4621
- fileStore
4622
- };
4623
- }, [authToken, apiBaseURL, toI18N]);
4624
- const value = useMemo(() => {
4625
- return {
4626
- authToken,
4627
- t,
4628
- i18nKeys,
4629
- api,
4630
- logEvent
4631
- };
4632
- }, [authToken, t, i18nKeys, api, logEvent]);
4633
- return /* @__PURE__ */ jsx(PostBuilderContext.Provider, { value, children });
4634
- };
4635
4587
  function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
4636
4588
  return function handleEvent(event) {
4637
4589
  originalEventHandler?.(event);
@@ -4975,9 +4927,6 @@ function useControllableState({
4975
4927
  if (wasControlled !== isControlled) {
4976
4928
  const from = wasControlled ? "controlled" : "uncontrolled";
4977
4929
  const to = isControlled ? "controlled" : "uncontrolled";
4978
- console.warn(
4979
- `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`
4980
- );
4981
4930
  }
4982
4931
  isControlledRef.current = isControlled;
4983
4932
  }, [isControlled, caller]);
@@ -8582,7 +8531,7 @@ const EditorTypeTabs = ({ editorTab, onSwitchEditorTab }) => {
8582
8531
  const { trackTabSwitch } = usePostBuilderAnalytics();
8583
8532
  const handleSwitchTab = (newTab) => {
8584
8533
  const oldTab = editorTab;
8585
- trackTabSwitch(oldTab, newTab);
8534
+ trackTabSwitch({ oldTab, newTab });
8586
8535
  onSwitchEditorTab(newTab);
8587
8536
  };
8588
8537
  return /* @__PURE__ */ jsx(
@@ -11304,7 +11253,6 @@ var correctTargets = function(parent2, targets) {
11304
11253
  if (correctedTarget && parent2.contains(correctedTarget)) {
11305
11254
  return correctedTarget;
11306
11255
  }
11307
- console.error("aria-hidden", target, "in not contained inside", parent2, ". Doing nothing");
11308
11256
  return null;
11309
11257
  }).filter(function(x2) {
11310
11258
  return Boolean(x2);
@@ -11353,7 +11301,6 @@ var applyAttributeToOthers = function(originalTarget, parentNode, markerName, co
11353
11301
  node.setAttribute(controlAttribute, "true");
11354
11302
  }
11355
11303
  } catch (e) {
11356
- console.error("aria-hidden: cannot operate on ", node, e);
11357
11304
  }
11358
11305
  }
11359
11306
  });
@@ -13991,15 +13938,11 @@ function requireUseSyncExternalStoreShim_development() {
13991
13938
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
13992
13939
  }
13993
13940
  function useSyncExternalStore$2(subscribe2, getSnapshot) {
13994
- didWarnOld18Alpha || void 0 === React2.startTransition || (didWarnOld18Alpha = true, console.error(
13995
- "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
13996
- ));
13941
+ didWarnOld18Alpha || void 0 === React2.startTransition || (didWarnOld18Alpha = true, void 0);
13997
13942
  var value = getSnapshot();
13998
13943
  if (!didWarnUncachedGetSnapshot) {
13999
13944
  var cachedValue = getSnapshot();
14000
- objectIs(value, cachedValue) || (console.error(
14001
- "The result of getSnapshot should be cached to avoid an infinite loop"
14002
- ), didWarnUncachedGetSnapshot = true);
13945
+ objectIs(value, cachedValue) || (void 0, didWarnUncachedGetSnapshot = true);
14003
13946
  }
14004
13947
  cachedValue = useState2({
14005
13948
  inst: { value, getSnapshot }
@@ -14231,9 +14174,6 @@ const GroupSelector = ({ store }) => {
14231
14174
  setGroups(response.entries ?? []);
14232
14175
  }
14233
14176
  } catch (error) {
14234
- if (!cancelled) {
14235
- console.error("Failed to fetch groups:", error);
14236
- }
14237
14177
  } finally {
14238
14178
  if (!cancelled) {
14239
14179
  setIsLoading(false);
@@ -14882,7 +14822,7 @@ const ToolbarButton = forwardRef(
14882
14822
  const { trackFeature } = usePostBuilderAnalytics();
14883
14823
  const handleClick = (e) => {
14884
14824
  onClick?.(e);
14885
- if (id) trackFeature(id);
14825
+ if (id) trackFeature({ featureName: id });
14886
14826
  if (!editor) return;
14887
14827
  requestAnimationFrame(editor?.chain()?.focus);
14888
14828
  };
@@ -15186,7 +15126,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15186
15126
  React.useEffect(() => {
15187
15127
  if (titleId) {
15188
15128
  const hasTitle = document.getElementById(titleId);
15189
- if (!hasTitle) console.error(MESSAGE);
15129
+ if (!hasTitle) ;
15190
15130
  }
15191
15131
  }, [MESSAGE, titleId]);
15192
15132
  return null;
@@ -15199,7 +15139,7 @@ var DescriptionWarning = ({ contentRef, descriptionId }) => {
15199
15139
  const describedById = contentRef.current?.getAttribute("aria-describedby");
15200
15140
  if (descriptionId && describedById) {
15201
15141
  const hasDescription = document.getElementById(descriptionId);
15202
- if (!hasDescription) console.warn(MESSAGE);
15142
+ if (!hasDescription) ;
15203
15143
  }
15204
15144
  }, [MESSAGE, contentRef, descriptionId]);
15205
15145
  return null;
@@ -15585,7 +15525,6 @@ const InputGroupText = forwardRef(
15585
15525
  InputGroupText.displayName = "InputGroupText";
15586
15526
  const InputGroupInput = forwardRef(
15587
15527
  ({ className, ref: legacyRef, ...props }, ref) => {
15588
- console.log({ legacyRef });
15589
15528
  return /* @__PURE__ */ jsx(
15590
15529
  Input,
15591
15530
  {
@@ -16206,7 +16145,6 @@ const resolveUrlType = async (url) => {
16206
16145
  if (mime?.startsWith("video/")) return { type: MediaNodeTypes.Video, src: url };
16207
16146
  if (mime?.startsWith("audio/")) return { type: MediaNodeTypes.Audio, src: url };
16208
16147
  } catch (error) {
16209
- console.warn("HEAD request failed, falling back to mime detection:", error);
16210
16148
  }
16211
16149
  const ext = url.split(".").pop()?.toLowerCase();
16212
16150
  if (ext) {
@@ -16345,11 +16283,9 @@ const LinkDecoratorModal = ({
16345
16283
  setIsValid(isValid2);
16346
16284
  };
16347
16285
  const handleInsertLink = (link2, text22, uid2) => {
16348
- console.log("HANDLE INSERT LINK::", { link: link2, text: text22 });
16349
16286
  setIsLoading(true);
16350
16287
  let metadata;
16351
- core?.resolveUrl(link2)?.then((res) => metadata = res)?.catch((err) => console.log(err))?.finally(() => {
16352
- console.log({ metadata });
16288
+ core?.resolveUrl(link2)?.then((res) => metadata = res)?.catch((err) => void 0)?.finally(() => {
16353
16289
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
16354
16290
  setIsLoading(false);
16355
16291
  onInsertLink(link2, text22, uid2, previewPayload);
@@ -16361,12 +16297,10 @@ const LinkDecoratorModal = ({
16361
16297
  e.preventDefault();
16362
16298
  const isTextInput = textInputRef.current === e.target;
16363
16299
  if (isTextInput || hideTextInput) return handleInsertLink(link, text2, uid ?? void 0);
16364
- console.log("Enter", isTextInput);
16365
16300
  textInputRef?.current?.focus();
16366
16301
  }
16367
16302
  };
16368
16303
  useEffect(() => {
16369
- console.log({ defaultValues });
16370
16304
  if (!defaultValues?.link) return;
16371
16305
  const isValid2 = isValidUrl(defaultValues?.link);
16372
16306
  setIsValid(isValid2);
@@ -16375,7 +16309,6 @@ const LinkDecoratorModal = ({
16375
16309
  setLink(defaultValues?.link ?? "");
16376
16310
  setText(defaultValues?.text || "");
16377
16311
  }, [defaultValues]);
16378
- console.log("TEXT INSIDE LINK DECORATOR::", { isValid, text: text2 });
16379
16312
  return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: handleOpenChange, children: [
16380
16313
  children ? /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children }) : null,
16381
16314
  /* @__PURE__ */ jsxs(DialogContent, { className: "-translate-1/2", children: [
@@ -16560,10 +16493,8 @@ function parseThreshold(scrollThreshold) {
16560
16493
  value: parseFloat(scrollThreshold)
16561
16494
  };
16562
16495
  }
16563
- console.warn('scrollThreshold format is invalid. Valid formats: "120px", "50%"...');
16564
16496
  return defaultThreshold;
16565
16497
  }
16566
- console.warn("scrollThreshold should be string or number");
16567
16498
  return defaultThreshold;
16568
16499
  }
16569
16500
  var InfiniteScroll = (
@@ -16585,7 +16516,6 @@ var InfiniteScroll = (
16585
16516
  return document.getElementById(_this.props.scrollableTarget);
16586
16517
  }
16587
16518
  if (_this.props.scrollableTarget === null) {
16588
- console.warn("You are trying to pass scrollableTarget but it is null. This might\n happen because the element may not have been added to DOM yet.\n See https://github.com/ankeetmaini/react-infinite-scroll-component/issues/59 for more info.\n ");
16589
16519
  }
16590
16520
  return null;
16591
16521
  };
@@ -16830,7 +16760,6 @@ function useMediaSearch(type) {
16830
16760
  setItems((prev) => reset2 ? data : [...prev, ...data]);
16831
16761
  }
16832
16762
  } catch (error) {
16833
- console.error("Error fetching images:", error);
16834
16763
  pagination.setHasMore(false);
16835
16764
  } finally {
16836
16765
  pagination.setLoading(false);
@@ -16849,7 +16778,6 @@ function useMediaSearch(type) {
16849
16778
  setItems((prev) => reset2 ? data : [...prev, ...data]);
16850
16779
  }
16851
16780
  } catch (error) {
16852
- console.error("Error fetching gifs:", error);
16853
16781
  pagination.setHasMore(false);
16854
16782
  } finally {
16855
16783
  pagination.setLoading(false);
@@ -18424,8 +18352,8 @@ function ImageSearchModal({
18424
18352
  setSearchQuery("");
18425
18353
  return;
18426
18354
  }
18427
- gifSearch.fetch(withInitialQuery).catch((err) => console.log(err));
18428
- imageSearch.fetch(withInitialQuery).catch((err) => console.log(err));
18355
+ gifSearch.fetch(withInitialQuery).catch((err) => void 0);
18356
+ imageSearch.fetch(withInitialQuery).catch((err) => void 0);
18429
18357
  };
18430
18358
  const debouncedSearch = useMemo(
18431
18359
  () => debounce$2(async (query) => {
@@ -18443,7 +18371,7 @@ function ImageSearchModal({
18443
18371
  const handleSearch = useCallback(
18444
18372
  (query) => {
18445
18373
  setSearchQuery(query);
18446
- debouncedSearch(query)?.catch((err) => console.log(err));
18374
+ debouncedSearch(query)?.catch((err) => void 0);
18447
18375
  },
18448
18376
  [debouncedSearch]
18449
18377
  );
@@ -20397,7 +20325,9 @@ const Toolbar = ({
20397
20325
  };
20398
20326
  const handleImageClick = (imageUrl, searchFrom) => {
20399
20327
  if (searchFrom) {
20400
- trackFeature(searchFrom === ImageSearchFrom.Gif ? "gif_search" : "image_search");
20328
+ trackFeature({
20329
+ featureName: searchFrom === ImageSearchFrom.Gif ? "gif_search" : "image_search"
20330
+ });
20401
20331
  }
20402
20332
  editor?.commands.insertMediaWithUpload({
20403
20333
  source: imageUrl,
@@ -20810,6 +20740,79 @@ const Toolbar = ({
20810
20740
  ] });
20811
20741
  };
20812
20742
  const VerticalSeparator = () => /* @__PURE__ */ jsx("div", { className: "h-3 w-px bg-border" });
20743
+ var PostBuilderEvents = /* @__PURE__ */ ((PostBuilderEvents2) => {
20744
+ PostBuilderEvents2["POST_PUBLISH_ATTEMPTED"] = "select:post_publish_attempted";
20745
+ PostBuilderEvents2["POST_PUBLISH_SUCCESSFUL"] = "select:post_publish_success";
20746
+ PostBuilderEvents2["POST_PUBLISH_FAILED"] = "select:post_publish_failed";
20747
+ return PostBuilderEvents2;
20748
+ })(PostBuilderEvents || {});
20749
+ const useHostAnalyticsBridge = () => {
20750
+ const analytics = usePostBuilderAnalytics();
20751
+ const sessionIdRef = useRef(null);
20752
+ const processedRequestIds = useRef(/* @__PURE__ */ new Set());
20753
+ useEffect(() => {
20754
+ const onPublishSuccess = (e) => {
20755
+ const { postId, postType, groupId, failureReason } = e.detail;
20756
+ if (!postId || processedRequestIds.current.has(postId)) return;
20757
+ processedRequestIds.current.add(postId);
20758
+ analytics.trackPublish({
20759
+ sessionId: sessionIdRef.current ?? analytics.currentSessionId,
20760
+ status: "success",
20761
+ postId,
20762
+ groupId,
20763
+ postType,
20764
+ failureReason
20765
+ });
20766
+ sessionIdRef.current = null;
20767
+ };
20768
+ const onPublishFailed = (e) => {
20769
+ const { postId, postType, groupId, failureReason } = e.detail;
20770
+ if (!postId || processedRequestIds.current.has(postId)) return;
20771
+ processedRequestIds.current.add(postId);
20772
+ analytics.trackPublish({
20773
+ sessionId: sessionIdRef.current ?? analytics.currentSessionId,
20774
+ status: "failed",
20775
+ postId,
20776
+ groupId,
20777
+ postType,
20778
+ failureReason
20779
+ });
20780
+ sessionIdRef.current = null;
20781
+ };
20782
+ const lockSession = () => {
20783
+ if (!sessionIdRef.current) {
20784
+ sessionIdRef.current = analytics.currentSessionId;
20785
+ }
20786
+ };
20787
+ window.addEventListener(
20788
+ PostBuilderEvents.POST_PUBLISH_SUCCESSFUL,
20789
+ onPublishSuccess
20790
+ );
20791
+ window.addEventListener(
20792
+ PostBuilderEvents.POST_PUBLISH_FAILED,
20793
+ onPublishFailed
20794
+ );
20795
+ const handlePublishAttempt = () => lockSession();
20796
+ window.addEventListener(
20797
+ PostBuilderEvents.POST_PUBLISH_ATTEMPTED,
20798
+ handlePublishAttempt
20799
+ );
20800
+ return () => {
20801
+ window.removeEventListener(
20802
+ PostBuilderEvents.POST_PUBLISH_SUCCESSFUL,
20803
+ onPublishSuccess
20804
+ );
20805
+ window.removeEventListener(
20806
+ PostBuilderEvents.POST_PUBLISH_FAILED,
20807
+ onPublishFailed
20808
+ );
20809
+ window.removeEventListener(
20810
+ PostBuilderEvents.POST_PUBLISH_ATTEMPTED,
20811
+ handlePublishAttempt
20812
+ );
20813
+ };
20814
+ }, [analytics]);
20815
+ };
20813
20816
  const usePersistence = () => {
20814
20817
  const saveCurrentTabContent = (editorType, editor) => {
20815
20818
  if (typeof window === "undefined" || typeof localStorage === "undefined" || !editor || editor.isEmpty)
@@ -21066,11 +21069,9 @@ var Progress$1 = React.forwardRef(
21066
21069
  ...progressProps
21067
21070
  } = props;
21068
21071
  if ((maxProp || maxProp === 0) && !isValidMaxNumber(maxProp)) {
21069
- console.error(getInvalidMaxError(`${maxProp}`, "Progress"));
21070
21072
  }
21071
21073
  const max2 = isValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;
21072
21074
  if (valueProp !== null && !isValidValueNumber(valueProp, max2)) {
21073
- console.error(getInvalidValueError(`${valueProp}`, "Progress"));
21074
21075
  }
21075
21076
  const value = isValidValueNumber(valueProp, max2) ? valueProp : null;
21076
21077
  const valueLabel = isNumber(value) ? getValueLabel(value, max2) : void 0;
@@ -21390,13 +21391,7 @@ const createUpdateMarkByUidCommand = (markName) => {
21390
21391
  state,
21391
21392
  dispatch
21392
21393
  }) => {
21393
- console.log("=== UPDATE MARK COMMAND START ===");
21394
- console.log("markName:", markName);
21395
- console.log("uid:", uid);
21396
- console.log("attrs:", attrs);
21397
- console.log("state.doc:", state.doc.toJSON());
21398
21394
  if (!dispatch) {
21399
- console.log("No dispatch, returning false");
21400
21395
  return false;
21401
21396
  }
21402
21397
  const { doc, schema } = state;
@@ -21406,13 +21401,6 @@ const createUpdateMarkByUidCommand = (markName) => {
21406
21401
  doc.descendants((node, pos) => {
21407
21402
  if (node.isText && node.marks?.length) {
21408
21403
  node.marks.forEach((mark) => {
21409
- console.log("Checking mark:", {
21410
- markType: mark.type.name,
21411
- markUid: mark.attrs.uid,
21412
- targetMarkName: markName,
21413
- targetUid: uid,
21414
- matches: mark.type.name === markName && mark.attrs.uid === uid
21415
- });
21416
21404
  if (mark.type.name === markName && mark.attrs.uid === uid) {
21417
21405
  positions.push({
21418
21406
  from: pos,
@@ -21420,33 +21408,21 @@ const createUpdateMarkByUidCommand = (markName) => {
21420
21408
  mark
21421
21409
  });
21422
21410
  found2 = true;
21423
- console.log("Found matching mark at:", { from: pos, to: pos + node.nodeSize });
21424
21411
  }
21425
21412
  });
21426
21413
  }
21427
21414
  });
21428
- console.log("Total positions found:", positions.length);
21429
- console.log("Positions:", positions);
21430
21415
  if (found2) {
21431
21416
  positions.forEach(({ from, to, mark }) => {
21432
21417
  const newAttrs = { ...mark.attrs, ...attrs };
21433
21418
  const markType = schema.marks[markName];
21434
- console.log("Applying update:", { from, to, oldAttrs: mark.attrs, newAttrs });
21435
21419
  if (markType) {
21436
- console.log("Before removeMark - tr.doc:", tr.doc.toJSON());
21437
21420
  tr = tr.removeMark(from, to, markType);
21438
- console.log("After removeMark - tr.doc:", tr.doc.toJSON());
21439
21421
  tr = tr.addMark(from, to, markType.create(newAttrs));
21440
- console.log("After addMark - tr.doc:", tr.doc.toJSON());
21441
21422
  }
21442
21423
  });
21443
- console.log("About to dispatch transaction");
21444
- console.log("Final tr.doc:", tr.doc.toJSON());
21445
- console.log("Original state.doc:", state.doc.toJSON());
21446
21424
  dispatch(tr);
21447
- console.log("Transaction dispatched successfully");
21448
21425
  }
21449
- console.log("=== UPDATE MARK COMMAND END ===");
21450
21426
  return found2;
21451
21427
  };
21452
21428
  };
@@ -22464,7 +22440,6 @@ let warnedAboutTextSelection = false;
22464
22440
  function checkTextSelection($pos) {
22465
22441
  if (!warnedAboutTextSelection && !$pos.parent.inlineContent) {
22466
22442
  warnedAboutTextSelection = true;
22467
- console["warn"]("TextSelection endpoint not pointing into a node with inline content (" + $pos.parent.type.name + ")");
22468
22443
  }
22469
22444
  }
22470
22445
  class TextSelection extends Selection {
@@ -23189,7 +23164,6 @@ const PollCreator = ({ choices, onChange }) => {
23189
23164
  const result = await fileStore.uploadImage(file);
23190
23165
  return createPollMediaOption(result, startIndex + index2);
23191
23166
  } catch (error) {
23192
- console.error("Upload failed for", file.name, error);
23193
23167
  return null;
23194
23168
  }
23195
23169
  });
@@ -23209,7 +23183,6 @@ const PollCreator = ({ choices, onChange }) => {
23209
23183
  return final;
23210
23184
  });
23211
23185
  } catch (error) {
23212
- console.error("Unexpected error during file upload:", error);
23213
23186
  setInternalChoices((current) => {
23214
23187
  const withoutPlaceholders = current.filter((c) => !isPlaceholder(c));
23215
23188
  setTimeout(() => {
@@ -23242,7 +23215,6 @@ const PollCreator = ({ choices, onChange }) => {
23242
23215
  return updated;
23243
23216
  });
23244
23217
  } catch (error) {
23245
- console.error("URL upload failed:", error);
23246
23218
  setInternalChoices((current) => {
23247
23219
  const withoutPlaceholder = current.filter((c) => !isPlaceholder(c));
23248
23220
  setTimeout(() => {
@@ -23783,7 +23755,6 @@ const LinkMarkView = ({ mark, editor }) => {
23783
23755
  };
23784
23756
  const handleUpdateLink = (link, text2, uid, previewPayload) => {
23785
23757
  if (!editor.view) return;
23786
- console.log("UPDATE LINK IN VIEW::", { text: text2 });
23787
23758
  const newText = mark?.attrs?.isLinkMode ? link : text2 || link;
23788
23759
  if (uid) {
23789
23760
  editor.commands.updateLink(uid, { href: link, text: newText, previewPayload });
@@ -23843,25 +23814,66 @@ const LinkMarkView = ({ mark, editor }) => {
23843
23814
  )
23844
23815
  ] });
23845
23816
  };
23817
+ function isValidUrlFormat(text2) {
23818
+ return isValidUrl(normalizeUrl(text2.trim()));
23819
+ }
23846
23820
  function doesPreviewExist(editor, uid) {
23847
- let exists = false;
23848
- editor.state.doc.descendants((node) => {
23849
- if (node.type.name === "linkPreview" && node.attrs.uid === uid) {
23850
- exists = true;
23851
- return false;
23852
- }
23853
- });
23854
- return exists;
23821
+ if (!editor || !uid) {
23822
+ return false;
23823
+ }
23824
+ try {
23825
+ let exists = false;
23826
+ editor.state.doc.descendants((node) => {
23827
+ if (node && node.type && node.type.name === "linkPreview" && node.attrs?.uid === uid) {
23828
+ exists = true;
23829
+ return false;
23830
+ }
23831
+ });
23832
+ return exists;
23833
+ } catch (err) {
23834
+ return false;
23835
+ }
23855
23836
  }
23856
23837
  function findExistingPreview(editor) {
23857
- let result = null;
23858
- editor.state.doc.descendants((node, pos) => {
23859
- if (node.type.name === "linkPreview") {
23860
- result = { node, pos };
23861
- return false;
23838
+ if (!editor) {
23839
+ return null;
23840
+ }
23841
+ try {
23842
+ let result = null;
23843
+ editor.state.doc.descendants((node, pos) => {
23844
+ if (node && node.type && node.type.name === "linkPreview") {
23845
+ result = { node, pos };
23846
+ return false;
23847
+ }
23848
+ });
23849
+ return result;
23850
+ } catch (err) {
23851
+ return null;
23852
+ }
23853
+ }
23854
+ function removePreviewByUid(editor, uid) {
23855
+ if (!editor || !uid) {
23856
+ return;
23857
+ }
23858
+ try {
23859
+ let previewPos = null;
23860
+ let previewSize = 0;
23861
+ editor.state.doc.descendants((node, pos) => {
23862
+ if (node && node.type && node.type.name === "linkPreview" && node.attrs?.uid === uid) {
23863
+ previewPos = pos;
23864
+ previewSize = node.nodeSize;
23865
+ return false;
23866
+ }
23867
+ });
23868
+ if (previewPos !== null && previewSize > 0) {
23869
+ const tr = editor.state.tr;
23870
+ if (tr) {
23871
+ tr.delete(previewPos, Number(previewPos) + previewSize);
23872
+ editor.view.dispatch(tr);
23873
+ }
23862
23874
  }
23863
- });
23864
- return result;
23875
+ } catch (err) {
23876
+ }
23865
23877
  }
23866
23878
  function extractBestImage(metadata) {
23867
23879
  return metadata?.image?.high_resolution ?? metadata?.image?.url ?? metadata?.image?.thumbnail ?? metadata?.image?.placeholder ?? null;
@@ -23886,6 +23898,76 @@ function collectAllLinkMarks(state, linkMark) {
23886
23898
  });
23887
23899
  return links;
23888
23900
  }
23901
+ function syncLinkHrefWithText(newState, linkMark, editor, singlePreviewMode, pluginState) {
23902
+ if (!newState || !linkMark || !editor || !pluginState) {
23903
+ return null;
23904
+ }
23905
+ let tr = null;
23906
+ let hasChanges = false;
23907
+ try {
23908
+ newState.doc.descendants((node, pos) => {
23909
+ if (!node || !node.isText || !node.marks?.length) return;
23910
+ node.marks.forEach((mark) => {
23911
+ if (!mark || !mark.type || !mark.attrs) return;
23912
+ if (mark.type === linkMark && mark.attrs?.uid) {
23913
+ const currentText = node.text || "";
23914
+ const currentHref = mark.attrs.href || "";
23915
+ if (currentText !== currentHref) {
23916
+ const isValidUrl2 = isValidUrlFormat(currentText);
23917
+ if (!tr) {
23918
+ tr = newState.tr;
23919
+ }
23920
+ if (!tr) {
23921
+ return;
23922
+ }
23923
+ if (isValidUrl2) {
23924
+ const newMark = linkMark.create({
23925
+ ...mark.attrs,
23926
+ href: normalizeUrl(currentText)
23927
+ });
23928
+ if (!newMark) {
23929
+ return;
23930
+ }
23931
+ tr = tr.removeMark(pos, pos + node.nodeSize, linkMark);
23932
+ tr = tr.addMark(pos, pos + node.nodeSize, newMark);
23933
+ hasChanges = true;
23934
+ pluginState.processedLinks.delete(mark.attrs.uid);
23935
+ if (singlePreviewMode) {
23936
+ queueMicrotask(() => {
23937
+ try {
23938
+ const existingPreview = findExistingPreview(editor);
23939
+ if (existingPreview && mark.attrs?.uid) {
23940
+ }
23941
+ } catch (err) {
23942
+ }
23943
+ });
23944
+ } else {
23945
+ }
23946
+ } else {
23947
+ tr = tr.removeMark(pos, pos + node.nodeSize, linkMark);
23948
+ hasChanges = true;
23949
+ queueMicrotask(() => {
23950
+ try {
23951
+ if (mark.attrs?.uid) {
23952
+ removePreviewByUid(editor, mark.attrs.uid);
23953
+ }
23954
+ } catch (err) {
23955
+ }
23956
+ });
23957
+ if (mark.attrs?.uid) {
23958
+ pluginState.processedLinks.delete(mark.attrs.uid);
23959
+ pluginState.resolvingLinks.delete(mark.attrs.uid);
23960
+ }
23961
+ }
23962
+ }
23963
+ }
23964
+ });
23965
+ });
23966
+ } catch (err) {
23967
+ return null;
23968
+ }
23969
+ return hasChanges ? tr : null;
23970
+ }
23889
23971
  function assignUidsToLinks(newState, linkMark) {
23890
23972
  const newUids = /* @__PURE__ */ new Map();
23891
23973
  let tr = null;
@@ -23895,11 +23977,6 @@ function assignUidsToLinks(newState, linkMark) {
23895
23977
  node.marks.forEach((mark) => {
23896
23978
  if (mark.type === linkMark && mark.attrs?.href && !mark.attrs.uid) {
23897
23979
  const newUid = v4();
23898
- console.log("🔧 Assigning UID to autolinked URL:", {
23899
- href: mark.attrs.href,
23900
- uid: newUid,
23901
- pos
23902
- });
23903
23980
  const newMark = linkMark.create({
23904
23981
  ...mark.attrs,
23905
23982
  uid: newUid
@@ -23926,25 +24003,14 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23926
24003
  const { api, editor } = options;
23927
24004
  const mediaGroup = findByType(editor?.getJSON(), "mediaGroup");
23928
24005
  if (!api) {
23929
- console.warn("⚠️ No API provided to resolve link");
23930
24006
  return;
23931
24007
  }
23932
24008
  if (singlePreviewMode && mediaGroup.length >= 1) return;
23933
24009
  pluginState.resolvingLinks.add(link.uid);
23934
- console.log("🌐 Resolving link metadata:", {
23935
- uid: link.uid,
23936
- href: link.href,
23937
- singlePreviewMode
23938
- });
23939
24010
  api.resolveUrl(normalizeUrl(link.href)).then((metadata) => {
23940
24011
  pluginState.resolvingLinks.delete(link.uid);
23941
24012
  pluginState.processedLinks.add(link.uid);
23942
- console.log("✅ Link metadata resolved:", {
23943
- uid: link.uid,
23944
- metadata
23945
- });
23946
24013
  if (!metadata) {
23947
- console.warn("⚠️ No metadata returned for:", link.href);
23948
24014
  return;
23949
24015
  }
23950
24016
  const previewData = {
@@ -23959,13 +24025,11 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23959
24025
  if (singlePreviewMode) {
23960
24026
  const existingPreview = findExistingPreview(editor);
23961
24027
  if (existingPreview) {
23962
- console.log("🔄 Updating existing preview in single mode");
23963
24028
  const { pos } = existingPreview;
23964
24029
  const tr = editor.state.tr;
23965
24030
  tr.setNodeMarkup(pos, void 0, previewData);
23966
24031
  editor.view.dispatch(tr);
23967
24032
  } else {
23968
- console.log("➕ Creating first preview in single mode");
23969
24033
  editor.commands.setLinkPreview(previewData);
23970
24034
  }
23971
24035
  editor.commands.updateLinkByUid(link.uid, {
@@ -23973,16 +24037,12 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23973
24037
  });
23974
24038
  } else {
23975
24039
  if (!doesPreviewExist(editor, link.uid)) {
23976
- console.log("➕ Creating new preview in multi mode");
23977
24040
  editor.chain().updateLinkByUid(link.uid, {
23978
24041
  previewPayload: convertLinkMetaToPreviewItem(metadata)
23979
24042
  }).setLinkPreview(previewData).run();
23980
- } else {
23981
- console.log("⏭️ Preview already exists, skipping");
23982
24043
  }
23983
24044
  }
23984
24045
  }).catch((err) => {
23985
- console.error("❌ Failed to resolve link:", err);
23986
24046
  pluginState.resolvingLinks.delete(link.uid);
23987
24047
  });
23988
24048
  }
@@ -23992,10 +24052,6 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
23992
24052
  key: pluginKey,
23993
24053
  state: {
23994
24054
  init() {
23995
- console.log("🔌 LinkAutoResolve plugin initialized", {
23996
- singlePreviewMode,
23997
- hasApi: !!options.api
23998
- });
23999
24055
  return {
24000
24056
  resolvingLinks: /* @__PURE__ */ new Set(),
24001
24057
  processedLinks: /* @__PURE__ */ new Set()
@@ -24025,27 +24081,22 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24025
24081
  appendTransaction: (transactions, oldState, newState) => {
24026
24082
  const linkMark = newState.schema.marks["customLink"];
24027
24083
  if (!linkMark) {
24028
- console.warn("⚠️ customLink mark not found in schema");
24029
24084
  return null;
24030
24085
  }
24031
24086
  if (!transactions.some((tr) => tr.docChanged)) {
24032
24087
  return null;
24033
24088
  }
24034
- console.log("📝 Document changed, checking for new links...");
24035
24089
  const pluginState = pluginKey.getState(newState);
24090
+ if (!pluginState) {
24091
+ return null;
24092
+ }
24093
+ const syncTr = singlePreviewMode ? syncLinkHrefWithText(newState, linkMark, options.editor, singlePreviewMode, pluginState) : null;
24036
24094
  const oldLinks = collectAllLinkMarks(oldState, linkMark);
24037
24095
  const newLinks = collectAllLinkMarks(newState, linkMark);
24038
- console.log("📊 Link count:", {
24039
- old: oldLinks.size,
24040
- new: newLinks.size,
24041
- processed: pluginState.processedLinks.size,
24042
- resolving: pluginState.resolvingLinks.size
24043
- });
24044
24096
  const { tr: uidTr, newUids } = assignUidsToLinks(newState, linkMark);
24045
24097
  const linksToResolve = [];
24046
24098
  newUids.forEach((linkData) => {
24047
24099
  if (!pluginState.processedLinks.has(linkData.uid) && !pluginState.resolvingLinks.has(linkData.uid)) {
24048
- console.log("🆕 New autolinked URL detected:", linkData);
24049
24100
  linksToResolve.push(linkData);
24050
24101
  }
24051
24102
  });
@@ -24058,21 +24109,33 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24058
24109
  return;
24059
24110
  }
24060
24111
  if (!oldLinks.has(uid)) {
24061
- console.log("🆕 New link detected (with UID):", linkData);
24062
24112
  linksToResolve.push(linkData);
24063
24113
  }
24064
24114
  });
24065
24115
  if (linksToResolve.length > 0) {
24066
- console.log("🚀 Processing", linksToResolve.length, "new link(s)");
24067
24116
  queueMicrotask(() => {
24068
24117
  linksToResolve.forEach((link) => {
24069
24118
  resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginState);
24070
24119
  });
24071
24120
  });
24072
- } else {
24073
- console.log("✓ No new links to process");
24074
24121
  }
24075
- return uidTr;
24122
+ if (syncTr && uidTr) {
24123
+ try {
24124
+ uidTr.steps.forEach((step, i) => {
24125
+ if (step && syncTr) {
24126
+ syncTr.step(step);
24127
+ const map = uidTr.mapping.maps[i];
24128
+ if (map) {
24129
+ syncTr.mapping.appendMap(map);
24130
+ }
24131
+ }
24132
+ });
24133
+ return syncTr;
24134
+ } catch (err) {
24135
+ return syncTr;
24136
+ }
24137
+ }
24138
+ return syncTr ?? uidTr ?? null;
24076
24139
  }
24077
24140
  });
24078
24141
  }
@@ -24168,7 +24231,6 @@ const CustomLink = Link$1.extend({
24168
24231
  this?.options?.api?.resolveUrl(normalizeUrl(href))?.then((metadata) => {
24169
24232
  if (metadata) {
24170
24233
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
24171
- console.log({ href, text: text2 });
24172
24234
  editor?.chain()?.updateLinkByUid(uid, { href, text: text2, previewPayload })?.updateLinkPreviewByUid(uid, {
24173
24235
  // Now using correct UID
24174
24236
  loading: false,
@@ -24227,7 +24289,6 @@ const CustomLink = Link$1.extend({
24227
24289
  if (attrs.href) {
24228
24290
  queueMicrotask(() => {
24229
24291
  this.options.api?.resolveUrl(normalizeUrl(attrs.href))?.then((metadata) => {
24230
- console.log({ metadata });
24231
24292
  if (metadata) {
24232
24293
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
24233
24294
  let linkPreviewExists = false;
@@ -24256,7 +24317,6 @@ const CustomLink = Link$1.extend({
24256
24317
  editor.commands.deleteLinkPreviewByUid(uid);
24257
24318
  }
24258
24319
  }).catch((err) => {
24259
- console.log("LINK UPDATE ERR::", { err });
24260
24320
  editor.commands.deleteLinkPreviewByUid(uid);
24261
24321
  });
24262
24322
  });
@@ -24336,7 +24396,6 @@ const IframeView = ({
24336
24396
  setPreviewData(previewPayload);
24337
24397
  updateAttributes({ previewPayload });
24338
24398
  }).catch((error) => {
24339
- console.error("Failed to fetch preview:", error);
24340
24399
  }).finally(() => {
24341
24400
  });
24342
24401
  }
@@ -24581,7 +24640,6 @@ const _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTyp
24581
24640
  }
24582
24641
  });
24583
24642
  } catch (_) {
24584
- console.warn("TrustedTypes policy " + policyName + " could not be created.");
24585
24643
  return null;
24586
24644
  }
24587
24645
  };
@@ -25418,7 +25476,6 @@ const configureDOMPurify = () => {
25418
25476
  const element = node;
25419
25477
  const src = element.getAttribute("src") || "";
25420
25478
  if (!isAllowedDomain(src)) {
25421
- console.warn("🚨 Blocked iframe from non-allowed domain:", src);
25422
25479
  node.parentNode?.removeChild(node);
25423
25480
  }
25424
25481
  }
@@ -25430,7 +25487,6 @@ function sanitizeIframeHTML(html2) {
25430
25487
  const config = configureDOMPurify();
25431
25488
  const cleaned = purify.sanitize(html2, config);
25432
25489
  if (!cleaned.includes("<iframe")) {
25433
- console.warn("⚠️ No valid iframe found after sanitization");
25434
25490
  return null;
25435
25491
  }
25436
25492
  const match = cleaned.match(/<iframe[^>]*src=["']([^"']+)["']/i);
@@ -25442,7 +25498,6 @@ function sanitizeIframeHTML(html2) {
25442
25498
  }
25443
25499
  return match[1];
25444
25500
  } catch (error) {
25445
- console.error("🚨 Error sanitizing iframe:", error);
25446
25501
  return null;
25447
25502
  } finally {
25448
25503
  purify.removeAllHooks();
@@ -25480,7 +25535,6 @@ const createFinder = (regex) => {
25480
25535
  match
25481
25536
  });
25482
25537
  }
25483
- console.log({ match, matches });
25484
25538
  return matches.length > 0 ? matches : null;
25485
25539
  };
25486
25540
  };
@@ -25532,11 +25586,9 @@ const Iframe = Node$1.create({
25532
25586
  const iframeHTML = match[0];
25533
25587
  const safeSrc = sanitizeIframeHTML(iframeHTML);
25534
25588
  if (!safeSrc) {
25535
- console.warn("🚨 Blocked unsafe iframe paste");
25536
25589
  toast.error("🚨 Your pasted iframe is not safe to render");
25537
25590
  return;
25538
25591
  }
25539
- console.log("✅ Safe iframe URL validated:", safeSrc);
25540
25592
  const node = this.type.create({ src: safeSrc, previewPayload: null });
25541
25593
  state.tr.replaceRangeWith(range.from, range.to, node);
25542
25594
  }
@@ -25547,7 +25599,6 @@ const Iframe = Node$1.create({
25547
25599
  handler: ({ state, range, match }) => {
25548
25600
  const fullUrl = match[0];
25549
25601
  const embedUrl = getEmbedUrl(fullUrl);
25550
- console.log({ match, fullUrl, embedUrl });
25551
25602
  if (!embedUrl) return;
25552
25603
  const node = this.type.create({ src: embedUrl });
25553
25604
  state.tr.replaceRangeWith(range.from, range.to, node);
@@ -25593,10 +25644,9 @@ const handleUrlWithoutSelection = (editor, url, event, autoDetectMedia) => {
25593
25644
  mediaType: MediaItemType.MEDIA_ITEM
25594
25645
  });
25595
25646
  }).catch(
25596
- (e) => console.error("[SmartLinkPaste] Media detection failed, falling back to link:", e)
25647
+ (e) => void 0
25597
25648
  );
25598
25649
  }
25599
- console.log("[SmartLinkPaste] Inserting as link node");
25600
25650
  editor.chain().focus().insertLink({ href: normalizedUrl, text: url }).run();
25601
25651
  return true;
25602
25652
  };
@@ -25618,7 +25668,6 @@ const createPasteHandler = (editor, options) => {
25618
25668
  return false;
25619
25669
  }
25620
25670
  const trimmedText = pasteText.trim();
25621
- console.log("[SmartLinkPaste] Valid URL detected:", isEmbeddableUrl(trimmedText));
25622
25671
  if (isEmbeddableUrl(trimmedText) && options?.autoEmbed) {
25623
25672
  event.preventDefault();
25624
25673
  return false;
@@ -25635,7 +25684,6 @@ const createPasteHandler = (editor, options) => {
25635
25684
  options?.autoDetectMedia ?? true
25636
25685
  );
25637
25686
  } catch (error) {
25638
- console.error("[SmartLinkPaste] Error:", error);
25639
25687
  return false;
25640
25688
  }
25641
25689
  };
@@ -25647,10 +25695,8 @@ const createTransformHandler = (editor) => {
25647
25695
  return slice;
25648
25696
  }
25649
25697
  try {
25650
- console.log("[SmartLinkPaste] Transforming inline URLs in pasted content");
25651
25698
  return transformUrlsInSlice(editor, slice);
25652
25699
  } catch (error) {
25653
- console.error("[SmartLinkPaste] Transform error:", error);
25654
25700
  return slice;
25655
25701
  }
25656
25702
  };
@@ -25757,7 +25803,6 @@ const SmartMediaUpload = Extension.create({
25757
25803
  const uid = v4();
25758
25804
  const options = this.options;
25759
25805
  if (!options.api) {
25760
- console.error("API instance not provided to SmartMediaUpload");
25761
25806
  return false;
25762
25807
  }
25763
25808
  if (isFileOrBlob(source)) {
@@ -25767,7 +25812,6 @@ const SmartMediaUpload = Extension.create({
25767
25812
  options.allowedFileTypes
25768
25813
  );
25769
25814
  if (!validation.valid) {
25770
- console.error("File validation failed:", validation.error);
25771
25815
  options.onUploadError?.(uid, new Error(validation.error));
25772
25816
  return false;
25773
25817
  }
@@ -25851,7 +25895,6 @@ const SmartMediaUpload = Extension.create({
25851
25895
  } else editor.commands.deleteMediaByUid(item.uid);
25852
25896
  options.onUploadComplete?.(item.uid, hostedUrl);
25853
25897
  } catch (error) {
25854
- console.error("Upload failed:", error);
25855
25898
  const blobUrl = this.storage.blobUrls.get(item.uid);
25856
25899
  if (blobUrl) {
25857
25900
  URL.revokeObjectURL(blobUrl);
@@ -25863,7 +25906,7 @@ const SmartMediaUpload = Extension.create({
25863
25906
  this.storage.activeUploads--;
25864
25907
  this.storage.processUploadQueue(editor);
25865
25908
  }
25866
- })().catch((err) => console.log(err));
25909
+ })().catch((err) => void 0);
25867
25910
  if (this.storage.uploadQueue.length > 0) {
25868
25911
  this.storage.processUploadQueue(editor);
25869
25912
  }
@@ -28563,7 +28606,6 @@ function getSuggestionOptions({
28563
28606
  const text2 = editor.getText();
28564
28607
  const trimmed = text2?.replace(WHITESPACE_REGEX, " ")?.trim();
28565
28608
  const matchStartPosition = trimmed?.lastIndexOf(char);
28566
- console.log({ matchStartPosition });
28567
28609
  const nodeAfter = editor.view.state.selection.$to.nodeAfter;
28568
28610
  const overrideSpace = nodeAfter?.text?.startsWith(" ");
28569
28611
  if (overrideSpace) {
@@ -28677,7 +28719,6 @@ const Mention = Node$1.create({
28677
28719
  renderHTML({ node, HTMLAttributes }) {
28678
28720
  const suggestion = getSuggestionFromChar(this, node.attrs.mentionSuggestionChar);
28679
28721
  if (this.options.renderLabel !== void 0) {
28680
- console.warn("renderLabel is deprecated use renderText and renderHTML instead");
28681
28722
  return [
28682
28723
  "span",
28683
28724
  mergeAttributes({ "data-type": this.name }, this.options.HTMLAttributes, HTMLAttributes),
@@ -28717,7 +28758,6 @@ const Mention = Node$1.create({
28717
28758
  suggestion: getSuggestionFromChar(this, node.attrs.mentionSuggestionChar)
28718
28759
  };
28719
28760
  if (this.options.renderLabel !== void 0) {
28720
- console.warn("renderLabel is deprecated use renderText and renderHTML instead");
28721
28761
  return this.options.renderLabel(args);
28722
28762
  }
28723
28763
  return this.options.renderText(args);
@@ -29706,11 +29746,9 @@ const mentionService = (api, mfs, store) => {
29706
29746
  const fetchMentions = async () => {
29707
29747
  const params = store.getState().getMentionParams();
29708
29748
  if (!params) {
29709
- console.error("DEBUG MENTION SERVICE::", "No group id or post id has been provided");
29710
29749
  return [];
29711
29750
  }
29712
29751
  const { groupId, postId } = params;
29713
- console.log({ groupId, postId });
29714
29752
  const response = postId ? await mfs.getRecommendationPost(groupId, postId, 0, 999) : await mfs.getRecommendationGroup(groupId, 0, 999);
29715
29753
  return response.entries?.filter((item) => Boolean(item?.user_data))?.map(
29716
29754
  (item) => ({
@@ -29729,7 +29767,6 @@ const mentionService = (api, mfs, store) => {
29729
29767
  const { selectedGroupId, groupId } = store.getState();
29730
29768
  const activeGroupId = selectedGroupId ?? groupId;
29731
29769
  if (!activeGroupId) {
29732
- console.warn("DEBUG HASHTAG SERVICE::", "No active group selected or provided");
29733
29770
  return [];
29734
29771
  }
29735
29772
  const response = await api.fetchGroupConversations(999, 0);
@@ -29931,8 +29968,8 @@ const LinkPreviewExtended = ({
29931
29968
  title,
29932
29969
  description,
29933
29970
  image,
29934
- domain
29935
- // onClickDelete,
29971
+ domain,
29972
+ onClickDelete
29936
29973
  }) => {
29937
29974
  const safeDomain = useMemo(() => {
29938
29975
  try {
@@ -29941,6 +29978,11 @@ const LinkPreviewExtended = ({
29941
29978
  return "unknown";
29942
29979
  }
29943
29980
  }, [href, domain]);
29981
+ const handleDelete = (e) => {
29982
+ e.preventDefault();
29983
+ e.stopPropagation();
29984
+ onClickDelete();
29985
+ };
29944
29986
  return /* @__PURE__ */ jsxs(
29945
29987
  "div",
29946
29988
  {
@@ -29949,18 +29991,32 @@ const LinkPreviewExtended = ({
29949
29991
  selected ? "ring-2 ring-blue-500 ring-offset-2 rounded-lg" : ""
29950
29992
  ),
29951
29993
  children: [
29952
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 absolute z-50 right-3 top-3", children: /* @__PURE__ */ jsx(
29953
- ToolbarButton,
29954
- {
29955
- asChild: true,
29956
- tooltip: "Visit Link",
29957
- className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none group-hover:bg-accent/70 group-hover:text-accent-foreground text-primary-send",
29958
- children: /* @__PURE__ */ jsxs("span", { className: "relative", children: [
29959
- /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "absolute inset-0" }),
29960
- /* @__PURE__ */ jsx(ExternalLink, {})
29961
- ] })
29962
- }
29963
- ) }),
29994
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 absolute z-50 right-3 top-3", children: [
29995
+ /* @__PURE__ */ jsx(
29996
+ ToolbarButton,
29997
+ {
29998
+ asChild: true,
29999
+ tooltip: "Visit Link",
30000
+ className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none group-hover:bg-accent/70 group-hover:text-accent-foreground text-primary-send",
30001
+ children: /* @__PURE__ */ jsxs("span", { className: "relative", children: [
30002
+ /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "absolute inset-0" }),
30003
+ /* @__PURE__ */ jsx(ExternalLink, {})
30004
+ ] })
30005
+ }
30006
+ ),
30007
+ /* @__PURE__ */ jsx(
30008
+ ToolbarButton,
30009
+ {
30010
+ tooltip: "Remove Link Preview",
30011
+ onClick: handleDelete,
30012
+ "aria-label": "Delete link preview",
30013
+ type: "button",
30014
+ size: "icon",
30015
+ className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none bg-transparent group-hover:bg-red-50/70 hover:bg-red-50 text-destructive hover:text-destructive",
30016
+ children: /* @__PURE__ */ jsx(Trash2, {})
30017
+ }
30018
+ )
30019
+ ] }),
29964
30020
  /* @__PURE__ */ jsx("div", { className: "relative z-0 w-full", children: /* @__PURE__ */ jsxs("div", { className: "group overflow-hidden flex flex-col rounded-lg border bg-accent/30 transition-all hover:border-foreground/20 hover:shadow-sm", children: [
29965
30021
  /* @__PURE__ */ jsx("div", { className: "relative h-80 w-full shrink-0 overflow-hidden bg-muted border-b", children: /* @__PURE__ */ jsx(
29966
30022
  "img",
@@ -30081,7 +30137,6 @@ const LinkPreview = Node$1.create({
30081
30137
  },
30082
30138
  renderHTML({ node }) {
30083
30139
  const { href, uid, title, description, image, domain } = node.attrs;
30084
- console.log("INSIDE RENDER HTML::", { href, image });
30085
30140
  if (!href) return ["div", {}];
30086
30141
  const content = [
30087
30142
  // Link overlay
@@ -30216,11 +30271,6 @@ const MediaGroupView = ({ node, editor }) => {
30216
30271
  editor.commands.deleteMediaByUid(uid);
30217
30272
  };
30218
30273
  const mediaNodes = node?.content?.content || [];
30219
- console.log("MediaGroupView render:", {
30220
- contentSize: node?.content?.size,
30221
- mediaCount: mediaNodes?.length,
30222
- nodes: mediaNodes?.map((n) => ({ type: n?.type?.name, uid: n?.attrs?.uid }))
30223
- });
30224
30274
  return /* @__PURE__ */ jsx(
30225
30275
  NodeViewWrapper,
30226
30276
  {
@@ -30322,14 +30372,12 @@ const createMediaModePlugin = () => {
30322
30372
  child.marks.forEach((mark) => {
30323
30373
  if (mark.type.name === "customLink" && mark.attrs.previewPayload) {
30324
30374
  lastLinkPreviewData = mark.attrs.previewPayload;
30325
- console.log("Found link with previewPayload:", lastLinkPreviewData);
30326
30375
  }
30327
30376
  });
30328
30377
  }
30329
30378
  });
30330
30379
  }
30331
30380
  });
30332
- console.log("Cleanup check:", { modified, hasMediaGroup, lastLinkPreviewData });
30333
30381
  if (modified && hasMediaGroup && lastLinkPreviewData) {
30334
30382
  let hasLinkPreview = false;
30335
30383
  tr.doc.forEach((node) => {
@@ -30337,10 +30385,6 @@ const createMediaModePlugin = () => {
30337
30385
  hasLinkPreview = true;
30338
30386
  }
30339
30387
  });
30340
- console.log("Creating linkPreview:", {
30341
- hasLinkPreview,
30342
- schemaHasLinkPreview: !!newState.schema.nodes.linkPreview
30343
- });
30344
30388
  if (!hasLinkPreview && newState.schema.nodes.linkPreview) {
30345
30389
  const preview = lastLinkPreviewData;
30346
30390
  const linkPreviewNode = newState.schema.nodes.linkPreview.create({
@@ -30351,7 +30395,6 @@ const createMediaModePlugin = () => {
30351
30395
  image: preview.linkImage?.url ?? "",
30352
30396
  variant: LinkPreviewType.Extended
30353
30397
  });
30354
- console.log("Inserting linkPreview node:", { lastLinkPreviewData, linkPreviewNode });
30355
30398
  tr.insert(tr.doc.content.size, linkPreviewNode);
30356
30399
  modified = true;
30357
30400
  }
@@ -30411,7 +30454,6 @@ const createMediaModePlugin = () => {
30411
30454
  }
30412
30455
  const mediaNodes = updatedTopLevelMedia.map((m) => m.node);
30413
30456
  if (mediaNodes.some((n) => !n || n.type.name !== "media")) {
30414
- console.warn("Invalid media nodes detected, skipping group creation");
30415
30457
  return null;
30416
30458
  }
30417
30459
  const mediaGroup = newState.schema.nodes.mediaGroup.create({}, mediaNodes);
@@ -30429,7 +30471,6 @@ const createMediaModePlugin = () => {
30429
30471
  const $pos = tr.doc.resolve(endPos);
30430
30472
  tr.setSelection(TextSelection$1.near($pos));
30431
30473
  } catch (e) {
30432
- console.warn("Could not set selection:", e);
30433
30474
  }
30434
30475
  }
30435
30476
  tr.setMeta("addToHistory", false);
@@ -30437,7 +30478,6 @@ const createMediaModePlugin = () => {
30437
30478
  }
30438
30479
  return modified ? tr : null;
30439
30480
  } catch (error) {
30440
- console.error("MediaMode plugin error:", error);
30441
30481
  return null;
30442
30482
  } finally {
30443
30483
  isProcessing = false;
@@ -30579,7 +30619,7 @@ const getMediaExtensions = ({ api, store, user }) => {
30579
30619
  }),
30580
30620
  LinkPreview.configure({
30581
30621
  variant: LinkPreviewType.Extended,
30582
- selectable: false,
30622
+ // selectable: false,
30583
30623
  draggable: false
30584
30624
  }),
30585
30625
  getMentionExtension(core, mfs, store),
@@ -30723,7 +30763,6 @@ const isLinkMarkWithPayload = (node) => isLinkMark(node) && Boolean(node?.attrs?
30723
30763
  const getLinkItemsPayload = (json) => {
30724
30764
  const links = find(json, (node) => isLinkMarkWithPayload(node));
30725
30765
  const items = links?.at(-1);
30726
- console.log("Link Items Payload::", { items });
30727
30766
  return { items };
30728
30767
  };
30729
30768
  const getPollItemsPayload = (json) => {
@@ -30737,7 +30776,7 @@ const isValidItem = (item) => {
30737
30776
  const mediaItem = item;
30738
30777
  const isValidLinkItem = linkItem?.linkUrl;
30739
30778
  const mediaItemSources = mediaItem?.sources;
30740
- const isValidMediaItem = mediaItemSources?.original?.url || mediaItemSources?.thumbnail?.url || mediaItemSources?.placeholder?.url;
30779
+ const isValidMediaItem = mediaItemSources?.original?.url || mediaItemSources?.thumbnail?.url;
30741
30780
  return Boolean(isValidLinkItem || isValidMediaItem);
30742
30781
  };
30743
30782
  const generateHtmlPostPayload = ({
@@ -30757,7 +30796,6 @@ const generateHtmlPostPayload = ({
30757
30796
  )?.at(0);
30758
30797
  const isEmbedOnly = isOnlyContentNode(json, "iframe");
30759
30798
  const body = isEmbedOnly ? previewItemEmbed?.attrs?.previewPayload?.linkTitle ?? previewItemEmbed?.attrs?.src ?? "" : secondaryText?.text ?? firstText?.text ?? "";
30760
- console.log({ firstText });
30761
30799
  const items = [
30762
30800
  previewItemMedia?.attrs?.payload,
30763
30801
  previewItemEmbed?.attrs?.previewPayload,
@@ -30784,11 +30822,14 @@ const generateMediaPostPayload = ({
30784
30822
  const { mentionData } = getMentionDataPayload(json);
30785
30823
  const { items: mediaItems } = getMediaItemsPayload(json);
30786
30824
  const { items: linkItems } = getLinkItemsPayload(json);
30825
+ const items = mediaItems?.length > 0 ? mediaItems : linkItems?.length > 0 ? linkItems : [];
30826
+ if (!body && mediaItems.length === 0)
30827
+ return { error: "Your post is empty. Add text or media to share your thoughts." };
30787
30828
  return {
30788
30829
  ...commons,
30789
30830
  type: mediaItems?.length > 0 ? NewPostType.NEW_POST_MEDIA : linkItems?.length > 0 ? NewPostType.NEW_POST_LINK : NewPostType.NEW_POST_MESSAGE,
30790
30831
  body,
30791
- items: mediaItems?.length > 0 ? mediaItems : linkItems?.length > 0 ? linkItems : [],
30832
+ items,
30792
30833
  mentionData,
30793
30834
  sendCrossMention
30794
30835
  };
@@ -30808,7 +30849,6 @@ const generatePollPostPayload = ({
30808
30849
  option_id: index2 === 0 ? item.option_id : v4(),
30809
30850
  option_color: OPTION_COLORS[index2 % OPTION_COLORS.length]
30810
30851
  })) : items;
30811
- console.log({ polls });
30812
30852
  return {
30813
30853
  ...commons,
30814
30854
  type: NewPostType.NEW_POST_POLL,
@@ -30845,6 +30885,7 @@ const PostBuilderEditorInstance = ({
30845
30885
  const [isDragging, setIsDragging] = useState(false);
30846
30886
  const { trackPublish } = usePostBuilderAnalytics();
30847
30887
  const { clearContent } = usePersistence();
30888
+ useHostAnalyticsBridge();
30848
30889
  const handleDragOver = (e) => {
30849
30890
  e.preventDefault();
30850
30891
  setIsDragging(true);
@@ -30864,10 +30905,24 @@ const PostBuilderEditorInstance = ({
30864
30905
  const text2 = editor?.getText();
30865
30906
  const payload = generateCreatePostPayload(editorTab, { editor, sendCrossMention });
30866
30907
  const isPollType = payload?.type === NewPostType.NEW_POST_POLL;
30867
- if (!payload) return;
30908
+ if (payload?.error) {
30909
+ toast.error(payload.error);
30910
+ return;
30911
+ }
30912
+ if (!payload?.postId) return;
30868
30913
  if (isPollType && payload.items?.length === 0)
30869
30914
  return toast.warning(`At least ${POLL_LIMITS.MIN} option is mandatory to create a poll post`);
30870
- trackPublish("attempted");
30915
+ if (typeof window !== "undefined") {
30916
+ window.dispatchEvent(
30917
+ new CustomEvent(PostBuilderEvents.POST_PUBLISH_ATTEMPTED, {
30918
+ detail: {
30919
+ postId: payload.postId,
30920
+ postType: payload.type
30921
+ }
30922
+ })
30923
+ );
30924
+ }
30925
+ trackPublish({ status: "attempted", postId: payload?.postId, postType: payload?.type });
30871
30926
  onCreatePost?.({ payload, html: html2, json, text: text2 });
30872
30927
  if (!clearOnSuccess) return;
30873
30928
  clearContent();
@@ -31041,7 +31096,6 @@ class SessionManager {
31041
31096
  }, SESSION_TIMEOUT_MS);
31042
31097
  }
31043
31098
  endSession(reason) {
31044
- console.log({ reason });
31045
31099
  if (this.inactivityTimer) {
31046
31100
  clearTimeout(this.inactivityTimer);
31047
31101
  }
@@ -31102,7 +31156,7 @@ function useAnalytics({ editorTab, config }) {
31102
31156
  const featureTracker = useRef(new FeatureTracker()).current;
31103
31157
  const logEvent = useAnalyticsLogEvent();
31104
31158
  const trackEvent = useCallback(
31105
- (name, properties = {}) => {
31159
+ ({ name, properties }) => {
31106
31160
  const fullConfig = { ...DEFAULT_CONFIG, ...config };
31107
31161
  if (!fullConfig.enabled) return;
31108
31162
  sessionManager.updateActivity();
@@ -31110,30 +31164,32 @@ function useAnalytics({ editorTab, config }) {
31110
31164
  session_id: sessionManager.getSessionId(),
31111
31165
  timestamp: Date.now(),
31112
31166
  editor_type: editorTab,
31113
- ...properties
31167
+ ...properties ?? {}
31114
31168
  };
31115
- if (logEvent) {
31116
- logEvent(name, enrichedProperties);
31117
- }
31118
- if (fullConfig.debug) {
31119
- console.log("[Analytics]", name, enrichedProperties);
31120
- }
31169
+ const cleanProps = pickBy(enrichedProperties, (value) => value != null);
31170
+ if (logEvent) logEvent(name, cleanProps);
31121
31171
  },
31122
31172
  [config, editorTab, logEvent, sessionManager]
31123
31173
  );
31124
31174
  useEffect(() => {
31125
31175
  const sessionId = sessionManager.startSession();
31126
- trackEvent(ANALYTICS_EVENTS.SESSION.STARTED, {
31127
- session_id: sessionId,
31128
- timestamp: Date.now(),
31129
- editor_type: editorTab
31176
+ trackEvent({
31177
+ name: ANALYTICS_EVENTS.SESSION.STARTED,
31178
+ properties: {
31179
+ session_id: sessionId,
31180
+ timestamp: Date.now(),
31181
+ editor_type: editorTab
31182
+ }
31130
31183
  });
31131
31184
  const handleUnload = () => {
31132
- trackEvent(ANALYTICS_EVENTS.SESSION.COMPLETED, {
31133
- session_id: sessionManager.getSessionId(),
31134
- timestamp: Date.now(),
31135
- editor_type: editorTab,
31136
- session_duration_ms: sessionManager.getSessionDuration()
31185
+ trackEvent({
31186
+ name: ANALYTICS_EVENTS.SESSION.COMPLETED,
31187
+ properties: {
31188
+ session_id: sessionManager.getSessionId(),
31189
+ timestamp: Date.now(),
31190
+ editor_type: editorTab,
31191
+ session_duration_ms: sessionManager.getSessionDuration()
31192
+ }
31137
31193
  });
31138
31194
  };
31139
31195
  window.addEventListener("beforeunload", handleUnload);
@@ -31143,60 +31199,88 @@ function useAnalytics({ editorTab, config }) {
31143
31199
  };
31144
31200
  }, []);
31145
31201
  const trackFeature = useCallback(
31146
- (featureName) => {
31202
+ ({ featureName }) => {
31147
31203
  const { isFirstUse, usageCount } = featureTracker.trackUsage(featureName);
31148
- trackEvent(isFirstUse ? ANALYTICS_EVENTS.FEATURE.DISCOVERED : ANALYTICS_EVENTS.FEATURE.USED, {
31149
- feature_name: featureName,
31150
- is_first_use: isFirstUse,
31151
- usage_count: usageCount
31204
+ trackEvent({
31205
+ name: isFirstUse ? ANALYTICS_EVENTS.FEATURE.DISCOVERED : ANALYTICS_EVENTS.FEATURE.USED,
31206
+ properties: {
31207
+ feature_name: featureName,
31208
+ is_first_use: isFirstUse,
31209
+ usage_count: usageCount
31210
+ }
31152
31211
  });
31153
31212
  },
31154
31213
  [trackEvent, featureTracker]
31155
31214
  );
31156
31215
  const trackPublish = useCallback(
31157
- (status, data) => {
31216
+ ({ status, data }) => {
31158
31217
  const eventMap = {
31159
31218
  attempted: ANALYTICS_EVENTS.PUBLISH.ATTEMPTED,
31160
31219
  success: ANALYTICS_EVENTS.PUBLISH.SUCCESS,
31161
31220
  failed: ANALYTICS_EVENTS.PUBLISH.FAILED
31162
31221
  };
31163
- trackEvent(eventMap[status], {
31222
+ const properties = {
31164
31223
  editor_type: editorTab,
31165
31224
  session_duration_ms: sessionManager.getSessionDuration(),
31166
31225
  ...data
31226
+ };
31227
+ trackEvent({
31228
+ name: eventMap[status],
31229
+ properties
31167
31230
  });
31168
31231
  sessionManager.endSession("completed");
31169
31232
  },
31170
31233
  [trackEvent, editorTab, sessionManager]
31171
31234
  );
31172
31235
  const trackAbandon = useCallback(
31173
- (contentLength, hasUnsavedChanges, abandonReason, postType) => {
31174
- trackEvent(ANALYTICS_EVENTS.SESSION.ABANDONED, {
31175
- session_duration_ms: sessionManager.getSessionDuration(),
31176
- post_type: postType,
31177
- content_length: contentLength,
31178
- has_unsaved_changes: hasUnsavedChanges,
31179
- abandon_reason: abandonReason
31236
+ ({
31237
+ contentLength,
31238
+ hasUnsavedChanges,
31239
+ abandonReason,
31240
+ postType,
31241
+ userHistoryData
31242
+ }) => {
31243
+ trackEvent({
31244
+ name: ANALYTICS_EVENTS.SESSION.ABANDONED,
31245
+ properties: {
31246
+ session_duration_ms: sessionManager.getSessionDuration(),
31247
+ post_type: postType,
31248
+ content_length: contentLength,
31249
+ has_unsaved_changes: hasUnsavedChanges,
31250
+ abandon_reason: abandonReason,
31251
+ // Include user history if provided
31252
+ ...userHistoryData && {
31253
+ previous_abandon_count: userHistoryData.previous_abandon_count,
31254
+ previous_publish_count: userHistoryData.previous_publish_count,
31255
+ time_since_last_publish_ms: userHistoryData.time_since_last_publish_ms,
31256
+ is_returning_user: userHistoryData.is_returning_user
31257
+ }
31258
+ }
31180
31259
  });
31181
31260
  sessionManager.endSession("abandoned");
31182
31261
  },
31183
31262
  [trackEvent, sessionManager]
31184
31263
  );
31185
31264
  const trackTabSwitch = useCallback(
31186
- (oldTab, newTab) => {
31187
- trackEvent(ANALYTICS_EVENTS.EDITOR.FOCUSED, {
31188
- from_tab: oldTab,
31189
- to_tab: newTab,
31190
- editor_type: editorTab
31265
+ ({ oldTab, newTab }) => {
31266
+ trackEvent({
31267
+ name: ANALYTICS_EVENTS.EDITOR.FOCUSED,
31268
+ properties: {
31269
+ from_tab: oldTab,
31270
+ to_tab: newTab
31271
+ }
31191
31272
  });
31192
31273
  },
31193
- [trackEvent, editorTab]
31274
+ [trackEvent]
31194
31275
  );
31195
31276
  const trackEditorFocus = useCallback(
31196
- (context) => {
31197
- trackEvent(ANALYTICS_EVENTS.EDITOR.FOCUSED, {
31198
- context,
31199
- editor_type: editorTab
31277
+ ({ context }) => {
31278
+ trackEvent({
31279
+ name: ANALYTICS_EVENTS.EDITOR.FOCUSED,
31280
+ properties: {
31281
+ context,
31282
+ editor_type: editorTab
31283
+ }
31200
31284
  });
31201
31285
  },
31202
31286
  [trackEvent, editorTab]
@@ -31230,19 +31314,91 @@ function useAnalytics({ editorTab, config }) {
31230
31314
  ]
31231
31315
  );
31232
31316
  }
31317
+ const STORAGE_KEY = "pb_user_history";
31318
+ class UserHistoryTracker {
31319
+ history;
31320
+ constructor() {
31321
+ this.history = this.loadHistory();
31322
+ }
31323
+ loadHistory() {
31324
+ try {
31325
+ const stored = localStorage.getItem(STORAGE_KEY);
31326
+ if (stored) {
31327
+ return JSON.parse(stored);
31328
+ }
31329
+ } catch (error) {
31330
+ }
31331
+ return {
31332
+ previous_abandon_count: 0,
31333
+ previous_publish_count: 0,
31334
+ last_publish_timestamp: null,
31335
+ last_abandon_timestamp: null,
31336
+ first_session_timestamp: Date.now()
31337
+ };
31338
+ }
31339
+ saveHistory() {
31340
+ try {
31341
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(this.history));
31342
+ } catch (error) {
31343
+ }
31344
+ }
31345
+ /**
31346
+ * Record a successful publish
31347
+ */
31348
+ recordPublish() {
31349
+ this.history.previous_publish_count += 1;
31350
+ this.history.last_publish_timestamp = Date.now();
31351
+ this.saveHistory();
31352
+ }
31353
+ /**
31354
+ * Record an abandonment
31355
+ */
31356
+ recordAbandon() {
31357
+ this.history.previous_abandon_count += 1;
31358
+ this.history.last_abandon_timestamp = Date.now();
31359
+ this.saveHistory();
31360
+ }
31361
+ /**
31362
+ * Get current user history for analytics
31363
+ */
31364
+ getHistory() {
31365
+ const now2 = Date.now();
31366
+ const daysSinceFirstSession = Math.floor(
31367
+ (now2 - this.history.first_session_timestamp) / (1e3 * 60 * 60 * 24)
31368
+ );
31369
+ return {
31370
+ previous_abandon_count: this.history.previous_abandon_count,
31371
+ previous_publish_count: this.history.previous_publish_count,
31372
+ time_since_last_publish_ms: this.history.last_publish_timestamp ? now2 - this.history.last_publish_timestamp : null,
31373
+ is_returning_user: daysSinceFirstSession > 0.5,
31374
+ days_since_first_session: daysSinceFirstSession
31375
+ };
31376
+ }
31377
+ /**
31378
+ * Clear history (for testing or user request)
31379
+ */
31380
+ clearHistory() {
31381
+ localStorage.removeItem(STORAGE_KEY);
31382
+ this.history = {
31383
+ previous_abandon_count: 0,
31384
+ previous_publish_count: 0,
31385
+ last_publish_timestamp: null,
31386
+ last_abandon_timestamp: null,
31387
+ first_session_timestamp: Date.now()
31388
+ };
31389
+ }
31390
+ }
31233
31391
  function useEditorAnalytics({
31234
31392
  editor,
31235
31393
  editorType,
31236
31394
  context,
31237
31395
  idleTimeout = 3e5,
31238
- // 5 minutes
31239
31396
  trackBlur = false
31240
- // Default: don't track every blur
31241
31397
  }) {
31242
31398
  const analytics = useAnalytics({
31243
31399
  editorTab: editorType,
31244
31400
  config: {
31245
- debug: false,
31401
+ debug: true,
31246
31402
  enabled: true
31247
31403
  }
31248
31404
  });
@@ -31250,6 +31406,7 @@ function useEditorAnalytics({
31250
31406
  const idleTimer = useRef();
31251
31407
  const hasFocusedOnce = useRef(false);
31252
31408
  const hasAbandonedSession = useRef(false);
31409
+ const userHistory = useRef(new UserHistoryTracker()).current;
31253
31410
  const getEditorMetrics = useCallback(() => {
31254
31411
  if (!editor) return null;
31255
31412
  const json = editor.getJSON();
@@ -31289,7 +31446,6 @@ function useEditorAnalytics({
31289
31446
  linkCount,
31290
31447
  formattingFeatures: Array.from(formattingFeatures),
31291
31448
  hasUnsavedChanges: editor.state.doc.content.size > 2,
31292
- // Has content beyond empty doc
31293
31449
  isEmpty: editor.isEmpty
31294
31450
  };
31295
31451
  }, [editor, analytics]);
@@ -31300,16 +31456,29 @@ function useEditorAnalytics({
31300
31456
  idleTimer.current = setTimeout(() => {
31301
31457
  const metrics = getEditorMetrics();
31302
31458
  if (metrics && !metrics.isEmpty) {
31303
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "idle_timeout");
31459
+ const history = userHistory.getHistory();
31460
+ analytics.trackAbandon({
31461
+ contentLength: metrics.characterCount,
31462
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31463
+ abandonReason: "idle_timeout",
31464
+ postType: void 0,
31465
+ userHistoryData: {
31466
+ previous_abandon_count: history.previous_abandon_count,
31467
+ previous_publish_count: history.previous_publish_count,
31468
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31469
+ is_returning_user: history.is_returning_user
31470
+ }
31471
+ });
31472
+ userHistory.recordAbandon();
31304
31473
  hasAbandonedSession.current = true;
31305
31474
  }
31306
31475
  }, idleTimeout);
31307
- }, [editor, idleTimeout, analytics, getEditorMetrics]);
31476
+ }, [editor, idleTimeout, analytics, getEditorMetrics, userHistory]);
31308
31477
  useEffect(() => {
31309
31478
  if (!editor) return;
31310
31479
  const handleFocus = () => {
31311
31480
  if (!hasFocusedOnce.current) {
31312
- analytics.trackEditorFocus(context);
31481
+ analytics.trackEditorFocus({ context });
31313
31482
  hasFocusedOnce.current = true;
31314
31483
  }
31315
31484
  resetIdleTimer();
@@ -31320,9 +31489,12 @@ function useEditorAnalytics({
31320
31489
  if (trackBlur) {
31321
31490
  const metrics = getEditorMetrics();
31322
31491
  if (metrics && !metrics.isEmpty) {
31323
- analytics.trackEvent(ANALYTICS_EVENTS.EDITOR.BLURRED, {
31324
- content_length: metrics.characterCount,
31325
- session_duration_ms: Date.now() - lastActivity.current
31492
+ analytics.trackEvent({
31493
+ name: ANALYTICS_EVENTS.EDITOR.BLURRED,
31494
+ properties: {
31495
+ content_length: metrics.characterCount,
31496
+ session_duration_ms: Date.now() - lastActivity.current
31497
+ }
31326
31498
  });
31327
31499
  }
31328
31500
  }
@@ -31341,7 +31513,20 @@ function useEditorAnalytics({
31341
31513
  if (hasAbandonedSession.current) return;
31342
31514
  const metrics = getEditorMetrics();
31343
31515
  if (metrics && !metrics.isEmpty) {
31344
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "navigation");
31516
+ const history = userHistory.getHistory();
31517
+ analytics.trackAbandon({
31518
+ contentLength: metrics.characterCount,
31519
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31520
+ abandonReason: "navigation",
31521
+ postType: void 0,
31522
+ userHistoryData: {
31523
+ previous_abandon_count: history.previous_abandon_count,
31524
+ previous_publish_count: history.previous_publish_count,
31525
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31526
+ is_returning_user: history.is_returning_user
31527
+ }
31528
+ });
31529
+ userHistory.recordAbandon();
31345
31530
  hasAbandonedSession.current = true;
31346
31531
  }
31347
31532
  };
@@ -31352,46 +31537,76 @@ function useEditorAnalytics({
31352
31537
  clearTimeout(idleTimer.current);
31353
31538
  }
31354
31539
  };
31355
- }, [editor, analytics, getEditorMetrics]);
31540
+ }, [editor, analytics, getEditorMetrics, userHistory]);
31356
31541
  const trackFeature = useCallback(
31357
- (featureName) => {
31358
- analytics.trackFeature(featureName);
31542
+ ({ featureName }) => {
31543
+ analytics.trackFeature({ featureName });
31359
31544
  resetIdleTimer();
31360
31545
  },
31361
31546
  [analytics, resetIdleTimer]
31362
31547
  );
31363
31548
  const trackPublish = useCallback(
31364
- (status, failureReason) => {
31549
+ ({ sessionId, groupId, postId, status, failureReason, postType }) => {
31365
31550
  const metrics = getEditorMetrics();
31366
31551
  if (!metrics) return;
31367
- analytics.trackPublish(status, {
31368
- word_count: metrics.wordCount,
31369
- character_count: metrics.characterCount,
31370
- media_count: metrics.mediaCount,
31371
- link_count: metrics.linkCount,
31372
- formatting_features: metrics.formattingFeatures,
31373
- failure_reason: failureReason
31552
+ const history = userHistory.getHistory();
31553
+ analytics.trackPublish({
31554
+ status,
31555
+ data: {
31556
+ ...sessionId ? { session_id: sessionId } : {},
31557
+ group_id: groupId,
31558
+ post_id: postId,
31559
+ post_type: postType,
31560
+ word_count: metrics.wordCount,
31561
+ character_count: metrics.characterCount,
31562
+ media_count: metrics.mediaCount,
31563
+ link_count: metrics.linkCount,
31564
+ formatting_features: metrics.formattingFeatures,
31565
+ failure_reason: failureReason,
31566
+ // Include user history
31567
+ previous_abandon_count: history.previous_abandon_count,
31568
+ previous_publish_count: history.previous_publish_count,
31569
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31570
+ is_returning_user: history.is_returning_user
31571
+ }
31374
31572
  });
31375
31573
  if (status === "success") {
31574
+ userHistory.recordPublish();
31376
31575
  hasAbandonedSession.current = true;
31377
31576
  }
31378
31577
  },
31379
- [analytics, getEditorMetrics]
31578
+ [analytics, getEditorMetrics, userHistory]
31380
31579
  );
31381
31580
  const trackExplicitAbandon = useCallback(() => {
31382
31581
  if (hasAbandonedSession.current) return;
31383
31582
  const metrics = getEditorMetrics();
31384
31583
  if (metrics && !metrics.isEmpty) {
31385
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "user_closed");
31584
+ const history = userHistory.getHistory();
31585
+ analytics.trackAbandon({
31586
+ contentLength: metrics.characterCount,
31587
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31588
+ abandonReason: "user_closed",
31589
+ postType: void 0,
31590
+ userHistoryData: {
31591
+ previous_abandon_count: history.previous_abandon_count,
31592
+ previous_publish_count: history.previous_publish_count,
31593
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31594
+ is_returning_user: history.is_returning_user
31595
+ }
31596
+ });
31597
+ userHistory.recordAbandon();
31386
31598
  hasAbandonedSession.current = true;
31387
31599
  }
31388
- }, [analytics, getEditorMetrics]);
31600
+ }, [analytics, getEditorMetrics, userHistory]);
31389
31601
  return {
31390
31602
  trackFeature,
31391
31603
  trackPublish,
31392
31604
  trackExplicitAbandon,
31393
31605
  trackTabSwitch: analytics.trackTabSwitch,
31394
- getEditorMetrics
31606
+ getEditorMetrics,
31607
+ // Expose user history for debugging
31608
+ getUserHistory: () => userHistory.getHistory(),
31609
+ currentSessionId: analytics.getSessionId()
31395
31610
  };
31396
31611
  }
31397
31612
  const PostBuilderAnalyticsProvider = ({
@@ -31457,58 +31672,68 @@ const PostBuilderEditor = ({
31457
31672
  isSubmitting,
31458
31673
  clearOnSuccess
31459
31674
  }
31460
- ) : (
31461
- // <Dialog open={openModal} onOpenChange={onModalOpenChange}>
31462
- // <DialogContent
31463
- // className="bg-transparent shadow-none border-0 p-3 lg:max-w-4xl shrink-0 max-h-[calc(100dvh-7rem)]! flex flex-col overflow-y-auto -translate-1/2"
31464
- // showCloseButton={false}
31465
- // >
31466
- // <DialogHeader>
31467
- // <DialogTitle className="sr-only">Post Builder Modal</DialogTitle>
31468
- // {!hideGroupSelector && (
31469
- // <div className="flex items-center justify-between gap-3">
31470
- // <GroupSelector user={user} store={store} />
31471
- // <DialogClose asChild>
31472
- // <Button variant="outline" size="icon">
31473
- // <X />
31474
- // </Button>
31475
- // </DialogClose>
31476
- // </div>
31477
- // )}
31478
- // </DialogHeader>
31479
- // <PostBuilderEditorInstance
31480
- // editor={editor}
31481
- // actions={actions}
31482
- // editorTab={editorTab}
31483
- // onSwitchEditor={setEditorTab}
31484
- // isSubmitting={isSubmitting}
31485
- // onCreatePost={onCreatePost}
31486
- // clearOnSuccess={clearOnSuccess}
31487
- // />
31488
- // </DialogContent>
31489
- // </Dialog>
31490
- /* @__PURE__ */ jsxs("div", { className: "prose-blockquote: flex-1 flex flex-col space-y-3 max-w-full max-h-[calc(100dvh-7rem)]", children: [
31491
- !hideGroupSelector && /* @__PURE__ */ jsx(GroupSelector, { user, store }),
31492
- /* @__PURE__ */ jsx(
31493
- PostBuilderEditorInstance,
31494
- {
31495
- editor,
31496
- actions,
31497
- editorTab,
31498
- onSwitchEditor: setEditorTab,
31499
- isSubmitting,
31500
- onCreatePost,
31501
- clearOnSuccess
31502
- }
31503
- )
31504
- ] })
31505
- ) }),
31675
+ ) : /* @__PURE__ */ jsxs("div", { className: "prose-blockquote: flex-1 flex flex-col space-y-3 max-w-full max-h-[calc(100dvh-7rem)]", children: [
31676
+ !hideGroupSelector && /* @__PURE__ */ jsx(GroupSelector, { user, store }),
31677
+ /* @__PURE__ */ jsx(
31678
+ PostBuilderEditorInstance,
31679
+ {
31680
+ editor,
31681
+ actions,
31682
+ editorTab,
31683
+ onSwitchEditor: setEditorTab,
31684
+ isSubmitting,
31685
+ onCreatePost,
31686
+ clearOnSuccess
31687
+ }
31688
+ )
31689
+ ] }) }),
31506
31690
  /* @__PURE__ */ jsx(Toaster2, { position: "top-center" })
31507
31691
  ] })
31508
31692
  }
31509
31693
  );
31510
31694
  };
31695
+ const PostBuilderProvider = ({
31696
+ children,
31697
+ apiBaseURL,
31698
+ authToken,
31699
+ toI18N,
31700
+ i18nKeys,
31701
+ logEvent
31702
+ }) => {
31703
+ const t = useCallback(
31704
+ (key, fallback) => {
31705
+ const message = toI18N(i18nKeys[key]);
31706
+ if (message) return message;
31707
+ return fallback || key;
31708
+ },
31709
+ [toI18N, i18nKeys]
31710
+ );
31711
+ const api = useMemo(() => {
31712
+ const core = new CoreApi(apiBaseURL.core, authToken, toI18N);
31713
+ const mfs = new MFSApi(apiBaseURL.mfs, authToken, toI18N);
31714
+ const fileStore = new FilestoreApi(apiBaseURL.fileStore, authToken, toI18N);
31715
+ core.initApi();
31716
+ mfs.initApi();
31717
+ fileStore.initApi();
31718
+ return {
31719
+ core,
31720
+ mfs,
31721
+ fileStore
31722
+ };
31723
+ }, [authToken, apiBaseURL, toI18N]);
31724
+ const value = useMemo(() => {
31725
+ return {
31726
+ authToken,
31727
+ t,
31728
+ i18nKeys,
31729
+ api,
31730
+ logEvent
31731
+ };
31732
+ }, [authToken, t, i18nKeys, api, logEvent]);
31733
+ return /* @__PURE__ */ jsx(PostBuilderContext.Provider, { value, children });
31734
+ };
31511
31735
  export {
31512
31736
  PostBuilderEditor,
31737
+ PostBuilderEvents,
31513
31738
  PostBuilderProvider
31514
31739
  };