@xhub-short/sdk 0.1.0-beta.1 → 0.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -1
- package/dist/index.d.ts +469 -13
- package/dist/index.js +1733 -142
- package/package.json +8 -9
package/README.md
CHANGED
|
@@ -257,9 +257,24 @@ SDK đảm bảo hoạt động với Server-Side Rendering:
|
|
|
257
257
|
├── @xhub-short/contracts (types, interfaces)
|
|
258
258
|
├── @xhub-short/core (domain logic)
|
|
259
259
|
├── @xhub-short/adapters (mock + preset adapters)
|
|
260
|
-
|
|
260
|
+
├── @xhub-short/ui (headless components)
|
|
261
|
+
├── react (peer dependency)
|
|
262
|
+
└── zustand (peer dependency)
|
|
261
263
|
```
|
|
262
264
|
|
|
265
|
+
### Host App Installation
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
npm install @xhub-short/sdk
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**That's it!** No other dependencies needed.
|
|
272
|
+
|
|
273
|
+
**Bundled internally:**
|
|
274
|
+
- `zustand` - state management (bundled in @xhub-short/core)
|
|
275
|
+
- `clsx` - class names utility (bundled in @xhub-short/ui)
|
|
276
|
+
- Custom `useTouchDrag` hook - gesture handling (bundled in @xhub-short/sdk)
|
|
277
|
+
|
|
263
278
|
---
|
|
264
279
|
|
|
265
280
|
## ✨ Chức năng chính
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ComponentType, ReactNode,
|
|
3
|
-
import { ActionBarHeadlessProps, VideoItem, UIInteractionState, AuthorInfoHeadlessProps, UIAuthorState, UIAuthorActions, Author, ProgressBarHeadlessProps, UIFeedState, UISwipeState, VideoInfoProps, VideoSlotProps, IDataSource, IInteraction, ISessionStorage, IAnalytics, ILogger, INetworkAdapter, IVideoLoader, IPosterLoader } from '@xhub-short/contracts';
|
|
4
|
-
export { ActionBarHeadlessProps, ActionBarProps, ActionButtonHeadlessProps, AnalyticsEvent, AnalyticsEventType, Author, AuthorInfoHeadlessProps, AuthorInfoProps, ErrorBoundaryProps, FeedResponse, IAnalytics, IDataSource, IInteraction, ILogger, INetworkAdapter, IPosterLoader, ISessionStorage, IStorage, IVideoLoader, LogEntry, LogLevel, SessionSnapshot, SkeletonProps, UIAuthorActions, UIAuthorState, UIFeedState, UIInteractionActions, UIInteractionState, UIPlayerControls, UIPlayerState, UIResourceState, UISwipeState, UIVideoInfoActions, UIVideoInfoState, VideoFeedHeadlessProps, VideoInfoHeadlessProps, VideoInfoProps, VideoItem, VideoPlayerHeadlessProps, VideoSlotHeadlessProps, VideoSlotProps, VideoSource, VideoStats } from '@xhub-short/contracts';
|
|
2
|
+
import { ComponentType, ReactNode, ReactElement, CSSProperties, SyntheticEvent } from 'react';
|
|
3
|
+
import { ActionBarHeadlessProps, VideoItem, UIInteractionState, AuthorInfoHeadlessProps, UIAuthorState, UIAuthorActions, Author, CommentAuthor, CommentConfig, ProgressBarHeadlessProps, UIFeedState, UISwipeState, VideoInfoProps, VideoSlotProps, IDataSource, IInteraction, ICommentAdapter, ISessionStorage, IAnalytics, ILogger, INetworkAdapter, IVideoLoader, IPosterLoader, LocalizationConfig, UICommentState, UICommentActions, ILocalization, MessageKey, MessageValues, MessageCatalog } from '@xhub-short/contracts';
|
|
4
|
+
export { ActionBarHeadlessProps, ActionBarProps, ActionButtonHeadlessProps, AnalyticsEvent, AnalyticsEventType, Author, AuthorInfoHeadlessProps, AuthorInfoProps, CommentAuthor, CommentConfig, CommentItem, ErrorBoundaryProps, FeedResponse, IAnalytics, ICommentAdapter, IDataSource, IInteraction, ILocalization, ILogger, INetworkAdapter, IPosterLoader, ISessionStorage, IStorage, IVideoLoader, LocalizationConfig, LogEntry, LogLevel, MessageCatalog, MessageKey, MessageValue, MessageValues, PartialMessageCatalog, ReplyItem, SessionSnapshot, SkeletonProps, UIAuthorActions, UIAuthorState, UICommentActions, UICommentState, UIFeedState, UIInteractionActions, UIInteractionState, UIPlayerControls, UIPlayerState, UIResourceState, UISwipeState, UIVideoInfoActions, UIVideoInfoState, VideoFeedHeadlessProps, VideoInfoHeadlessProps, VideoInfoProps, VideoItem, VideoPlayerHeadlessProps, VideoSlotHeadlessProps, VideoSlotProps, VideoSource, VideoStats } from '@xhub-short/contracts';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
|
-
import { AuthorAvatar, AuthorName, AuthorDescription,
|
|
7
|
-
|
|
6
|
+
import { AuthorAvatar, AuthorName, AuthorDescription, FollowButtonProps, SheetHeaderProps, CommentListProps, CommentInputProps, VideoAuthorName, VideoCaption, VideoHashtags, VideoLocation, VideoMusic, VideoPlayerHeadlessExtendedProps, ErrorMode, ErrorBoundaryProps } from '@xhub-short/ui';
|
|
7
|
+
export { CommentInputProps, CommentListProps, SheetHeaderProps } from '@xhub-short/ui';
|
|
8
8
|
import { PlayerError, FeedConfig, PlayerConfig, ResourceConfig, LifecycleConfig, OptimisticConfig, RestoreResult, FeedError, FeedState, PlayerStatus, PlayerState, NetworkType, AllocationResult, PrefetchConfig, ResourceState, PendingAction, ActionType, OptimisticState, FeedManager, PlayerEngine, ResourceGovernor, LifecycleManager, OptimisticManager, LifecycleState } from '@xhub-short/core';
|
|
9
9
|
export { ActionType, AllocationResult, FeedConfig, FeedError, FeedState, LifecycleConfig, LifecycleState, NetworkType, OptimisticConfig, OptimisticState, PendingAction, PlayerConfig, PlayerError, PlayerState, PlayerStatus, PrefetchConfig, ResourceConfig, ResourceState, RestoreResult } from '@xhub-short/core';
|
|
10
10
|
import { BrowserAdaptersConfig } from '@xhub-short/adapters';
|
|
@@ -288,6 +288,10 @@ declare function AuthorInfoContent({ className, children, }: {
|
|
|
288
288
|
className?: string;
|
|
289
289
|
children?: ReactNode;
|
|
290
290
|
}): react_jsx_runtime.JSX.Element;
|
|
291
|
+
/**
|
|
292
|
+
* Translated FollowButton - auto-injects i18n strings
|
|
293
|
+
*/
|
|
294
|
+
declare function TranslatedFollowButton(props: FollowButtonProps): React.ReactElement;
|
|
291
295
|
/**
|
|
292
296
|
* AuthorInfo with compound sub-components
|
|
293
297
|
*
|
|
@@ -308,12 +312,84 @@ declare const AuthorInfo: typeof AuthorInfoRoot & {
|
|
|
308
312
|
Name: typeof AuthorName;
|
|
309
313
|
/** Description/bio sub-component */
|
|
310
314
|
Description: typeof AuthorDescription;
|
|
311
|
-
/** Follow button sub-component */
|
|
312
|
-
FollowButton: typeof
|
|
315
|
+
/** Follow button sub-component (auto-translated) */
|
|
316
|
+
FollowButton: typeof TranslatedFollowButton;
|
|
313
317
|
/** Content wrapper for name + description */
|
|
314
318
|
Content: typeof AuthorInfoContent;
|
|
315
319
|
};
|
|
316
320
|
|
|
321
|
+
/**
|
|
322
|
+
* CommentSheet - Wired SDK component
|
|
323
|
+
*
|
|
324
|
+
* TikTok-style bottom sheet for comments with SDK integration.
|
|
325
|
+
*
|
|
326
|
+
* @example Basic usage
|
|
327
|
+
* ```tsx
|
|
328
|
+
* <CommentSheet
|
|
329
|
+
* videoId={currentVideoId}
|
|
330
|
+
* isOpen={showComments}
|
|
331
|
+
* onClose={() => setShowComments(false)}
|
|
332
|
+
* />
|
|
333
|
+
* ```
|
|
334
|
+
*
|
|
335
|
+
* @example Custom composition
|
|
336
|
+
* ```tsx
|
|
337
|
+
* <CommentSheet videoId={videoId} isOpen={isOpen} onClose={onClose}>
|
|
338
|
+
* <CommentSheet.Header titleLabel="Bình luận" />
|
|
339
|
+
* <CommentSheet.List />
|
|
340
|
+
* <CommentSheet.Input placeholder="Aa..." />
|
|
341
|
+
* </CommentSheet>
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
|
|
345
|
+
interface CommentSheetProps {
|
|
346
|
+
/** Video ID to show comments for */
|
|
347
|
+
videoId: string;
|
|
348
|
+
/** Whether sheet is open */
|
|
349
|
+
isOpen: boolean;
|
|
350
|
+
/** Close callback */
|
|
351
|
+
onClose: () => void;
|
|
352
|
+
/** Current user info (required for optimistic UI when posting) */
|
|
353
|
+
currentUser?: CommentAuthor;
|
|
354
|
+
/** Config overrides */
|
|
355
|
+
config?: Partial<CommentConfig>;
|
|
356
|
+
/** Initial count from video data (displayed before API loads) */
|
|
357
|
+
initialCount?: number;
|
|
358
|
+
/** Auto load comments when opened */
|
|
359
|
+
autoLoad?: boolean;
|
|
360
|
+
/** Custom children for compound pattern */
|
|
361
|
+
children?: ReactNode;
|
|
362
|
+
/** Root class name */
|
|
363
|
+
className?: string;
|
|
364
|
+
/** Backdrop class name */
|
|
365
|
+
backdropClassName?: string;
|
|
366
|
+
/** Close on backdrop click (default: true) */
|
|
367
|
+
closeOnBackdropClick?: boolean;
|
|
368
|
+
/** Close on escape key (default: true) */
|
|
369
|
+
closeOnEscape?: boolean;
|
|
370
|
+
}
|
|
371
|
+
declare function CommentSheetInner({ videoId, isOpen, onClose, currentUser, config, initialCount, autoLoad, children, className, backdropClassName, closeOnBackdropClick, closeOnEscape, }: CommentSheetProps): ReactElement;
|
|
372
|
+
/**
|
|
373
|
+
* Translated SheetHeader - auto-injects i18n strings
|
|
374
|
+
*/
|
|
375
|
+
declare function TranslatedSheetHeader(props: SheetHeaderProps): ReactElement;
|
|
376
|
+
/**
|
|
377
|
+
* Translated CommentList - auto-injects i18n strings
|
|
378
|
+
*/
|
|
379
|
+
declare function TranslatedCommentList(props: CommentListProps): ReactElement;
|
|
380
|
+
/**
|
|
381
|
+
* Translated CommentInput - auto-injects i18n strings
|
|
382
|
+
*/
|
|
383
|
+
declare function TranslatedCommentInput(props: CommentInputProps): ReactElement;
|
|
384
|
+
declare const CommentSheet: typeof CommentSheetInner & {
|
|
385
|
+
/** Sheet header with title and close button (auto-translated) */
|
|
386
|
+
Header: typeof TranslatedSheetHeader;
|
|
387
|
+
/** Scrollable comment list with infinite loading (auto-translated) */
|
|
388
|
+
List: typeof TranslatedCommentList;
|
|
389
|
+
/** Input area with emoji bar and submit (auto-translated) */
|
|
390
|
+
Input: typeof TranslatedCommentInput;
|
|
391
|
+
};
|
|
392
|
+
|
|
317
393
|
/**
|
|
318
394
|
* Wired ProgressBar Component (P11)
|
|
319
395
|
*
|
|
@@ -382,6 +458,17 @@ interface ProgressBarProps extends Omit<ProgressBarHeadlessProps, 'currentTime'
|
|
|
382
458
|
* @default false
|
|
383
459
|
*/
|
|
384
460
|
minimal?: boolean;
|
|
461
|
+
/**
|
|
462
|
+
* Auto-hide progress bar when video is playing
|
|
463
|
+
*
|
|
464
|
+
* When enabled:
|
|
465
|
+
* - Hidden when video is playing
|
|
466
|
+
* - Visible when video is paused
|
|
467
|
+
* - Visible when user hovers (via CSS)
|
|
468
|
+
*
|
|
469
|
+
* @default true
|
|
470
|
+
*/
|
|
471
|
+
autoHide?: boolean;
|
|
385
472
|
/**
|
|
386
473
|
* Additional CSS class
|
|
387
474
|
*/
|
|
@@ -393,16 +480,24 @@ interface ProgressBarProps extends Omit<ProgressBarHeadlessProps, 'currentTime'
|
|
|
393
480
|
* Connects to PlayerEngine for automatic state updates.
|
|
394
481
|
* Uses Direct DOM Update for 60fps smooth progress animation.
|
|
395
482
|
*/
|
|
396
|
-
declare function ProgressBar({ seekable, showTime, showTooltip, minimal, className, onSeekStart, onSeekEnd, }: ProgressBarProps): React.ReactElement | null;
|
|
483
|
+
declare function ProgressBar({ seekable, showTime, showTooltip, minimal, autoHide, className, onSeekStart, onSeekEnd, }: ProgressBarProps): React.ReactElement | null;
|
|
397
484
|
declare namespace ProgressBar {
|
|
398
485
|
var displayName: string;
|
|
399
486
|
}
|
|
400
487
|
|
|
488
|
+
interface DragBind {
|
|
489
|
+
onPointerDown?: (e: React.PointerEvent) => void;
|
|
490
|
+
onTouchStart?: (e: React.TouchEvent) => void;
|
|
491
|
+
style?: {
|
|
492
|
+
touchAction: string;
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
401
496
|
/**
|
|
402
497
|
* Swipe Gesture Hook
|
|
403
498
|
*
|
|
404
499
|
* Headless hook for vertical swipe gestures in video feeds.
|
|
405
|
-
*
|
|
500
|
+
* Uses custom lightweight touch handler (~1KB instead of @use-gesture/react ~20KB).
|
|
406
501
|
*
|
|
407
502
|
* Features:
|
|
408
503
|
* - Touch and mouse support
|
|
@@ -506,7 +601,7 @@ interface UseSwipeGestureReturn {
|
|
|
506
601
|
* return <div {...bind()}>...</div>;
|
|
507
602
|
* ```
|
|
508
603
|
*/
|
|
509
|
-
bind:
|
|
604
|
+
bind: () => DragBind;
|
|
510
605
|
/**
|
|
511
606
|
* Get current swipe state (ref-based, no re-render).
|
|
512
607
|
* Use this for reading state during animations or imperative code.
|
|
@@ -543,6 +638,11 @@ interface UseSwipeGestureReturn {
|
|
|
543
638
|
* ```
|
|
544
639
|
*/
|
|
545
640
|
dragOffsetRef: React.RefObject<number>;
|
|
641
|
+
/**
|
|
642
|
+
* Ref indicating if current index change is from restore (vs user swipe).
|
|
643
|
+
* Use this to skip animations when restoring session.
|
|
644
|
+
*/
|
|
645
|
+
isRestoreTransitionRef: React.RefObject<boolean>;
|
|
546
646
|
}
|
|
547
647
|
/**
|
|
548
648
|
* Headless hook for vertical swipe gestures
|
|
@@ -750,7 +850,7 @@ interface VideoFeedProps {
|
|
|
750
850
|
* React re-renders. The `dragOffset` in swipeState is always 0 because
|
|
751
851
|
* real-time offset is stored in a ref and applied directly to DOM elements.
|
|
752
852
|
*/
|
|
753
|
-
declare function VideoFeed({ height, className, renderSlot, onIndexChange, onEndReached, endReachedThreshold, bufferSize, loadingText, emptyText, endText, autoLoad, autoLoadMore, swipeThreshold, velocityThreshold, snapDuration, onSwipe, feedState: feedStateProp, swipeState: swipeStateProp, containerStyle, }: VideoFeedProps): React.ReactElement;
|
|
853
|
+
declare function VideoFeed({ height, className, renderSlot, onIndexChange, onEndReached, endReachedThreshold, bufferSize, loadingText: loadingTextProp, emptyText: emptyTextProp, endText: endTextProp, autoLoad, autoLoadMore, swipeThreshold, velocityThreshold, snapDuration, onSwipe, feedState: feedStateProp, swipeState: swipeStateProp, containerStyle, }: VideoFeedProps): React.ReactElement;
|
|
754
854
|
declare namespace VideoFeed {
|
|
755
855
|
var displayName: string;
|
|
756
856
|
}
|
|
@@ -847,11 +947,17 @@ declare const VideoInfo: typeof VideoInfoRoot & {
|
|
|
847
947
|
*
|
|
848
948
|
* VideoPlayer (Wired) -> VideoPlayerHeadless (UI)
|
|
849
949
|
*
|
|
850
|
-
* - Auto-connects to PlayerEngine via
|
|
950
|
+
* - Auto-connects to PlayerEngine via usePlayerCore() (optimized)
|
|
851
951
|
* - Auto-loads video when video prop changes
|
|
852
952
|
* - Reports playback events back to PlayerEngine
|
|
853
953
|
* - Can detect VideoSlot context for embedded use
|
|
854
954
|
*
|
|
955
|
+
* ## Re-render Optimization
|
|
956
|
+
*
|
|
957
|
+
* Uses `usePlayerCore()` instead of `usePlayer()` to avoid re-renders
|
|
958
|
+
* during playback. This hook excludes time-based state (currentTime,
|
|
959
|
+
* duration, buffered, watchTime) which update ~4 times per second.
|
|
960
|
+
*
|
|
855
961
|
* ## Important: Standalone vs Isolated
|
|
856
962
|
*
|
|
857
963
|
* **Standalone mode does NOT mean isolated player.**
|
|
@@ -1065,6 +1171,10 @@ interface DefaultSlotProps {
|
|
|
1065
1171
|
index: number;
|
|
1066
1172
|
/** Show poster before video plays (default: true) */
|
|
1067
1173
|
showPoster?: boolean;
|
|
1174
|
+
/** Show play/pause indicator on tap (default: true) */
|
|
1175
|
+
showPlayIndicator?: boolean;
|
|
1176
|
+
/** Keep play icon visible while video is paused - YouTube style (default: true) */
|
|
1177
|
+
persistPlayIndicatorWhenPaused?: boolean;
|
|
1068
1178
|
/** Show like animation on double-tap (default: true) */
|
|
1069
1179
|
showLikeAnimation?: boolean;
|
|
1070
1180
|
/** Show author info - avatar + follow badge (default: true) */
|
|
@@ -1081,6 +1191,8 @@ interface DefaultSlotProps {
|
|
|
1081
1191
|
showTooltip?: boolean;
|
|
1082
1192
|
/** Show bookmark button (default: false) */
|
|
1083
1193
|
showBookmark?: boolean;
|
|
1194
|
+
/** Show comment sheet when comment button is clicked (default: true) */
|
|
1195
|
+
showCommentSheet?: boolean;
|
|
1084
1196
|
/** Show debug info (default: false) */
|
|
1085
1197
|
showDebug?: boolean;
|
|
1086
1198
|
/** Called when comments button is clicked */
|
|
@@ -1107,8 +1219,14 @@ interface DefaultSlotProps {
|
|
|
1107
1219
|
renderVideoInfo?: (props: VideoInfoWiredProps) => ReactNode;
|
|
1108
1220
|
/** Custom ProgressBar renderer */
|
|
1109
1221
|
renderProgressBar?: (props: ProgressBarProps) => ReactNode;
|
|
1222
|
+
/** Custom CommentSheet renderer */
|
|
1223
|
+
renderCommentSheet?: (props: CommentSheetProps) => ReactNode;
|
|
1110
1224
|
/** Custom Error renderer */
|
|
1111
1225
|
renderError?: (error: Error, retry: () => void) => ReactNode;
|
|
1226
|
+
/** Current user info for optimistic UI when posting comments */
|
|
1227
|
+
currentUser?: CommentAuthor;
|
|
1228
|
+
/** Comment configuration (pageSize, maxLength, etc.) */
|
|
1229
|
+
commentConfig?: Partial<CommentConfig>;
|
|
1112
1230
|
/** Like animation style (default: 'float') */
|
|
1113
1231
|
likeAnimationStyle?: 'float' | 'burst' | 'scale' | 'bounce';
|
|
1114
1232
|
/** Like animation duration in ms (default: 1200) */
|
|
@@ -1139,6 +1257,8 @@ interface AdaptersConfig {
|
|
|
1139
1257
|
dataSource?: IDataSource;
|
|
1140
1258
|
/** Interaction adapter for like/follow/comment actions */
|
|
1141
1259
|
interaction?: IInteraction;
|
|
1260
|
+
/** Comment adapter for comment operations (read/write/like) */
|
|
1261
|
+
comment?: ICommentAdapter;
|
|
1142
1262
|
/** Storage adapter for session persistence */
|
|
1143
1263
|
storage?: ISessionStorage;
|
|
1144
1264
|
/** Analytics adapter for tracking events */
|
|
@@ -1232,6 +1352,67 @@ interface SDKConfig {
|
|
|
1232
1352
|
* @see OptimisticConfig
|
|
1233
1353
|
*/
|
|
1234
1354
|
optimistic?: Partial<OptimisticConfig>;
|
|
1355
|
+
/**
|
|
1356
|
+
* Comment feature configuration
|
|
1357
|
+
* @see CommentConfig
|
|
1358
|
+
*/
|
|
1359
|
+
comment?: Partial<CommentConfig>;
|
|
1360
|
+
/**
|
|
1361
|
+
* Prefetch cache configuration for instant feed loading
|
|
1362
|
+
*
|
|
1363
|
+
* When enabled, SDK caches the last N videos from the feed.
|
|
1364
|
+
* On fresh load (reload/new tab), cached videos are shown instantly
|
|
1365
|
+
* while fresh data is fetched in the background.
|
|
1366
|
+
*
|
|
1367
|
+
* @example
|
|
1368
|
+
* ```tsx
|
|
1369
|
+
* <ShortVideoRoot
|
|
1370
|
+
* config={{
|
|
1371
|
+
* prefetchCache: {
|
|
1372
|
+
* enabled: true,
|
|
1373
|
+
* maxVideos: 15,
|
|
1374
|
+
* }
|
|
1375
|
+
* }}
|
|
1376
|
+
* />
|
|
1377
|
+
* ```
|
|
1378
|
+
*/
|
|
1379
|
+
prefetchCache?: {
|
|
1380
|
+
/** Enable instant loading from cache (default: true) */
|
|
1381
|
+
enabled?: boolean;
|
|
1382
|
+
/** Number of videos to cache (default: 10) */
|
|
1383
|
+
maxVideos?: number;
|
|
1384
|
+
/**
|
|
1385
|
+
* Enable dynamic cache eviction (default: true)
|
|
1386
|
+
* When user scrolls past cached videos, remove them from cache
|
|
1387
|
+
* Prevents user from rewatching same videos on reload
|
|
1388
|
+
*/
|
|
1389
|
+
enableDynamicEviction?: boolean;
|
|
1390
|
+
/**
|
|
1391
|
+
* Throttle duration (ms) for dynamic eviction (default: 2000)
|
|
1392
|
+
* Reduces storage writes during fast scrolling
|
|
1393
|
+
*/
|
|
1394
|
+
evictionThrottleMs?: number;
|
|
1395
|
+
};
|
|
1396
|
+
/**
|
|
1397
|
+
* Localization configuration
|
|
1398
|
+
*
|
|
1399
|
+
* Configure locale and custom messages for i18n support.
|
|
1400
|
+
*
|
|
1401
|
+
* @example
|
|
1402
|
+
* ```tsx
|
|
1403
|
+
* <ShortVideoProvider config={{
|
|
1404
|
+
* localization: {
|
|
1405
|
+
* locale: 'vi',
|
|
1406
|
+
* messages: {
|
|
1407
|
+
* 'feed.empty': 'Hiện chưa có video nào',
|
|
1408
|
+
* },
|
|
1409
|
+
* },
|
|
1410
|
+
* }}>
|
|
1411
|
+
* <App />
|
|
1412
|
+
* </ShortVideoProvider>
|
|
1413
|
+
* ```
|
|
1414
|
+
*/
|
|
1415
|
+
localization?: LocalizationConfig;
|
|
1235
1416
|
/**
|
|
1236
1417
|
* Enable debug mode
|
|
1237
1418
|
* When true, enables verbose logging
|
|
@@ -1932,6 +2113,8 @@ interface SDKInstance {
|
|
|
1932
2113
|
network: INetworkAdapter;
|
|
1933
2114
|
videoLoader: IVideoLoader;
|
|
1934
2115
|
posterLoader: IPosterLoader;
|
|
2116
|
+
/** Comment adapter (optional - only if comment feature is enabled) */
|
|
2117
|
+
comment?: ICommentAdapter;
|
|
1935
2118
|
};
|
|
1936
2119
|
/** Destroy all managers and cleanup resources */
|
|
1937
2120
|
destroy: () => void;
|
|
@@ -2051,6 +2234,12 @@ interface UseLifecycleOptions {
|
|
|
2051
2234
|
* - Session restore on mount
|
|
2052
2235
|
* - State tracking during usage
|
|
2053
2236
|
* - Session save on unmount/visibility hidden
|
|
2237
|
+
*
|
|
2238
|
+
* ## Session-Only Restore
|
|
2239
|
+
*
|
|
2240
|
+
* By default, restore only happens when user navigates within the app
|
|
2241
|
+
* (e.g., going to another page and coming back). Fresh loads (reload,
|
|
2242
|
+
* new tab, direct URL) will NOT restore to prevent stale data issues.
|
|
2054
2243
|
*/
|
|
2055
2244
|
declare function useLifecycle(options?: UseLifecycleOptions): UseLifecycleReturn;
|
|
2056
2245
|
/**
|
|
@@ -2064,4 +2253,271 @@ declare function useLifecycle(options?: UseLifecycleOptions): UseLifecycleReturn
|
|
|
2064
2253
|
*/
|
|
2065
2254
|
declare function useLifecycleSelector<T>(selector: (state: LifecycleState) => T): T;
|
|
2066
2255
|
|
|
2067
|
-
|
|
2256
|
+
/**
|
|
2257
|
+
* useComment Hook - SDK integration for Comment feature
|
|
2258
|
+
*
|
|
2259
|
+
* Provides comment state and actions for a specific video.
|
|
2260
|
+
* Uses CommentManager from @xhub-short/core with Zustand store.
|
|
2261
|
+
*
|
|
2262
|
+
* @example
|
|
2263
|
+
* ```tsx
|
|
2264
|
+
* function CommentSheet({ videoId }) {
|
|
2265
|
+
* const { state, actions, isReady } = useComment({ videoId, autoLoad: true });
|
|
2266
|
+
*
|
|
2267
|
+
* if (!isReady) return null;
|
|
2268
|
+
*
|
|
2269
|
+
* return (
|
|
2270
|
+
* <>
|
|
2271
|
+
* {state.isLoading ? <Spinner /> : null}
|
|
2272
|
+
* {state.comments.map(c => <Comment key={c.id} {...c} />)}
|
|
2273
|
+
* </>
|
|
2274
|
+
* );
|
|
2275
|
+
* }
|
|
2276
|
+
* ```
|
|
2277
|
+
*/
|
|
2278
|
+
|
|
2279
|
+
interface UseCommentOptions {
|
|
2280
|
+
/** Video ID to load comments for */
|
|
2281
|
+
videoId: string;
|
|
2282
|
+
/** Auto load comments when hook mounts (default: false) */
|
|
2283
|
+
autoLoad?: boolean;
|
|
2284
|
+
/** Current user info (required for posting) */
|
|
2285
|
+
currentUser?: CommentAuthor;
|
|
2286
|
+
/** Config overrides */
|
|
2287
|
+
config?: Partial<CommentConfig>;
|
|
2288
|
+
}
|
|
2289
|
+
interface UseCommentReturn {
|
|
2290
|
+
/** Comment state */
|
|
2291
|
+
state: UICommentState;
|
|
2292
|
+
/** Comment actions */
|
|
2293
|
+
actions: UICommentActions;
|
|
2294
|
+
/** Whether hook is ready (adapter configured) */
|
|
2295
|
+
isReady: boolean;
|
|
2296
|
+
}
|
|
2297
|
+
declare function resetCommentManager(): void;
|
|
2298
|
+
declare function useComment(options: UseCommentOptions): UseCommentReturn;
|
|
2299
|
+
|
|
2300
|
+
/**
|
|
2301
|
+
* Localization Context
|
|
2302
|
+
*
|
|
2303
|
+
* Holds the ILocalization instance for the SDK.
|
|
2304
|
+
*/
|
|
2305
|
+
declare const LocalizationContext: react.Context<ILocalization | null>;
|
|
2306
|
+
interface LocalizationProviderProps {
|
|
2307
|
+
/**
|
|
2308
|
+
* Localization configuration
|
|
2309
|
+
*/
|
|
2310
|
+
config?: LocalizationConfig;
|
|
2311
|
+
/**
|
|
2312
|
+
* Children components
|
|
2313
|
+
*/
|
|
2314
|
+
children: ReactNode;
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* Localization Provider
|
|
2318
|
+
*
|
|
2319
|
+
* Wraps SDK components with i18n support.
|
|
2320
|
+
*
|
|
2321
|
+
* @example
|
|
2322
|
+
* <LocalizationProvider config={{ locale: 'vi' }}>
|
|
2323
|
+
* <VideoFeed />
|
|
2324
|
+
* </LocalizationProvider>
|
|
2325
|
+
*/
|
|
2326
|
+
declare function LocalizationProvider({ config, children, }: LocalizationProviderProps): React.ReactElement;
|
|
2327
|
+
/**
|
|
2328
|
+
* Get localization instance from context
|
|
2329
|
+
*
|
|
2330
|
+
* @throws Error if used outside LocalizationProvider
|
|
2331
|
+
*/
|
|
2332
|
+
declare function useLocalization(): ILocalization;
|
|
2333
|
+
/**
|
|
2334
|
+
* Get localization instance (nullable)
|
|
2335
|
+
*
|
|
2336
|
+
* For components that may be used outside SDK context.
|
|
2337
|
+
*/
|
|
2338
|
+
declare function useOptionalLocalization(): ILocalization | null;
|
|
2339
|
+
|
|
2340
|
+
/**
|
|
2341
|
+
* useTranslation Hook
|
|
2342
|
+
*
|
|
2343
|
+
* Main hook for accessing i18n functions in SDK components.
|
|
2344
|
+
*/
|
|
2345
|
+
|
|
2346
|
+
/**
|
|
2347
|
+
* Translation function type
|
|
2348
|
+
*/
|
|
2349
|
+
type TranslateFn = (key: MessageKey, values?: MessageValues) => string;
|
|
2350
|
+
/**
|
|
2351
|
+
* Return type of useTranslation hook
|
|
2352
|
+
*/
|
|
2353
|
+
interface UseTranslationReturn {
|
|
2354
|
+
/** Current locale */
|
|
2355
|
+
locale: string;
|
|
2356
|
+
/** Translate function */
|
|
2357
|
+
t: TranslateFn;
|
|
2358
|
+
/** Format number with locale separators */
|
|
2359
|
+
formatNumber: (value: number) => string;
|
|
2360
|
+
/** Format compact number (1K, 1M, 1B) */
|
|
2361
|
+
formatCompact: (value: number) => string;
|
|
2362
|
+
/** Format relative time */
|
|
2363
|
+
formatRelativeTime: (date: Date | number) => string;
|
|
2364
|
+
}
|
|
2365
|
+
/**
|
|
2366
|
+
* Hook to access translation functions
|
|
2367
|
+
*
|
|
2368
|
+
* Must be used within ShortVideoProvider.
|
|
2369
|
+
*
|
|
2370
|
+
* @example
|
|
2371
|
+
* const { t, formatCompact } = useTranslation();
|
|
2372
|
+
*
|
|
2373
|
+
* // Simple translation
|
|
2374
|
+
* t('feed.loading') // "Đang tải..."
|
|
2375
|
+
*
|
|
2376
|
+
* // With interpolation
|
|
2377
|
+
* t('comment.replyTo', { name: 'John' }) // "Đang trả lời John"
|
|
2378
|
+
*
|
|
2379
|
+
* // Plural
|
|
2380
|
+
* t('comment.count', { count: 5 }) // "5 Bình luận"
|
|
2381
|
+
*
|
|
2382
|
+
* // Compact number
|
|
2383
|
+
* formatCompact(15000) // "15N" (Vietnamese) or "15K" (English)
|
|
2384
|
+
*/
|
|
2385
|
+
declare function useTranslation(): UseTranslationReturn;
|
|
2386
|
+
/**
|
|
2387
|
+
* Hook to access translation functions (nullable)
|
|
2388
|
+
*
|
|
2389
|
+
* Returns null if used outside ShortVideoProvider.
|
|
2390
|
+
* Useful for components that may be used standalone.
|
|
2391
|
+
*
|
|
2392
|
+
* NOTE: This hook always runs all internal hooks unconditionally
|
|
2393
|
+
* to comply with Rules of Hooks. The null check happens at the end.
|
|
2394
|
+
*/
|
|
2395
|
+
declare function useOptionalTranslation(): UseTranslationReturn | null;
|
|
2396
|
+
|
|
2397
|
+
/**
|
|
2398
|
+
* Default Localization Adapter
|
|
2399
|
+
*
|
|
2400
|
+
* Built-in implementation using lightweight ICU-like parser.
|
|
2401
|
+
* Zero external dependencies.
|
|
2402
|
+
*/
|
|
2403
|
+
|
|
2404
|
+
/**
|
|
2405
|
+
* Default Localization Adapter
|
|
2406
|
+
*
|
|
2407
|
+
* Provides i18n support with:
|
|
2408
|
+
* - ICU-like message format (plural, select, interpolation)
|
|
2409
|
+
* - Compact number formatting (1K, 1M, 1B)
|
|
2410
|
+
* - Relative time formatting
|
|
2411
|
+
*
|
|
2412
|
+
* @example
|
|
2413
|
+
* const l10n = new LocalizationAdapter({ locale: 'vi' });
|
|
2414
|
+
* l10n.t('comment.count', { count: 5 }); // "5 Bình luận"
|
|
2415
|
+
* l10n.formatCompact(15000); // "15N"
|
|
2416
|
+
*/
|
|
2417
|
+
declare class LocalizationAdapter implements ILocalization {
|
|
2418
|
+
readonly locale: string;
|
|
2419
|
+
private readonly messages;
|
|
2420
|
+
private readonly fallbackMessages;
|
|
2421
|
+
constructor(config?: LocalizationConfig);
|
|
2422
|
+
/**
|
|
2423
|
+
* Translate a message key with optional interpolation
|
|
2424
|
+
*/
|
|
2425
|
+
t(key: MessageKey, values?: MessageValues): string;
|
|
2426
|
+
/**
|
|
2427
|
+
* Format number with locale-aware separators
|
|
2428
|
+
*/
|
|
2429
|
+
formatNumber(value: number): string;
|
|
2430
|
+
/**
|
|
2431
|
+
* Format number in compact form (1K, 1M, 1B)
|
|
2432
|
+
*/
|
|
2433
|
+
formatCompact(value: number): string;
|
|
2434
|
+
/**
|
|
2435
|
+
* Format relative time (e.g., "2 hours ago")
|
|
2436
|
+
*/
|
|
2437
|
+
formatRelativeTime(date: Date | number): string;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
/**
|
|
2441
|
+
* Lightweight ICU-like Message Parser
|
|
2442
|
+
*
|
|
2443
|
+
* Custom implementation - NO external dependencies.
|
|
2444
|
+
* Bundle size: ~0.5KB gzipped
|
|
2445
|
+
*
|
|
2446
|
+
* Supported syntax:
|
|
2447
|
+
* - Simple interpolation: {name}
|
|
2448
|
+
* - Plural: {count, plural, =0 {none} =1 {one} one {# item} other {# items}}
|
|
2449
|
+
* - Select: {gender, select, male {He} female {She} other {They}}
|
|
2450
|
+
*
|
|
2451
|
+
* Note: This is a simplified parser that covers 95% of i18n use cases.
|
|
2452
|
+
* For full ICU compliance, use FormatJS.
|
|
2453
|
+
*/
|
|
2454
|
+
|
|
2455
|
+
/**
|
|
2456
|
+
* Parse ICU-like message format
|
|
2457
|
+
*
|
|
2458
|
+
* @param message - Message template with ICU placeholders
|
|
2459
|
+
* @param values - Values to interpolate
|
|
2460
|
+
* @param locale - Locale for plural rules
|
|
2461
|
+
* @returns Formatted string
|
|
2462
|
+
*
|
|
2463
|
+
* @example
|
|
2464
|
+
* parseMessage("Hello {name}!", { name: "World" })
|
|
2465
|
+
* // "Hello World!"
|
|
2466
|
+
*
|
|
2467
|
+
* parseMessage("{count, plural, =0 {No items} one {# item} other {# items}}", { count: 5 })
|
|
2468
|
+
* // "5 items"
|
|
2469
|
+
*
|
|
2470
|
+
* parseMessage("{active, select, true {Active} other {Inactive}}", { active: true })
|
|
2471
|
+
* // "Active"
|
|
2472
|
+
*/
|
|
2473
|
+
declare function parseMessage(message: string, values?: MessageValues, locale?: string): string;
|
|
2474
|
+
|
|
2475
|
+
/**
|
|
2476
|
+
* English Messages (Default)
|
|
2477
|
+
*
|
|
2478
|
+
* Uses ICU-like message format for pluralization and selection.
|
|
2479
|
+
*/
|
|
2480
|
+
|
|
2481
|
+
declare const enMessages: MessageCatalog;
|
|
2482
|
+
|
|
2483
|
+
/**
|
|
2484
|
+
* Vietnamese Messages
|
|
2485
|
+
*
|
|
2486
|
+
* Vietnamese doesn't have grammatical plural forms,
|
|
2487
|
+
* so ICU plural syntax always uses "other" category.
|
|
2488
|
+
*/
|
|
2489
|
+
|
|
2490
|
+
declare const viMessages: MessageCatalog;
|
|
2491
|
+
|
|
2492
|
+
/**
|
|
2493
|
+
* Message Catalogs Index
|
|
2494
|
+
*
|
|
2495
|
+
* Default messages for supported locales.
|
|
2496
|
+
* Host App can override any message via config.
|
|
2497
|
+
*/
|
|
2498
|
+
|
|
2499
|
+
/**
|
|
2500
|
+
* All supported locales
|
|
2501
|
+
*/
|
|
2502
|
+
declare const SUPPORTED_LOCALES: readonly ["en", "vi"];
|
|
2503
|
+
type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
2504
|
+
/**
|
|
2505
|
+
* Default locale
|
|
2506
|
+
*/
|
|
2507
|
+
declare const DEFAULT_LOCALE: SupportedLocale;
|
|
2508
|
+
/**
|
|
2509
|
+
* Message catalogs by locale
|
|
2510
|
+
*/
|
|
2511
|
+
declare const messageCatalogs: Record<SupportedLocale, MessageCatalog>;
|
|
2512
|
+
/**
|
|
2513
|
+
* Get messages for a locale
|
|
2514
|
+
*
|
|
2515
|
+
* Falls back to English if locale not supported
|
|
2516
|
+
*/
|
|
2517
|
+
declare function getMessages(locale: string): MessageCatalog;
|
|
2518
|
+
/**
|
|
2519
|
+
* Check if locale is supported
|
|
2520
|
+
*/
|
|
2521
|
+
declare function isLocaleSupported(locale: string): locale is SupportedLocale;
|
|
2522
|
+
|
|
2523
|
+
export { ActionBar, type ActionBarIconSet, type ActionBarProps as ActionBarWiredProps, type AdaptersConfig, AuthorInfo, type AuthorInfoProps as AuthorInfoWiredProps, CommentSheet, type CommentSheetProps, DEFAULT_LOCALE, DefaultSlot, type DefaultSlotProps, type HookReturn, LocalizationAdapter, LocalizationContext, LocalizationProvider, type LocalizationProviderProps, ProgressBar, type ProgressBarProps, type SDKConfig, type SDKInstance, SDKPlayerError, SUPPORTED_LOCALES, ShortVideoProvider, type ShortVideoProviderProps, ShortVideoRoot, type ShortVideoRootProps, type SupportedLocale, type SwipeConfig, type SwipeDirection, type SwipeState, type TranslateFn, type UseCommentOptions, type UseCommentReturn, type UseFeedReturn, type UseLifecycleOptions, type UseLifecycleReturn, type UseOptimisticReturn, type UsePlayerForVideoReturn, type UsePlayerReturn, type UseResourceAllocationReturn, type UseResourceReturn, type UseSwipeGestureReturn, type UseTranslationReturn, type VideoElementHandlers, VideoFeed, type VideoFeedProps, VideoInfo, type VideoInfoWiredProps, VideoPlayer, type VideoPlayerProps, VideoSlot, type VideoSlotWiredProps, type WireConfig, createSDK, createSimpleWireConfig, createWiredComponent, destroySDK, enMessages, getMessages, getSDK, isLocaleSupported, messageCatalogs, parseMessage, resetCommentManager, useComment, useFeed, useFeedSelector, useLifecycle, useLifecycleSelector, useLocalization, useOptimistic, useOptimisticSelector, useOptionalLocalization, useOptionalTranslation, usePlayer, usePlayerForVideo, usePlayerSelector, useResource, useResourceAllocation, useResourceSelector, useSDK, useSwipeGesture, useTranslation, viMessages };
|