@streamplace/components 0.7.14 → 0.7.17

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 (123) hide show
  1. package/package.json +13 -15
  2. package/src/components/mobile-player/fullscreen.native.tsx +14 -3
  3. package/src/components/mobile-player/fullscreen.tsx +10 -2
  4. package/src/components/mobile-player/player.tsx +7 -1
  5. package/src/components/mobile-player/props.tsx +7 -0
  6. package/src/components/mobile-player/video-async.native.tsx +436 -0
  7. package/src/components/mobile-player/video.native.tsx +16 -406
  8. package/src/components/mobile-player/video.tsx +14 -3
  9. package/src/hooks/useLivestreamInfo.ts +6 -2
  10. package/src/lib/browser.ts +27 -0
  11. package/src/livestream-store/stream-key.tsx +1 -28
  12. package/src/streamplace-store/stream.tsx +52 -13
  13. package/dist/assets/emoji-data.json +0 -19371
  14. package/dist/components/chat/chat-box.js +0 -314
  15. package/dist/components/chat/chat-message.js +0 -87
  16. package/dist/components/chat/chat.js +0 -149
  17. package/dist/components/chat/emoji-suggestions.js +0 -35
  18. package/dist/components/chat/mention-suggestions.js +0 -42
  19. package/dist/components/chat/mod-view.js +0 -94
  20. package/dist/components/chat/system-message.js +0 -19
  21. package/dist/components/dashboard/chat-panel.js +0 -38
  22. package/dist/components/dashboard/header.js +0 -80
  23. package/dist/components/dashboard/index.js +0 -14
  24. package/dist/components/dashboard/information-widget.js +0 -234
  25. package/dist/components/dashboard/mod-actions.js +0 -71
  26. package/dist/components/dashboard/problems.js +0 -74
  27. package/dist/components/icons/bluesky-icon.js +0 -9
  28. package/dist/components/keep-awake.js +0 -7
  29. package/dist/components/keep-awake.native.js +0 -16
  30. package/dist/components/mobile-player/fullscreen.js +0 -74
  31. package/dist/components/mobile-player/fullscreen.native.js +0 -141
  32. package/dist/components/mobile-player/player.js +0 -94
  33. package/dist/components/mobile-player/props.js +0 -2
  34. package/dist/components/mobile-player/shared.js +0 -54
  35. package/dist/components/mobile-player/ui/countdown.js +0 -83
  36. package/dist/components/mobile-player/ui/index.js +0 -11
  37. package/dist/components/mobile-player/ui/input.js +0 -42
  38. package/dist/components/mobile-player/ui/metrics.js +0 -44
  39. package/dist/components/mobile-player/ui/report-modal.js +0 -90
  40. package/dist/components/mobile-player/ui/streamer-context-menu.js +0 -7
  41. package/dist/components/mobile-player/ui/streamer-loading-overlay.js +0 -104
  42. package/dist/components/mobile-player/ui/viewer-context-menu.js +0 -51
  43. package/dist/components/mobile-player/ui/viewer-loading-overlay.js +0 -49
  44. package/dist/components/mobile-player/ui/viewers.js +0 -23
  45. package/dist/components/mobile-player/use-webrtc.js +0 -243
  46. package/dist/components/mobile-player/video-retry.js +0 -29
  47. package/dist/components/mobile-player/video.js +0 -460
  48. package/dist/components/mobile-player/video.native.js +0 -276
  49. package/dist/components/mobile-player/webrtc-diagnostics.js +0 -110
  50. package/dist/components/mobile-player/webrtc-primitives.js +0 -27
  51. package/dist/components/mobile-player/webrtc-primitives.native.js +0 -8
  52. package/dist/components/share/sharesheet.js +0 -91
  53. package/dist/components/ui/button.js +0 -223
  54. package/dist/components/ui/dialog.js +0 -206
  55. package/dist/components/ui/dropdown.js +0 -172
  56. package/dist/components/ui/icons.js +0 -25
  57. package/dist/components/ui/index.js +0 -34
  58. package/dist/components/ui/info-box.js +0 -31
  59. package/dist/components/ui/info-row.js +0 -23
  60. package/dist/components/ui/input.js +0 -205
  61. package/dist/components/ui/loader.js +0 -10
  62. package/dist/components/ui/primitives/button.js +0 -125
  63. package/dist/components/ui/primitives/input.js +0 -206
  64. package/dist/components/ui/primitives/modal.js +0 -206
  65. package/dist/components/ui/primitives/text.js +0 -292
  66. package/dist/components/ui/resizeable.js +0 -121
  67. package/dist/components/ui/slider.js +0 -5
  68. package/dist/components/ui/text.js +0 -177
  69. package/dist/components/ui/textarea.js +0 -19
  70. package/dist/components/ui/toast.js +0 -175
  71. package/dist/components/ui/view.js +0 -252
  72. package/dist/hooks/index.js +0 -14
  73. package/dist/hooks/useAvatars.js +0 -35
  74. package/dist/hooks/useCameraToggle.js +0 -12
  75. package/dist/hooks/useKeyboard.js +0 -36
  76. package/dist/hooks/useKeyboardSlide.js +0 -14
  77. package/dist/hooks/useLivestreamInfo.js +0 -65
  78. package/dist/hooks/useOuterAndInnerDimensions.js +0 -30
  79. package/dist/hooks/usePlayerDimensions.js +0 -22
  80. package/dist/hooks/usePointerDevice.js +0 -71
  81. package/dist/hooks/useSegmentDimensions.js +0 -17
  82. package/dist/hooks/useSegmentTiming.js +0 -65
  83. package/dist/index.js +0 -34
  84. package/dist/lib/facet.js +0 -92
  85. package/dist/lib/system-messages.js +0 -101
  86. package/dist/lib/theme/atoms.js +0 -646
  87. package/dist/lib/theme/atoms.types.js +0 -6
  88. package/dist/lib/theme/index.js +0 -35
  89. package/dist/lib/theme/theme.js +0 -256
  90. package/dist/lib/theme/tokens.js +0 -659
  91. package/dist/lib/utils.js +0 -105
  92. package/dist/livestream-provider/index.js +0 -30
  93. package/dist/livestream-provider/websocket.js +0 -45
  94. package/dist/livestream-store/chat.js +0 -286
  95. package/dist/livestream-store/context.js +0 -5
  96. package/dist/livestream-store/index.js +0 -7
  97. package/dist/livestream-store/livestream-state.js +0 -2
  98. package/dist/livestream-store/livestream-store.js +0 -58
  99. package/dist/livestream-store/problems.js +0 -76
  100. package/dist/livestream-store/stream-key.js +0 -119
  101. package/dist/livestream-store/websocket-consumer.js +0 -94
  102. package/dist/player-store/context.js +0 -5
  103. package/dist/player-store/index.js +0 -9
  104. package/dist/player-store/player-provider.js +0 -57
  105. package/dist/player-store/player-state.js +0 -25
  106. package/dist/player-store/player-store.js +0 -199
  107. package/dist/player-store/single-player-provider.js +0 -121
  108. package/dist/streamplace-provider/context.js +0 -5
  109. package/dist/streamplace-provider/index.js +0 -20
  110. package/dist/streamplace-provider/poller.js +0 -49
  111. package/dist/streamplace-provider/xrpc.js +0 -0
  112. package/dist/streamplace-store/block.js +0 -65
  113. package/dist/streamplace-store/index.js +0 -6
  114. package/dist/streamplace-store/stream.js +0 -218
  115. package/dist/streamplace-store/streamplace-store.js +0 -47
  116. package/dist/streamplace-store/user.js +0 -52
  117. package/dist/streamplace-store/xrpc.js +0 -15
  118. package/dist/ui/index.js +0 -79
  119. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  120. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/56540125 +0 -0
  121. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/67b1eb60 +0 -0
  122. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/7c275f90 +0 -0
  123. package/tsconfig.tsbuildinfo +0 -1
@@ -1,314 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ChatBox = ChatBox;
4
- const tslib_1 = require("tslib");
5
- const jsx_runtime_1 = require("react/jsx-runtime");
6
- const react_1 = tslib_1.__importDefault(require("@emoji-mart/react"));
7
- const lucide_react_native_1 = require("lucide-react-native");
8
- const react_2 = require("react");
9
- const react_native_1 = require("react-native");
10
- const __1 = require("../../");
11
- const atoms_1 = require("../../lib/theme/atoms");
12
- const xrpc_1 = require("../../streamplace-store/xrpc");
13
- const textarea_1 = require("../ui/textarea");
14
- const chat_message_1 = require("./chat-message");
15
- const emoji_suggestions_1 = require("./emoji-suggestions");
16
- const mention_suggestions_1 = require("./mention-suggestions");
17
- const COOL_EMOJI_LIST = [
18
- ..."😀🥸😍😘😁🥸😆🥸😜🥸😂😅🥸🙂🤫😱🥸🤣😗😄🥸😎🤓😲😯😰🥸😥🥸😣🥸😞😓🥸😩😩🥸😤🥱",
19
- ];
20
- function ChatBox({ isPopout, chatBoxStyle, emojiData, setIsChatVisible, }) {
21
- const [submitting, setSubmitting] = (0, react_2.useState)(false);
22
- const [message, setMessage] = (0, react_2.useState)("");
23
- const [showSuggestions, setShowSuggestions] = (0, react_2.useState)(false);
24
- const [showEmojiSuggestions, setShowEmojiSuggestions] = (0, react_2.useState)(false);
25
- const [showEmojiSelector, setShowEmojiSelector] = (0, react_2.useState)(false);
26
- const [emojiIconIndex, setEmojiIconIndex] = (0, react_2.useState)(Math.floor(Math.random() * COOL_EMOJI_LIST.length));
27
- const [highlightedIndex, setHighlightedIndex] = (0, react_2.useState)(0);
28
- const [filteredAuthors, setFilteredAuthors] = (0, react_2.useState)(new Map());
29
- const [filteredEmojis, setFilteredEmojis] = (0, react_2.useState)([]);
30
- let linfo = (0, __1.useLivestream)();
31
- const chat = (0, __1.useChat)();
32
- const createChatMessage = (0, __1.useCreateChatMessage)();
33
- const replyTo = (0, __1.useReplyToMessage)();
34
- const setReplyToMessage = (0, __1.useSetReplyToMessage)();
35
- const textAreaRef = (0, react_2.useRef)(null);
36
- // are we logged in?
37
- let agent = (0, xrpc_1.usePDSAgent)();
38
- if (!agent?.did) {
39
- (0, jsx_runtime_1.jsx)(__1.View, { style: [atoms_1.layout.flex.row, atoms_1.layout.flex.alignCenter, atoms_1.gap.all[2]], children: (0, jsx_runtime_1.jsx)(__1.Text, { children: "Log in to chat." }) });
40
- }
41
- const authors = (0, react_2.useMemo)(() => {
42
- if (!chat)
43
- return null;
44
- return chat.reduce((acc, msg) => {
45
- acc.set(msg.author.handle, msg.chatProfile);
46
- return acc;
47
- }, new Map());
48
- }, [chat]);
49
- const handleMentionSelect = (handle) => {
50
- const beforeAt = message.slice(0, message.lastIndexOf("@"));
51
- setMessage(`${beforeAt}@${handle} `);
52
- setShowSuggestions(false);
53
- };
54
- const handleEmojiSelect = (emoji) => {
55
- const beforeColon = message.slice(0, message.lastIndexOf(":"));
56
- setMessage(`${beforeColon}${emoji.skins[0]?.native} `);
57
- setShowEmojiSuggestions(false);
58
- };
59
- const updateSuggestions = (text) => {
60
- // Handle mentions
61
- const atIndex = text.lastIndexOf("@");
62
- if (atIndex !== -1 && authors) {
63
- const searchText = text.slice(atIndex + 1).toLowerCase();
64
- const filteredAuthorsMap = new Map(Array.from(authors.entries()).filter(([handle]) => handle.toLowerCase().includes(searchText)));
65
- setFilteredAuthors(filteredAuthorsMap);
66
- setHighlightedIndex(0);
67
- setShowSuggestions(filteredAuthorsMap.size > 0);
68
- setShowEmojiSuggestions(false);
69
- }
70
- else {
71
- setShowSuggestions(false);
72
- }
73
- const colonIndex = text.lastIndexOf(":");
74
- if (colonIndex !== -1) {
75
- const searchText = text.slice(colonIndex + 1).toLowerCase();
76
- if (searchText.length > 0) {
77
- const aliasMatches = Object.entries(emojiData.aliases)
78
- .map(([alias, emojiId]) => {
79
- const aliasLower = alias.toLowerCase();
80
- if (aliasLower === searchText) {
81
- return { emojiId, alias, matchType: 0, index: 0 };
82
- }
83
- else if (aliasLower.startsWith(searchText)) {
84
- return { emojiId, alias, matchType: 1, index: 0 };
85
- }
86
- else if (aliasLower.includes(searchText)) {
87
- return {
88
- emojiId,
89
- alias,
90
- matchType: 2,
91
- index: aliasLower.indexOf(searchText),
92
- }; // includes
93
- }
94
- return null;
95
- })
96
- .filter(Boolean);
97
- // Map emojiId to best alias match info
98
- const bestAliasMatch = {};
99
- for (const match of aliasMatches) {
100
- if (!match)
101
- continue;
102
- const prev = bestAliasMatch[match.emojiId];
103
- if (!prev ||
104
- match?.matchType < prev.matchType ||
105
- (match.matchType === prev.matchType && match.index < prev.index)) {
106
- bestAliasMatch[match.emojiId] = match;
107
- }
108
- }
109
- // Collect all matching emojis by id, name, keywords, or alias
110
- const allEmojis = Object.values(emojiData.emojis);
111
- const filtered = allEmojis
112
- .map((emoji) => {
113
- // Check alias match
114
- const aliasMatch = bestAliasMatch[emoji.id];
115
- if (aliasMatch) {
116
- return {
117
- emoji,
118
- sort: [aliasMatch.matchType, aliasMatch.index, 0],
119
- };
120
- }
121
- // Check id, name, keywords
122
- if (emoji.id.toLowerCase() === searchText) {
123
- return { emoji, sort: [3, 0, 0] }; // exact id
124
- }
125
- if (emoji.id.toLowerCase().startsWith(searchText)) {
126
- return { emoji, sort: [4, 0, 0] }; // startsWith id
127
- }
128
- if (emoji.id.toLowerCase().includes(searchText)) {
129
- return {
130
- emoji,
131
- sort: [5, emoji.id.toLowerCase().indexOf(searchText), 0],
132
- }; // includes id
133
- }
134
- if (emoji.name.toLowerCase().includes(searchText)) {
135
- return {
136
- emoji,
137
- sort: [6, emoji.name.toLowerCase().indexOf(searchText), 0],
138
- };
139
- }
140
- if (emoji.keywords &&
141
- emoji.keywords.some((keyword) => keyword.toLowerCase().includes(searchText))) {
142
- return { emoji, sort: [7, 0, 0] };
143
- }
144
- return null;
145
- })
146
- .filter(Boolean)
147
- // Remove duplicates by emoji id (keep best match)
148
- .reduce((acc, curr) => {
149
- if (!acc.find((e) => e.emoji.id === curr.emoji.id)) {
150
- acc.push(curr);
151
- }
152
- return acc;
153
- }, [])
154
- // Sort by alias match type, then position, then fallback
155
- .sort((a, b) => {
156
- for (let i = 0; i < a.sort.length; ++i) {
157
- if (a.sort[i] !== b.sort[i])
158
- return a.sort[i] - b.sort[i];
159
- }
160
- return 0;
161
- })
162
- .slice(0, 10) // Limit to 10 results
163
- .map((entry) => entry.emoji);
164
- setFilteredEmojis(filtered);
165
- setHighlightedIndex(0);
166
- setShowEmojiSuggestions(filtered.length > 0);
167
- setShowSuggestions(false);
168
- }
169
- else {
170
- setShowEmojiSuggestions(false);
171
- }
172
- }
173
- else {
174
- setShowEmojiSuggestions(false);
175
- }
176
- // If neither mention nor emoji, hide all suggestions
177
- if (atIndex === -1 && colonIndex === -1) {
178
- setShowSuggestions(false);
179
- setShowEmojiSuggestions(false);
180
- }
181
- };
182
- const submit = () => {
183
- if (!message.trim())
184
- return;
185
- setMessage("");
186
- setReplyToMessage(null);
187
- setSubmitting(true);
188
- createChatMessage({
189
- text: message,
190
- reply: replyTo || undefined,
191
- });
192
- setSubmitting(false);
193
- // if we press "send" button, we want the same action as pressing "Enter"
194
- // if we're already focused no need to do extra work
195
- if (textAreaRef.current && !textAreaRef.current.isFocused()) {
196
- textAreaRef.current.focus();
197
- requestAnimationFrame(() => {
198
- textAreaRef.current?.focus();
199
- });
200
- }
201
- };
202
- (0, react_2.useEffect)(() => {
203
- if (replyTo && textAreaRef.current) {
204
- textAreaRef.current.focus();
205
- }
206
- }, [replyTo]);
207
- return ((0, jsx_runtime_1.jsxs)(__1.View, { style: [atoms_1.layout.flex.column, atoms_1.flex.shrink[1], atoms_1.gap.all[2]], children: [replyTo && ((0, jsx_runtime_1.jsxs)(__1.View, { style: [
208
- atoms_1.layout.flex.row,
209
- atoms_1.layout.flex.alignCenter,
210
- atoms_1.layout.flex.spaceBetween,
211
- atoms_1.pl[2],
212
- atoms_1.pr[6],
213
- atoms_1.mr[6],
214
- atoms_1.mb[2],
215
- atoms_1.py[1],
216
- atoms_1.bg.gray[800],
217
- { borderRadius: 16 },
218
- ], children: [(0, jsx_runtime_1.jsx)(chat_message_1.RenderChatMessage, { item: replyTo, showReply: false, userCache: authors || new Map() }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => setReplyToMessage(null), children: (0, jsx_runtime_1.jsx)(__1.View, { style: [
219
- atoms_1.layout.flex.row,
220
- atoms_1.layout.flex.alignCenter,
221
- atoms_1.layout.flex.justifyCenter,
222
- atoms_1.h[12],
223
- atoms_1.w[12],
224
- atoms_1.bg.gray[600],
225
- { borderRadius: 999 },
226
- ], children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.X, { size: 24 }) }) })] })), showEmojiSelector && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: {
227
- position: "absolute",
228
- top: 0,
229
- left: 0,
230
- right: 0,
231
- bottom: 0,
232
- zIndex: 200,
233
- }, onPress: () => setShowEmojiSelector(false) }), (0, jsx_runtime_1.jsx)(__1.View, { style: {
234
- position: "absolute",
235
- bottom: "100%",
236
- left: 0,
237
- zIndex: 2001,
238
- }, children: (0, jsx_runtime_1.jsx)(react_1.default, { data: emojiData, onEmojiSelect: (e) => setMessage(message + e.native) }) })] })), (0, jsx_runtime_1.jsxs)(__1.View, { style: [atoms_1.layout.flex.row, atoms_1.layout.flex.alignCenter, atoms_1.gap.all[2]], children: [(0, jsx_runtime_1.jsx)(textarea_1.Textarea, { ref: textAreaRef, numberOfLines: 1, value: message, enterKeyHint: "send", onSubmitEditing: (e) => {
239
- e.preventDefault();
240
- submit();
241
- }, multiline: false, onChangeText: (text) => {
242
- setMessage(text);
243
- updateSuggestions(text);
244
- }, onKeyPress: (k) => {
245
- if (k.nativeEvent.key === "Enter") {
246
- if (showSuggestions) {
247
- k.preventDefault();
248
- const handles = Array.from(filteredAuthors.keys());
249
- if (handles.length > 0) {
250
- handleMentionSelect(handles[highlightedIndex]);
251
- }
252
- }
253
- else if (showEmojiSuggestions) {
254
- k.preventDefault();
255
- if (filteredEmojis.length > 0) {
256
- handleEmojiSelect(filteredEmojis[highlightedIndex]);
257
- }
258
- }
259
- else {
260
- k.preventDefault();
261
- submit();
262
- }
263
- }
264
- else if (k.nativeEvent.key === "ArrowUp") {
265
- if (showSuggestions || showEmojiSuggestions) {
266
- k.preventDefault();
267
- setHighlightedIndex((prev) => Math.max(prev - 1, 0));
268
- }
269
- }
270
- else if (k.nativeEvent.key === "ArrowDown") {
271
- if (showSuggestions) {
272
- k.preventDefault();
273
- setHighlightedIndex((prev) => Math.min(prev + 1, Array.from(filteredAuthors.keys()).length - 1));
274
- }
275
- else if (showEmojiSuggestions) {
276
- k.preventDefault();
277
- setHighlightedIndex((prev) => Math.min(prev + 1, filteredEmojis.length - 1));
278
- }
279
- }
280
- else if (k.nativeEvent.key === "Escape") {
281
- if (showSuggestions || showEmojiSuggestions) {
282
- k.preventDefault();
283
- setShowSuggestions(false);
284
- setShowEmojiSuggestions(false);
285
- }
286
- }
287
- }, style: [chatBoxStyle],
288
- // "submit" won't blur on enter
289
- submitBehavior: "submit", placeholder: "Type a message..." }), (0, jsx_runtime_1.jsx)(__1.Button, { disabled: submitting, variant: "secondary", style: { borderRadius: 16, height: 36, minWidth: 80 }, onPress: submit, children: submitting ? (0, jsx_runtime_1.jsx)(__1.Loader, {}) : "Send" })] }), showSuggestions && ((0, jsx_runtime_1.jsx)(mention_suggestions_1.MentionSuggestions, { authors: filteredAuthors || new Map(), highlightedIndex: highlightedIndex, onSelect: handleMentionSelect })), showEmojiSuggestions && ((0, jsx_runtime_1.jsx)(emoji_suggestions_1.EmojiSuggestions, { emojis: filteredEmojis, highlightedIndex: highlightedIndex, onSelect: handleEmojiSelect })), react_native_1.Platform.OS === "web" && ((0, jsx_runtime_1.jsxs)(__1.View, { style: [
290
- atoms_1.layout.flex.row,
291
- atoms_1.mb[2],
292
- atoms_1.gap.all[2],
293
- { justifyContent: "flex-end" },
294
- ], children: [(0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16, height: 36, maxWidth: 36 }, onPress: () => {
295
- // if the last character is not @, add it
296
- !message.endsWith("@") && setMessage(message + "@");
297
- // get all the text after the last @
298
- const atIndex = message.lastIndexOf("@");
299
- const searchText = message.slice(atIndex + 1).toLowerCase();
300
- updateSuggestions(searchText);
301
- setShowSuggestions(true);
302
- // focus the textarea
303
- textAreaRef.current?.focus();
304
- }, children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.AtSignIcon, { size: 20, color: "white" }) }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onHoverOut: () => {
305
- setEmojiIconIndex(Math.floor(Math.random() * COOL_EMOJI_LIST.length));
306
- }, children: (0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16, height: 36, maxWidth: 36 }, onPress: () => setShowEmojiSelector(!showEmojiSelector), children: (0, jsx_runtime_1.jsx)(__1.Text, { children: COOL_EMOJI_LIST[emojiIconIndex] }) }) }), !isPopout && ((0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16, height: 36, maxWidth: 36 }, onPress: () => {
307
- if (!linfo)
308
- return;
309
- const u = new URL(window.location.href);
310
- u.pathname = `/chat-popout/${linfo?.author?.did}`;
311
- window.open(u.toString(), "_blank", "popup=true");
312
- setIsChatVisible?.(false);
313
- }, children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.ExternalLink, { size: 16 }) }))] }))] }));
314
- }
@@ -1,87 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RenderChatMessage = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
6
- const react_native_1 = require("react-native");
7
- const facet_1 = require("../../lib/facet");
8
- const atoms_1 = require("../../lib/theme/atoms");
9
- const ui_1 = require("../ui");
10
- const livestream_store_1 = require("../../livestream-store");
11
- const text_1 = require("../ui/text");
12
- const getRgbColor = (color) => color ? `rgb(${color.red}, ${color.green}, ${color.blue})` : ui_1.colors.gray[500];
13
- const segmentedObject = (obj, index, userCache) => {
14
- if (obj.features && obj.features.length > 0) {
15
- let ftr = obj.features[0];
16
- // afaik there shouldn't be a case where facets overlap, at least currently
17
- if (ftr.$type === "app.bsky.richtext.facet#link") {
18
- let linkftr = ftr;
19
- return ((0, jsx_runtime_1.jsx)(text_1.Text, { style: [{ color: ui_1.atoms.colors.ios.systemBlue, cursor: "pointer" }], onPress: () => react_native_1.Linking.openURL(linkftr.uri || ""), children: obj.text }, `mention-${index}`));
20
- }
21
- else if (ftr.$type === "app.bsky.richtext.facet#mention") {
22
- let mtnftr = ftr;
23
- const profile = userCache?.[mtnftr.did];
24
- return ((0, jsx_runtime_1.jsx)(text_1.Text, { style: [
25
- {
26
- cursor: "pointer",
27
- color: getRgbColor(profile?.color),
28
- },
29
- ], onPress: () => react_native_1.Linking.openURL(`https://bsky.app/profile/${mtnftr.did || ""}`), children: obj.text }, `mention-${index}`));
30
- }
31
- }
32
- else {
33
- return (0, jsx_runtime_1.jsx)(text_1.Text, { children: obj.text }, `text-${index}`);
34
- }
35
- };
36
- const RichTextMessage = ({ text, facets, }) => {
37
- if (!facets?.length)
38
- return (0, jsx_runtime_1.jsx)(text_1.Text, { children: text });
39
- const userCache = (0, livestream_store_1.useLivestreamStore)((state) => state.authors);
40
- let segs = (0, facet_1.segmentize)(text, facets);
41
- return segs.map((seg, i) => segmentedObject(seg, i, userCache));
42
- };
43
- exports.RenderChatMessage = (0, react_1.memo)(function RenderChatMessage({ item, showReply = true, showTime = true, }) {
44
- const formatTime = (0, react_1.useCallback)((dateString) => {
45
- return new Date(dateString).toLocaleString(undefined, {
46
- hour: "2-digit",
47
- minute: "2-digit",
48
- hour12: false,
49
- });
50
- }, []);
51
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [item.replyTo && showReply && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [
52
- atoms_1.gap.all[2],
53
- ui_1.layout.flex.row,
54
- { minWidth: 0, maxWidth: "100%" },
55
- atoms_1.borders.left.width.medium,
56
- atoms_1.borders.left.color.gray[700],
57
- atoms_1.ml[4],
58
- atoms_1.pl[4],
59
- atoms_1.opacity[80],
60
- ], children: (0, jsx_runtime_1.jsxs)(text_1.Text, { numberOfLines: 1, style: [
61
- atoms_1.flex.shrink[1],
62
- atoms_1.mr[4],
63
- { minWidth: 0, overflow: "hidden" },
64
- ], children: [(0, jsx_runtime_1.jsxs)(text_1.Text, { style: {
65
- color: getRgbColor(item.replyTo.chatProfile.color),
66
- fontWeight: "thin",
67
- }, children: ["@", item.replyTo.author.handle] }), " ", (0, jsx_runtime_1.jsx)(text_1.Text, { style: {
68
- color: ui_1.colors.gray[300],
69
- fontStyle: "italic",
70
- }, children: item.replyTo.record.text })] }) })), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
71
- atoms_1.gap.all[2],
72
- ui_1.layout.flex.row,
73
- { minWidth: 0, maxWidth: "100%" },
74
- ], children: [showTime && ((0, jsx_runtime_1.jsx)(text_1.Text, { style: {
75
- fontVariant: ["tabular-nums"],
76
- color: ui_1.colors.gray[400],
77
- }, children: formatTime(item.record.createdAt) })), (0, jsx_runtime_1.jsxs)(text_1.Text, { weight: "bold", color: "default", style: [atoms_1.flex.shrink[1], { minWidth: 0, overflow: "hidden" }], children: [(0, jsx_runtime_1.jsxs)(text_1.Text, { style: [
78
- {
79
- cursor: "pointer",
80
- color: getRgbColor(item.chatProfile?.color),
81
- },
82
- ], children: ["@", item.author.handle] }), ":", " ", (0, jsx_runtime_1.jsx)(RichTextMessage, { text: item.record.text, facets: item.record.facets || [] })] })] })] }));
83
- }, (prevProps, nextProps) => {
84
- return (prevProps.item.author.handle === nextProps.item.author.handle &&
85
- prevProps.item.record.text === nextProps.item.record.text &&
86
- prevProps.item.uri === nextProps.item.uri);
87
- });
@@ -1,149 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Chat = Chat;
4
- const tslib_1 = require("tslib");
5
- const jsx_runtime_1 = require("react/jsx-runtime");
6
- const lucide_react_native_1 = require("lucide-react-native");
7
- const react_1 = require("react");
8
- const react_native_1 = require("react-native");
9
- const ReanimatedSwipeable_1 = tslib_1.__importDefault(require("react-native-gesture-handler/ReanimatedSwipeable"));
10
- const react_native_reanimated_1 = tslib_1.__importStar(require("react-native-reanimated"));
11
- const __1 = require("../../");
12
- const atoms_1 = require("../../lib/theme/atoms");
13
- const chat_message_1 = require("./chat-message");
14
- const mod_view_1 = require("./mod-view");
15
- function RightAction(prog, drag) {
16
- const styleAnimation = (0, react_native_reanimated_1.useAnimatedStyle)(() => {
17
- return {
18
- transform: [{ translateX: drag.value + 25 }],
19
- };
20
- });
21
- return ((0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [styleAnimation], children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.Reply, { color: "white" }) }));
22
- }
23
- function LeftAction(prog, drag) {
24
- const styleAnimation = (0, react_native_reanimated_1.useAnimatedStyle)(() => {
25
- return {
26
- transform: [{ translateX: drag.value - 25 }],
27
- };
28
- });
29
- return ((0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [styleAnimation], children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.ShieldEllipsis, { color: "white" }) }));
30
- }
31
- // ios/android, 25, else 100 msgs
32
- const SHOWN_MSGS = react_native_1.Platform.OS === "ios" || react_native_1.Platform.OS === "android" ? 25 : 100;
33
- const keyExtractor = (item, index) => {
34
- return `${item.uri}`;
35
- };
36
- // Actions bar for larger screens
37
- const ActionsBar = (0, react_1.memo)(({ item, visible, hoverTimeoutRef, }) => {
38
- const setReply = (0, __1.useSetReplyToMessage)();
39
- const setModMsg = (0, __1.usePlayerStore)((state) => state.setModMessage);
40
- if (!visible)
41
- return null;
42
- return ((0, jsx_runtime_1.jsxs)(__1.View, { style: [
43
- {
44
- position: "absolute",
45
- top: -14,
46
- right: 8,
47
- flexDirection: "row",
48
- backgroundColor: "rgba(180,180,180, 0.5)",
49
- borderRadius: 6,
50
- borderWidth: 1,
51
- padding: 1,
52
- gap: 4,
53
- zIndex: 10,
54
- maxWidth: 120,
55
- flexShrink: 0,
56
- },
57
- ], children: [(0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => setReply(item), style: [
58
- {
59
- padding: 6,
60
- borderRadius: 4,
61
- backgroundColor: "rgba(255, 255, 255, 0.1)",
62
- },
63
- ], onHoverIn: () => {
64
- // Keep the actions bar visible when hovering over it
65
- if (hoverTimeoutRef.current) {
66
- clearTimeout(hoverTimeoutRef.current);
67
- hoverTimeoutRef.current = null;
68
- }
69
- }, children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.Reply, { color: "white", size: 16 }) }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => setModMsg(item), style: [
70
- {
71
- padding: 6,
72
- borderRadius: 4,
73
- backgroundColor: "rgba(255, 255, 255, 0.1)",
74
- },
75
- ], onHoverIn: () => {
76
- // Keep the actions bar visible when hovering over it
77
- if (hoverTimeoutRef.current) {
78
- clearTimeout(hoverTimeoutRef.current);
79
- hoverTimeoutRef.current = null;
80
- }
81
- }, children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.Ellipsis, { color: "white", size: 16 }) })] }));
82
- });
83
- const ChatLine = (0, react_1.memo)(({ item, canModerate, }) => {
84
- const setReply = (0, __1.useSetReplyToMessage)();
85
- const setModMsg = (0, __1.usePlayerStore)((state) => state.setModMessage);
86
- const swipeableRef = (0, react_1.useRef)(null);
87
- const [isHovered, setIsHovered] = (0, react_1.useState)(false);
88
- const hoverTimeoutRef = (0, react_1.useRef)(null);
89
- const handleHoverIn = () => {
90
- if (hoverTimeoutRef.current) {
91
- clearTimeout(hoverTimeoutRef.current);
92
- hoverTimeoutRef.current = null;
93
- }
94
- setIsHovered(true);
95
- };
96
- const handleHoverOut = () => {
97
- hoverTimeoutRef.current = setTimeout(() => {
98
- setIsHovered(false);
99
- }, 50);
100
- };
101
- (0, react_1.useEffect)(() => {
102
- return () => {
103
- if (hoverTimeoutRef.current) {
104
- clearTimeout(hoverTimeoutRef.current);
105
- }
106
- };
107
- }, []);
108
- if (item.author.did === "did:sys:system") {
109
- return ((0, jsx_runtime_1.jsx)(__1.SystemMessage, { timestamp: new Date(item.record.createdAt), title: item.record.text }));
110
- }
111
- if (react_native_1.Platform.OS === "web") {
112
- return ((0, jsx_runtime_1.jsxs)(__1.View, { style: [
113
- atoms_1.py[1],
114
- atoms_1.px[2],
115
- {
116
- position: "relative",
117
- borderRadius: 8,
118
- minWidth: 0,
119
- maxWidth: "100%",
120
- },
121
- isHovered && atoms_1.bg.gray[950],
122
- ], onPointerEnter: handleHoverIn, onPointerLeave: handleHoverOut, children: [(0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: [{ minWidth: 0, maxWidth: "100%" }], children: (0, jsx_runtime_1.jsx)(chat_message_1.RenderChatMessage, { item: item }) }), (0, jsx_runtime_1.jsx)(ActionsBar, { item: item, visible: isHovered, hoverTimeoutRef: hoverTimeoutRef })] }));
123
- }
124
- return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(ReanimatedSwipeable_1.default, { containerStyle: [atoms_1.py[1]], friction: 2, enableTrackpadTwoFingerGesture: true, rightThreshold: 40, leftThreshold: 40, renderRightActions: react_native_1.Platform.OS === "android" ? undefined : RightAction, renderLeftActions: react_native_1.Platform.OS === "android" ? undefined : LeftAction, overshootFriction: 9, ref: (ref) => {
125
- swipeableRef.current = ref;
126
- }, onSwipeableOpen: (r) => {
127
- if (r === (react_native_1.Platform.OS === "android" ? "right" : "left")) {
128
- setReply(item);
129
- }
130
- if (r === (react_native_1.Platform.OS === "android" ? "left" : "right")) {
131
- setModMsg(item);
132
- }
133
- // close this swipeable
134
- const swipeable = swipeableRef.current;
135
- if (swipeable) {
136
- swipeable.close();
137
- }
138
- }, children: (0, jsx_runtime_1.jsx)(chat_message_1.RenderChatMessage, { item: item }) }) }));
139
- });
140
- function Chat({ shownMessages = SHOWN_MSGS, style: propsStyle, canModerate = false, ...props }) {
141
- const chat = (0, __1.useChat)();
142
- if (!chat)
143
- return ((0, jsx_runtime_1.jsx)(__1.View, { style: [atoms_1.flex.shrink[1], { minWidth: 0, maxWidth: "100%" }], children: (0, jsx_runtime_1.jsx)(__1.Text, { children: "Loading chaat..." }) }));
144
- return ((0, jsx_runtime_1.jsxs)(__1.View, { style: [atoms_1.flex.shrink[1], { minWidth: 0, maxWidth: "100%" }].concat(propsStyle || []), children: [(0, jsx_runtime_1.jsx)(react_native_1.FlatList, { style: [
145
- atoms_1.flex.grow[1],
146
- atoms_1.flex.shrink[1],
147
- { minWidth: 0, maxWidth: "100%" },
148
- ], data: chat.slice(0, shownMessages), inverted: true, keyExtractor: keyExtractor, renderItem: ({ item, index }) => ((0, jsx_runtime_1.jsx)(ChatLine, { item: item, canModerate: canModerate })), removeClippedSubviews: true, maxToRenderPerBatch: 10, initialNumToRender: 10, updateCellsBatchingPeriod: 50 }), (0, jsx_runtime_1.jsx)(mod_view_1.ModView, {})] }));
149
- }
@@ -1,35 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EmojiSuggestions = EmojiSuggestions;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_native_1 = require("react-native");
6
- const __1 = require("../..");
7
- const atoms_1 = require("../../lib/theme/atoms");
8
- function EmojiSuggestions({ emojis, onSelect, highlightedIndex, }) {
9
- if (!emojis || emojis.length === 0) {
10
- return null;
11
- }
12
- return ((0, jsx_runtime_1.jsx)(__1.View, { style: [
13
- atoms_1.bg.gray[800],
14
- atoms_1.layout.position.absolute,
15
- atoms_1.left[0],
16
- atoms_1.right[0],
17
- atoms_1.zIndex[50],
18
- {
19
- bottom: "100%",
20
- borderRadius: 8,
21
- boxShadow: "0px 4px 6px rgba(0, 0, 0, 0.1)",
22
- maxHeight: 200,
23
- overflow: "auto",
24
- },
25
- ], children: emojis.map((emoji, index) => ((0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { onPress: () => onSelect(emoji), style: [
26
- {
27
- padding: 8,
28
- flexDirection: "row",
29
- alignItems: "center",
30
- backgroundColor: index === highlightedIndex
31
- ? "rgba(255, 255, 255, 0.1)"
32
- : "transparent",
33
- },
34
- ], children: [(0, jsx_runtime_1.jsx)(__1.Text, { style: { fontSize: 16, marginRight: 8 }, children: emoji.skins[0]?.native }), (0, jsx_runtime_1.jsxs)(__1.Text, { style: { color: "white", fontSize: 14 }, children: [(0, jsx_runtime_1.jsxs)(__1.Code, { style: [atoms_1.bg.gray[950]], children: [":", emoji.id, ":"] }), " ", emoji.name] })] }, emoji.id))) }));
35
- }
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MentionSuggestions = MentionSuggestions;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_native_1 = require("react-native");
6
- const __1 = require("../..");
7
- const atoms_1 = require("../../lib/theme/atoms");
8
- function MentionSuggestions({ authors, onSelect, highlightedIndex, }) {
9
- if (!authors || authors.size === 0) {
10
- return null; // No authors to display
11
- }
12
- const authorHandles = Array.from(authors.keys());
13
- return ((0, jsx_runtime_1.jsx)(__1.View, { style: [
14
- atoms_1.bg.gray[800],
15
- atoms_1.layout.position.absolute,
16
- atoms_1.left[0],
17
- atoms_1.right[0],
18
- atoms_1.zIndex[50],
19
- {
20
- bottom: "100%",
21
- borderRadius: 8,
22
- boxShadow: "0px 4px 6px rgba(0, 0, 0, 0.1)",
23
- },
24
- ], children: authorHandles.map((handle, index) => {
25
- let profile = authors.get(handle);
26
- return ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => onSelect(handle), style: [
27
- {
28
- padding: 8,
29
- flexDirection: "row",
30
- alignItems: "center",
31
- backgroundColor: index === highlightedIndex
32
- ? "rgba(0, 0, 0, 0.1)"
33
- : "rgba(0, 0, 0, 0.5)",
34
- },
35
- ], children: (0, jsx_runtime_1.jsxs)(__1.Text, { style: {
36
- color: profile?.color
37
- ? `rgb(${profile.color.red}, ${profile.color.green}, ${profile.color.blue})`
38
- : "black",
39
- fontWeight: "bold",
40
- }, children: ["@", handle] }) }, handle));
41
- }) }));
42
- }