@streamplace/components 0.7.34 → 0.8.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.
Files changed (64) hide show
  1. package/dist/components/content-metadata/content-metadata-form.js +404 -0
  2. package/dist/components/content-metadata/content-rights.js +78 -0
  3. package/dist/components/content-metadata/content-warnings.js +68 -0
  4. package/dist/components/content-metadata/index.js +11 -0
  5. package/dist/components/dashboard/header.js +16 -2
  6. package/dist/components/dashboard/problems.js +29 -28
  7. package/dist/components/mobile-player/player.js +4 -0
  8. package/dist/components/mobile-player/ui/report-modal.js +3 -2
  9. package/dist/components/mobile-player/ui/viewer-context-menu.js +44 -1
  10. package/dist/components/ui/button.js +9 -9
  11. package/dist/components/ui/checkbox.js +87 -0
  12. package/dist/components/ui/dialog.js +188 -83
  13. package/dist/components/ui/dropdown.js +15 -10
  14. package/dist/components/ui/icons.js +6 -0
  15. package/dist/components/ui/primitives/button.js +0 -7
  16. package/dist/components/ui/primitives/input.js +13 -1
  17. package/dist/components/ui/primitives/modal.js +2 -2
  18. package/dist/components/ui/select.js +89 -0
  19. package/dist/components/ui/textarea.js +23 -4
  20. package/dist/components/ui/toast.js +464 -114
  21. package/dist/components/ui/tooltip.js +103 -0
  22. package/dist/index.js +2 -0
  23. package/dist/lib/metadata-constants.js +157 -0
  24. package/dist/lib/theme/theme.js +5 -3
  25. package/dist/lib/theme/tokens.js +9 -0
  26. package/dist/streamplace-provider/index.js +14 -4
  27. package/dist/streamplace-store/content-metadata-actions.js +118 -0
  28. package/dist/streamplace-store/graph.js +195 -0
  29. package/dist/streamplace-store/streamplace-store.js +18 -5
  30. package/dist/streamplace-store/user.js +67 -7
  31. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  32. package/package.json +3 -3
  33. package/src/components/content-metadata/content-metadata-form.tsx +761 -0
  34. package/src/components/content-metadata/content-rights.tsx +104 -0
  35. package/src/components/content-metadata/content-warnings.tsx +100 -0
  36. package/src/components/content-metadata/index.tsx +18 -0
  37. package/src/components/dashboard/header.tsx +37 -3
  38. package/src/components/dashboard/index.tsx +1 -1
  39. package/src/components/dashboard/problems.tsx +57 -46
  40. package/src/components/mobile-player/player.tsx +5 -0
  41. package/src/components/mobile-player/ui/report-modal.tsx +13 -7
  42. package/src/components/mobile-player/ui/viewer-context-menu.tsx +100 -1
  43. package/src/components/ui/button.tsx +10 -13
  44. package/src/components/ui/checkbox.tsx +147 -0
  45. package/src/components/ui/dialog.tsx +319 -99
  46. package/src/components/ui/dropdown.tsx +27 -13
  47. package/src/components/ui/icons.tsx +14 -0
  48. package/src/components/ui/primitives/button.tsx +0 -7
  49. package/src/components/ui/primitives/input.tsx +19 -2
  50. package/src/components/ui/primitives/modal.tsx +4 -2
  51. package/src/components/ui/select.tsx +175 -0
  52. package/src/components/ui/textarea.tsx +47 -29
  53. package/src/components/ui/toast.tsx +785 -179
  54. package/src/components/ui/tooltip.tsx +131 -0
  55. package/src/index.tsx +3 -0
  56. package/src/lib/metadata-constants.ts +180 -0
  57. package/src/lib/theme/theme.tsx +10 -6
  58. package/src/lib/theme/tokens.ts +9 -0
  59. package/src/streamplace-provider/index.tsx +20 -2
  60. package/src/streamplace-store/content-metadata-actions.tsx +142 -0
  61. package/src/streamplace-store/graph.tsx +232 -0
  62. package/src/streamplace-store/streamplace-store.tsx +30 -4
  63. package/src/streamplace-store/user.tsx +71 -7
  64. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useCreateFollowRecord = useCreateFollowRecord;
4
+ exports.useDeleteFollowRecord = useDeleteFollowRecord;
5
+ exports.useGraphManager = useGraphManager;
6
+ const react_1 = require("react");
7
+ const streamplace_store_1 = require("./streamplace-store");
8
+ const xrpc_1 = require("./xrpc");
9
+ function useCreateFollowRecord() {
10
+ let agent = (0, xrpc_1.usePDSAgent)();
11
+ const [isLoading, setIsLoading] = (0, react_1.useState)(false);
12
+ const createFollow = async (subjectDID) => {
13
+ if (!agent) {
14
+ throw new Error("No PDS agent found");
15
+ }
16
+ if (!agent.did) {
17
+ throw new Error("No user DID found, assuming not logged in");
18
+ }
19
+ setIsLoading(true);
20
+ try {
21
+ const record = {
22
+ $type: "app.bsky.graph.follow",
23
+ subject: subjectDID,
24
+ createdAt: new Date().toISOString(),
25
+ };
26
+ const result = await agent.com.atproto.repo.createRecord({
27
+ repo: agent.did,
28
+ collection: "app.bsky.graph.follow",
29
+ record,
30
+ });
31
+ return result;
32
+ }
33
+ finally {
34
+ setIsLoading(false);
35
+ }
36
+ };
37
+ return { createFollow, isLoading };
38
+ }
39
+ function useDeleteFollowRecord() {
40
+ let agent = (0, xrpc_1.usePDSAgent)();
41
+ const [isLoading, setIsLoading] = (0, react_1.useState)(false);
42
+ const deleteFollow = async (followRecordUri) => {
43
+ if (!agent) {
44
+ throw new Error("No PDS agent found");
45
+ }
46
+ if (!agent.did) {
47
+ throw new Error("No user DID found, assuming not logged in");
48
+ }
49
+ setIsLoading(true);
50
+ try {
51
+ const result = await agent.com.atproto.repo.deleteRecord({
52
+ repo: agent.did,
53
+ collection: "app.bsky.graph.follow",
54
+ rkey: followRecordUri.split("/").pop(),
55
+ });
56
+ return result;
57
+ }
58
+ finally {
59
+ setIsLoading(false);
60
+ }
61
+ };
62
+ return { deleteFollow, isLoading };
63
+ }
64
+ function useGraphManager(subjectDID) {
65
+ const agent = (0, xrpc_1.usePDSAgent)();
66
+ const [isFollowing, setIsFollowing] = (0, react_1.useState)(null);
67
+ const [followUri, setFollowUri] = (0, react_1.useState)(null);
68
+ const [isLoading, setIsLoading] = (0, react_1.useState)(false);
69
+ const [error, setError] = (0, react_1.useState)(null);
70
+ const userDID = agent?.did;
71
+ const streamplaceUrl = (0, streamplace_store_1.useStreamplaceStore)((state) => state.url);
72
+ const fetchFollowStatus = async () => {
73
+ if (!userDID || !subjectDID || !streamplaceUrl) {
74
+ setIsFollowing(null);
75
+ setFollowUri(null);
76
+ return;
77
+ }
78
+ setIsLoading(true);
79
+ setError(null);
80
+ try {
81
+ const res = await fetch(`${streamplaceUrl}/xrpc/place.stream.graph.getFollowingUser?subjectDID=${encodeURIComponent(subjectDID)}&userDID=${encodeURIComponent(userDID)}`, {
82
+ credentials: "include",
83
+ });
84
+ if (!res.ok) {
85
+ const errorText = await res.text();
86
+ throw new Error(`Failed to fetch follow status: ${errorText}`);
87
+ }
88
+ const data = await res.json();
89
+ if (data.follow) {
90
+ setIsFollowing(true);
91
+ setFollowUri(data.follow.uri);
92
+ }
93
+ else {
94
+ setIsFollowing(false);
95
+ setFollowUri(null);
96
+ }
97
+ }
98
+ catch (err) {
99
+ setError(`Could not determine follow state: ${err instanceof Error ? err.message : `Unknown error: ${err}`}`);
100
+ setIsFollowing(null);
101
+ }
102
+ finally {
103
+ setIsLoading(false);
104
+ }
105
+ };
106
+ (0, react_1.useEffect)(() => {
107
+ if (!userDID || !subjectDID) {
108
+ setIsFollowing(null);
109
+ setFollowUri(null);
110
+ setError(null);
111
+ return;
112
+ }
113
+ fetchFollowStatus();
114
+ }, [userDID, subjectDID, streamplaceUrl]);
115
+ const follow = async () => {
116
+ if (!agent || !subjectDID) {
117
+ throw new Error("Cannot follow: not logged in or no subject DID");
118
+ }
119
+ if (!agent.did) {
120
+ throw new Error("No user DID found, assuming not logged in");
121
+ }
122
+ setIsLoading(true);
123
+ setError(null);
124
+ const previousState = isFollowing;
125
+ setIsFollowing(true); // Optimistic
126
+ try {
127
+ const record = {
128
+ $type: "app.bsky.graph.follow",
129
+ subject: subjectDID,
130
+ createdAt: new Date().toISOString(),
131
+ };
132
+ const result = await agent.com.atproto.repo.createRecord({
133
+ repo: agent.did,
134
+ collection: "app.bsky.graph.follow",
135
+ record,
136
+ });
137
+ setFollowUri(result.data.uri);
138
+ setIsFollowing(true);
139
+ }
140
+ catch (err) {
141
+ setIsFollowing(previousState);
142
+ const errorMsg = `Failed to follow: ${err instanceof Error ? err.message : "Unknown error"}`;
143
+ setError(errorMsg);
144
+ throw new Error(errorMsg);
145
+ }
146
+ finally {
147
+ setIsLoading(false);
148
+ }
149
+ };
150
+ const unfollow = async () => {
151
+ if (!agent || !subjectDID) {
152
+ throw new Error("Cannot unfollow: not logged in or no subject DID");
153
+ }
154
+ if (!agent.did) {
155
+ throw new Error("No user DID found, assuming not logged in");
156
+ }
157
+ if (!followUri) {
158
+ throw new Error("Cannot unfollow: no follow URI found");
159
+ }
160
+ setIsLoading(true);
161
+ setError(null);
162
+ const previousState = isFollowing;
163
+ const previousUri = followUri;
164
+ setIsFollowing(false); // Optimistic
165
+ setFollowUri(null);
166
+ try {
167
+ await agent.com.atproto.repo.deleteRecord({
168
+ repo: agent.did,
169
+ collection: "app.bsky.graph.follow",
170
+ rkey: followUri.split("/").pop(),
171
+ });
172
+ setIsFollowing(false);
173
+ setFollowUri(null);
174
+ }
175
+ catch (err) {
176
+ setIsFollowing(previousState);
177
+ setFollowUri(previousUri);
178
+ const errorMsg = `Failed to unfollow: ${err instanceof Error ? err.message : "Unknown error"}`;
179
+ setError(errorMsg);
180
+ throw new Error(errorMsg);
181
+ }
182
+ finally {
183
+ setIsLoading(false);
184
+ }
185
+ };
186
+ return {
187
+ isFollowing,
188
+ followUri,
189
+ isLoading,
190
+ error,
191
+ follow,
192
+ unfollow,
193
+ refresh: fetchFollowStatus,
194
+ };
195
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useEffectiveVolume = exports.useSetMuted = exports.useSetVolume = exports.useMuted = exports.useVolume = exports.useSetHandle = exports.useHandle = exports.useDID = exports.useUrl = exports.makeStreamplaceStore = void 0;
3
+ exports.useUpdateStreamRecord = exports.useCreateStreamRecord = exports.useEffectiveVolume = exports.useSetMuted = exports.useSetVolume = exports.useMuted = exports.useVolume = exports.useSetContentMetadata = exports.useContentMetadata = exports.useSetHandle = exports.useHandle = exports.useDID = exports.useUrl = exports.makeStreamplaceStore = void 0;
4
4
  exports.getStreamplaceStoreFromContext = getStreamplaceStoreFromContext;
5
5
  exports.useStreamplaceStore = useStreamplaceStore;
6
6
  const tslib_1 = require("tslib");
@@ -25,6 +25,9 @@ const makeStreamplaceStore = ({ url, }) => {
25
25
  oauthSession: null,
26
26
  handle: null,
27
27
  chatProfile: null,
28
+ // Content metadata
29
+ contentMetadata: null,
30
+ setContentMetadata: (metadata) => set({ contentMetadata: metadata }),
28
31
  // Volume state - start with defaults
29
32
  volume: 1.0,
30
33
  muted: false,
@@ -68,14 +71,13 @@ const makeStreamplaceStore = ({ url, }) => {
68
71
  if (storedMuted) {
69
72
  initialMuted = storedMuted === "true";
70
73
  }
71
- // Update the store with loaded values
72
74
  store.setState({
73
75
  volume: initialVolume,
74
76
  muted: initialMuted,
75
77
  });
76
78
  }
77
- catch (e) {
78
- console.warn("Failed to load volume settings from storage:", e);
79
+ catch (error) {
80
+ console.error("Failed to load volume state from storage:", error);
79
81
  }
80
82
  })();
81
83
  return store;
@@ -102,7 +104,15 @@ const useSetHandle = () => {
102
104
  return (handle) => store.setState({ handle });
103
105
  };
104
106
  exports.useSetHandle = useSetHandle;
105
- // Volume convenience hooks
107
+ // Content metadata hooks
108
+ const useContentMetadata = () => useStreamplaceStore((x) => x.contentMetadata);
109
+ exports.useContentMetadata = useContentMetadata;
110
+ const useSetContentMetadata = () => {
111
+ const store = getStreamplaceStoreFromContext();
112
+ return (metadata) => store.setState({ contentMetadata: metadata });
113
+ };
114
+ exports.useSetContentMetadata = useSetContentMetadata;
115
+ // Volume/muted hooks
106
116
  const useVolume = () => useStreamplaceStore((x) => x.volume);
107
117
  exports.useVolume = useVolume;
108
118
  const useMuted = () => useStreamplaceStore((x) => x.muted);
@@ -118,3 +128,6 @@ const useEffectiveVolume = () => useStreamplaceStore((state) => {
118
128
  return Number.isFinite(effectiveVolume) ? effectiveVolume : 1.0;
119
129
  });
120
130
  exports.useEffectiveVolume = useEffectiveVolume;
131
+ var stream_1 = require("./stream");
132
+ Object.defineProperty(exports, "useCreateStreamRecord", { enumerable: true, get: function () { return stream_1.useCreateStreamRecord; } });
133
+ Object.defineProperty(exports, "useUpdateStreamRecord", { enumerable: true, get: function () { return stream_1.useUpdateStreamRecord; } });
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useGetChatProfile = useGetChatProfile;
4
+ exports.useCreateEmptyChatProfile = useCreateEmptyChatProfile;
4
5
  exports.useGetBskyProfile = useGetBskyProfile;
5
6
  exports.useChatProfile = useChatProfile;
6
7
  const streamplace_1 = require("streamplace");
@@ -10,17 +11,34 @@ function useGetChatProfile() {
10
11
  const did = (0, streamplace_store_1.useDID)();
11
12
  const pdsAgent = (0, xrpc_1.usePDSAgent)();
12
13
  const store = (0, streamplace_store_1.getStreamplaceStoreFromContext)();
14
+ const createEmptyChatProfile = useCreateEmptyChatProfile();
13
15
  return async () => {
14
16
  if (!did || !pdsAgent) {
15
17
  throw new Error("No DID or PDS agent");
16
18
  }
17
- const res = await pdsAgent.com.atproto.repo.getRecord({
18
- repo: did,
19
- collection: "place.stream.chat.profile",
20
- rkey: "self",
21
- });
22
- if (!res.success) {
23
- throw new Error("Failed to get chat profile record");
19
+ let res;
20
+ try {
21
+ res = await pdsAgent.com.atproto.repo.getRecord({
22
+ repo: did,
23
+ collection: "place.stream.chat.profile",
24
+ rkey: "self",
25
+ });
26
+ }
27
+ catch (e) {
28
+ console.error("Failed to get chat profile record, attempting creation", e);
29
+ }
30
+ if (!res || !res.success) {
31
+ try {
32
+ await createEmptyChatProfile();
33
+ res = await pdsAgent.com.atproto.repo.getRecord({
34
+ repo: did,
35
+ collection: "place.stream.chat.profile",
36
+ rkey: "self",
37
+ });
38
+ }
39
+ catch (e) {
40
+ console.error("Failed to create empty chat profile record", e);
41
+ }
24
42
  }
25
43
  if (streamplace_1.PlaceStreamChatProfile.isRecord(res.data.value)) {
26
44
  store.setState({ chatProfile: res.data.value });
@@ -30,6 +48,27 @@ function useGetChatProfile() {
30
48
  }
31
49
  };
32
50
  }
51
+ function useCreateEmptyChatProfile() {
52
+ const did = (0, streamplace_store_1.useDID)();
53
+ const pdsAgent = (0, xrpc_1.usePDSAgent)();
54
+ return async () => {
55
+ if (!did || !pdsAgent) {
56
+ throw new Error("No DID or PDS agent");
57
+ }
58
+ const res = await pdsAgent.com.atproto.repo.putRecord({
59
+ repo: did,
60
+ collection: "place.stream.chat.profile",
61
+ rkey: "self",
62
+ record: {
63
+ $type: "place.stream.chat.profile",
64
+ color: DEFAULT_COLORS[Math.floor(Math.random() * DEFAULT_COLORS.length)],
65
+ },
66
+ });
67
+ if (!res.success) {
68
+ throw new Error("Failed to create empty chat profile record");
69
+ }
70
+ };
71
+ }
33
72
  function useGetBskyProfile() {
34
73
  const did = (0, streamplace_store_1.useDID)();
35
74
  const pdsAgent = (0, xrpc_1.usePDSAgent)();
@@ -50,3 +89,24 @@ function useGetBskyProfile() {
50
89
  function useChatProfile() {
51
90
  return (0, streamplace_store_1.useStreamplaceStore)((x) => x.chatProfile);
52
91
  }
92
+ const DEFAULT_COLORS = [
93
+ { red: 244, green: 67, blue: 54 },
94
+ { red: 233, green: 30, blue: 99 },
95
+ { red: 156, green: 39, blue: 176 },
96
+ { red: 103, green: 58, blue: 183 },
97
+ { red: 63, green: 81, blue: 181 },
98
+ { red: 33, green: 150, blue: 243 },
99
+ { red: 3, green: 169, blue: 244 },
100
+ { red: 0, green: 188, blue: 212 },
101
+ { red: 0, green: 150, blue: 136 },
102
+ { red: 76, green: 175, blue: 80 },
103
+ { red: 139, green: 195, blue: 74 },
104
+ { red: 205, green: 220, blue: 57 },
105
+ { red: 255, green: 235, blue: 59 },
106
+ { red: 255, green: 193, blue: 7 },
107
+ { red: 255, green: 152, blue: 0 },
108
+ { red: 255, green: 87, blue: 34 },
109
+ { red: 121, green: 85, blue: 72 },
110
+ { red: 158, green: 158, blue: 158 },
111
+ { red: 96, green: 125, blue: 139 },
112
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamplace/components",
3
- "version": "0.7.34",
3
+ "version": "0.8.0",
4
4
  "description": "Streamplace React (Native) Components",
5
5
  "main": "dist/index.js",
6
6
  "types": "src/index.tsx",
@@ -42,7 +42,7 @@
42
42
  "react-native-svg": "^15.0.0",
43
43
  "react-native-webrtc": "git+https://github.com/streamplace/react-native-webrtc.git#6b8472a771ac47f89217d327058a8a4124a6ae56",
44
44
  "react-use-websocket": "^4.13.0",
45
- "streamplace": "0.7.25",
45
+ "streamplace": "0.8.0",
46
46
  "viem": "^2.21.44",
47
47
  "zustand": "^5.0.5"
48
48
  },
@@ -54,5 +54,5 @@
54
54
  "start": "tsc --watch --preserveWatchOutput",
55
55
  "prepare": "tsc"
56
56
  },
57
- "gitHead": "8d33e4f6129af71ccf3c5d959e347f78b6eb609a"
57
+ "gitHead": "cb213f8cc49fc200aaf853a1f84d4ee1a6f69a9c"
58
58
  }