@liveblocks/react 1.10.4 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -28,9 +28,25 @@ declare type Props = {
28
28
  declare function ClientSideSuspense(props: Props): ReactElement;
29
29
 
30
30
  declare type UseThreadsOptions<TThreadMetadata extends BaseMetadata> = {
31
+ /**
32
+ * The query (including metadata) to filter the threads by. If provided, only threads
33
+ * that match the query will be returned. If not provided, all threads will be returned.
34
+ */
31
35
  query?: {
36
+ /**
37
+ * The metadata to filter the threads by. If provided, only threads with metadata that matches
38
+ * the provided metadata will be returned. If not provided, all threads will be returned.
39
+ */
32
40
  metadata?: Partial<TThreadMetadata>;
33
41
  };
42
+ /**
43
+ * Whether to scroll to a comment on load based on the URL hash. Defaults to `true`.
44
+ *
45
+ * @example
46
+ * Given the URL `https://example.com/my-room#cm_xxx`, the `cm_xxx` comment will be
47
+ * scrolled to on load if it exists in the page.
48
+ */
49
+ scrollOnLoad?: boolean;
34
50
  };
35
51
 
36
52
  declare type UserStateLoading = {
@@ -1045,7 +1061,7 @@ declare type LiveblocksContextBundle<TUserMeta extends BaseUserMeta> = Resolve<L
1045
1061
  * This is an internal API, use "createLiveblocksContext" instead.
1046
1062
  */
1047
1063
  declare function useLiveblocksContextBundle(): LiveblocksContextBundle<BaseUserMeta>;
1048
- declare function createLiveblocksContext<TUserMeta extends BaseUserMeta = BaseUserMeta, TThreadMetadata extends BaseMetadata$1 = never>(client: Client<TUserMeta>): LiveblocksContextBundle<TUserMeta>;
1064
+ declare function createLiveblocksContext<TUserMeta extends BaseUserMeta = BaseUserMeta, TThreadMetadata extends BaseMetadata$1 = never>(client: Client): LiveblocksContextBundle<TUserMeta>;
1049
1065
 
1050
1066
  /**
1051
1067
  * @private
package/dist/index.d.ts CHANGED
@@ -28,9 +28,25 @@ declare type Props = {
28
28
  declare function ClientSideSuspense(props: Props): ReactElement;
29
29
 
30
30
  declare type UseThreadsOptions<TThreadMetadata extends BaseMetadata> = {
31
+ /**
32
+ * The query (including metadata) to filter the threads by. If provided, only threads
33
+ * that match the query will be returned. If not provided, all threads will be returned.
34
+ */
31
35
  query?: {
36
+ /**
37
+ * The metadata to filter the threads by. If provided, only threads with metadata that matches
38
+ * the provided metadata will be returned. If not provided, all threads will be returned.
39
+ */
32
40
  metadata?: Partial<TThreadMetadata>;
33
41
  };
42
+ /**
43
+ * Whether to scroll to a comment on load based on the URL hash. Defaults to `true`.
44
+ *
45
+ * @example
46
+ * Given the URL `https://example.com/my-room#cm_xxx`, the `cm_xxx` comment will be
47
+ * scrolled to on load if it exists in the page.
48
+ */
49
+ scrollOnLoad?: boolean;
34
50
  };
35
51
 
36
52
  declare type UserStateLoading = {
@@ -1045,7 +1061,7 @@ declare type LiveblocksContextBundle<TUserMeta extends BaseUserMeta> = Resolve<L
1045
1061
  * This is an internal API, use "createLiveblocksContext" instead.
1046
1062
  */
1047
1063
  declare function useLiveblocksContextBundle(): LiveblocksContextBundle<BaseUserMeta>;
1048
- declare function createLiveblocksContext<TUserMeta extends BaseUserMeta = BaseUserMeta, TThreadMetadata extends BaseMetadata$1 = never>(client: Client<TUserMeta>): LiveblocksContextBundle<TUserMeta>;
1064
+ declare function createLiveblocksContext<TUserMeta extends BaseUserMeta = BaseUserMeta, TThreadMetadata extends BaseMetadata$1 = never>(client: Client): LiveblocksContextBundle<TUserMeta>;
1049
1065
 
1050
1066
  /**
1051
1067
  * @private
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ var _core = require('@liveblocks/core');
5
5
 
6
6
  // src/version.ts
7
7
  var PKG_NAME = "@liveblocks/react";
8
- var PKG_VERSION = "1.10.4";
8
+ var PKG_VERSION = "1.11.0";
9
9
  var PKG_FORMAT = "cjs";
10
10
 
11
11
  // src/ClientSideSuspense.tsx
@@ -895,7 +895,33 @@ function createRoomContext(client, options) {
895
895
  return;
896
896
  }
897
897
  }
898
- function useThreads(options2 = { query: { metadata: {} } }) {
898
+ function handleScrollToCommentOnLoad(isQueryLoading, shouldScrollOnLoad, state) {
899
+ if (shouldScrollOnLoad === false)
900
+ return;
901
+ if (isQueryLoading === true)
902
+ return;
903
+ const isWindowDefined = typeof window !== "undefined";
904
+ if (!isWindowDefined)
905
+ return;
906
+ const hash = window.location.hash;
907
+ const commentId = hash.slice(1);
908
+ if (!commentId.startsWith("cm_"))
909
+ return;
910
+ const comment = document.getElementById(commentId);
911
+ if (comment === null)
912
+ return;
913
+ const comments = state.threads.flatMap((thread) => thread.comments);
914
+ const isCommentInThreads = comments.some(
915
+ (comment2) => comment2.id === commentId
916
+ );
917
+ if (!isCommentInThreads)
918
+ return;
919
+ comment.scrollIntoView();
920
+ }
921
+ function useThreads(options2 = {
922
+ query: { metadata: {} }
923
+ }) {
924
+ const { scrollOnLoad = true } = options2;
899
925
  const room = useRoom();
900
926
  const queryKey = React2.useMemo(
901
927
  () => generateQueryKey(room.id, options2.query),
@@ -907,15 +933,15 @@ function createRoomContext(client, options) {
907
933
  return () => decrementQuerySubscribers(queryKey);
908
934
  }, [room, queryKey]);
909
935
  const selector = React2.useCallback(
910
- (state) => {
911
- const query = state.queries[queryKey];
936
+ (state2) => {
937
+ const query = state2.queries[queryKey];
912
938
  if (query === void 0 || query.isLoading) {
913
939
  return {
914
940
  isLoading: true
915
941
  };
916
942
  }
917
943
  return {
918
- threads: selectedThreads(room.id, state, options2),
944
+ threads: selectedThreads(room.id, state2, options2),
919
945
  isLoading: false,
920
946
  error: query.error
921
947
  };
@@ -923,17 +949,30 @@ function createRoomContext(client, options) {
923
949
  [room, queryKey]
924
950
  // eslint-disable-line react-hooks/exhaustive-deps
925
951
  );
926
- return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
952
+ const state = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
927
953
  store.subscribe,
928
954
  store.get,
929
955
  store.get,
930
956
  selector
931
957
  );
958
+ React2.useEffect(
959
+ () => {
960
+ if (state.isLoading === true)
961
+ return;
962
+ handleScrollToCommentOnLoad(state.isLoading, scrollOnLoad, state);
963
+ },
964
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- We only want to run this effect once
965
+ [state.isLoading]
966
+ );
967
+ return state;
932
968
  }
933
- function useThreadsSuspense(options2 = { query: { metadata: {} } }) {
969
+ function useThreadsSuspense(options2 = {
970
+ query: { metadata: {} }
971
+ }) {
972
+ const { scrollOnLoad = true } = options2;
934
973
  const room = useRoom();
935
974
  const queryKey = React2.useMemo(
936
- () => generateQueryKey(room.id, _optionalChain([options2, 'optionalAccess', _5 => _5.query])),
975
+ () => generateQueryKey(room.id, options2.query),
937
976
  [room, options2]
938
977
  );
939
978
  const query = store.get().queries[queryKey];
@@ -944,9 +983,9 @@ function createRoomContext(client, options) {
944
983
  throw query.error;
945
984
  }
946
985
  const selector = React2.useCallback(
947
- (state) => {
986
+ (state2) => {
948
987
  return {
949
- threads: selectedThreads(room.id, state, options2),
988
+ threads: selectedThreads(room.id, state2, options2),
950
989
  isLoading: false
951
990
  };
952
991
  },
@@ -959,12 +998,20 @@ function createRoomContext(client, options) {
959
998
  decrementQuerySubscribers(queryKey);
960
999
  };
961
1000
  }, [queryKey]);
962
- return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1001
+ const state = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
963
1002
  store.subscribe,
964
1003
  store.get,
965
1004
  store.get,
966
1005
  selector
967
1006
  );
1007
+ React2.useEffect(
1008
+ () => {
1009
+ handleScrollToCommentOnLoad(state.isLoading, scrollOnLoad, state);
1010
+ },
1011
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- We only want to run this effect once
1012
+ [state.isLoading]
1013
+ );
1014
+ return state;
968
1015
  }
969
1016
  function useCreateThread() {
970
1017
  const room = useRoom();
@@ -1448,7 +1495,7 @@ function createRoomContext(client, options) {
1448
1495
  );
1449
1496
  }
1450
1497
  } catch (error) {
1451
- _core.console.error(_optionalChain([error, 'optionalAccess', _6 => _6.message]));
1498
+ _core.console.error(_optionalChain([error, 'optionalAccess', _5 => _5.message]));
1452
1499
  }
1453
1500
  };
1454
1501
  if (mentionSuggestionsCache.has(mentionSuggestionsCacheKey)) {
@@ -1780,7 +1827,7 @@ function getCurrentUserId(room) {
1780
1827
  }
1781
1828
  function handleApiError(err) {
1782
1829
  const message = `Request failed with status ${err.status}: ${err.message}`;
1783
- if (_optionalChain([err, 'access', _7 => _7.details, 'optionalAccess', _8 => _8.error]) === "FORBIDDEN") {
1830
+ if (_optionalChain([err, 'access', _6 => _6.details, 'optionalAccess', _7 => _7.error]) === "FORBIDDEN") {
1784
1831
  const detailedMessage = [message, err.details.suggestion, err.details.docs].filter(Boolean).join("\n");
1785
1832
  _core.console.error(detailedMessage);
1786
1833
  }
@@ -1804,6 +1851,12 @@ function useSharedContextBundle() {
1804
1851
  );
1805
1852
  }
1806
1853
  }
1854
+ var missingUserError = new Error(
1855
+ "resolveUsers didn't return anything for this user ID."
1856
+ );
1857
+ var missingRoomInfoError = new Error(
1858
+ "resolveRoomsInfo didn't return anything for this room ID."
1859
+ );
1807
1860
  function createSharedContext(client) {
1808
1861
  const usersStore = client[_core.kInternal].usersStore;
1809
1862
  const roomsInfoStore = client[_core.kInternal].roomsInfoStore;
@@ -1821,8 +1874,10 @@ function createSharedContext(client) {
1821
1874
  getUserState
1822
1875
  );
1823
1876
  return state ? {
1824
- ...state,
1825
- user: state.data
1877
+ isLoading: state.isLoading,
1878
+ user: state.data,
1879
+ // Return an error if `undefined` was returned by `resolveUsers` for this user ID
1880
+ error: !state.isLoading && !state.data && !state.error ? missingUserError : state.error
1826
1881
  } : { isLoading: true };
1827
1882
  }
1828
1883
  function useUserSuspense(userId) {
@@ -1837,14 +1892,18 @@ function createSharedContext(client) {
1837
1892
  if (userState.error) {
1838
1893
  throw userState.error;
1839
1894
  }
1895
+ if (!userState.data) {
1896
+ throw missingUserError;
1897
+ }
1840
1898
  const state = _indexjs.useSyncExternalStore.call(void 0,
1841
1899
  usersStore.subscribe,
1842
1900
  getUserState,
1843
1901
  getUserState
1844
1902
  );
1845
1903
  return {
1846
- ...state,
1847
- user: _optionalChain([state, 'optionalAccess', _9 => _9.data])
1904
+ isLoading: false,
1905
+ user: _optionalChain([state, 'optionalAccess', _8 => _8.data]),
1906
+ error: _optionalChain([state, 'optionalAccess', _9 => _9.error])
1848
1907
  };
1849
1908
  }
1850
1909
  function useRoomInfo(roomId) {
@@ -1861,8 +1920,10 @@ function createSharedContext(client) {
1861
1920
  getRoomInfoState
1862
1921
  );
1863
1922
  return state ? {
1864
- ...state,
1865
- info: state.data
1923
+ isLoading: state.isLoading,
1924
+ info: state.data,
1925
+ // Return an error if `undefined` was returned by `resolveRoomsInfo` for this room ID
1926
+ error: !state.isLoading && !state.data && !state.error ? missingRoomInfoError : state.error
1866
1927
  } : { isLoading: true };
1867
1928
  }
1868
1929
  function useRoomInfoSuspense(roomId) {
@@ -1877,14 +1938,18 @@ function createSharedContext(client) {
1877
1938
  if (roomInfoState.error) {
1878
1939
  throw roomInfoState.error;
1879
1940
  }
1941
+ if (!roomInfoState.data) {
1942
+ throw missingRoomInfoError;
1943
+ }
1880
1944
  const state = _indexjs.useSyncExternalStore.call(void 0,
1881
1945
  roomsInfoStore.subscribe,
1882
1946
  getRoomInfoState,
1883
1947
  getRoomInfoState
1884
1948
  );
1885
1949
  return {
1886
- ...state,
1887
- info: _optionalChain([state, 'optionalAccess', _10 => _10.data])
1950
+ isLoading: false,
1951
+ info: _optionalChain([state, 'optionalAccess', _10 => _10.data]),
1952
+ error: _optionalChain([state, 'optionalAccess', _11 => _11.error])
1888
1953
  };
1889
1954
  }
1890
1955
  const bundle = {