hive-react-kit 0.10.0 → 0.10.2

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.
@@ -52,6 +52,10 @@ export interface BlogPostListProps {
52
52
  allowLandscapeVideos?: boolean;
53
53
  /** Default reward routing for inline comment composers. */
54
54
  defaultReward?: RewardOption;
55
+ /** Collapse the per-card secondary actions (reblog · share · tip ·
56
+ * flag) into a single 3-dot kebab menu. Forwarded to
57
+ * `<PostActionButton/>`. */
58
+ actionsAsMenu?: boolean;
55
59
  }
56
60
  export declare const BlogPostList: FC<BlogPostListProps>;
57
61
  export default BlogPostList;
@@ -10,7 +10,7 @@ export interface HiveDetailPostProps {
10
10
  * `voteWeight` is non-null when the composer's upvote-on-publish toggle is enabled
11
11
  * (1–100, step 0.25) — consumer should broadcast vote+comment atomically.
12
12
  */
13
- onSubmitComment?: (parentAuthor: string, parentPermlink: string, body: string, voteWeight?: number | null) => void | boolean | Promise<void | boolean>;
13
+ onSubmitComment?: (parentAuthor: string, parentPermlink: string, body: string, voteWeight?: number | null, beneficiaries?: import('../utils/beneficiaries').Beneficiary[]) => void | boolean | Promise<void | boolean>;
14
14
  /**
15
15
  * Show the upvote-on-publish toggle in the post's comment composer. Default false (opt-in).
16
16
  * Auto-hidden internally when the current user has already voted the post.
@@ -28,6 +28,18 @@ export interface HiveDetailPostProps {
28
28
  * Typically wired to a user setting.
29
29
  */
30
30
  defaultReward?: import('../utils/commentOptions').RewardOption;
31
+ /**
32
+ * Beneficiaries pre-populated into every comment composer on this detail
33
+ * page (top-level reply + nested sub-comment replies). Typically wired to
34
+ * the user's app-wide default beneficiaries setting.
35
+ */
36
+ defaultBeneficiaries?: import('../utils/beneficiaries').Beneficiary[];
37
+ /**
38
+ * Suggested beneficiary chips shown inside every comment composer's editor
39
+ * on this detail page — typically the user's previously-used beneficiary
40
+ * presets pulled from local history.
41
+ */
42
+ beneficiaryFavorites?: import('../utils/beneficiaries').Beneficiary[];
31
43
  /**
32
44
  * Initial percent (1–100) for the post's upvote slider AND every comment
33
45
  * composer's "upvote-on-publish" / comment-upvote slider on this page.
@@ -107,5 +119,5 @@ export interface HiveDetailPostProps {
107
119
  /** Called when user clicks "View parent post" — navigate to the parent post. */
108
120
  onNavigateToPost?: (author: string, permlink: string) => void;
109
121
  }
110
- export declare function HiveDetailPost({ author, permlink, currentUser, onUpvote, onSubmitComment, onClickCommentUpvote, onReblog, onShare, onTip, onReport, onShareComment, onTipComment, onReportComment, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, reportedAuthors, reportedPosts, hiveIconUrl, backgroundColor, onBack, onUserClick, onNavigateToPost, onVotePoll, showVoteButton, processBody, defaultReward, defaultVotePercent, voteWeightStep, allowLandscapeVideos, renderOptions, }: HiveDetailPostProps): import("react/jsx-runtime").JSX.Element;
122
+ export declare function HiveDetailPost({ author, permlink, currentUser, onUpvote, onSubmitComment, onClickCommentUpvote, onReblog, onShare, onTip, onReport, onShareComment, onTipComment, onReportComment, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, reportedAuthors, reportedPosts, hiveIconUrl, backgroundColor, onBack, onUserClick, onNavigateToPost, onVotePoll, showVoteButton, processBody, defaultReward, defaultBeneficiaries, beneficiaryFavorites, defaultVotePercent, voteWeightStep, allowLandscapeVideos, renderOptions, }: HiveDetailPostProps): import("react/jsx-runtime").JSX.Element;
111
123
  export default HiveDetailPost;
@@ -5,7 +5,13 @@ interface UpvoteListModalProps {
5
5
  currentUser?: string;
6
6
  token?: string;
7
7
  onClickUpvoteButton?: (currentUser?: string, token?: string) => void;
8
+ /** URL for the small Hive icon shown next to each voter's reward
9
+ * amount. Consumers usually pass a local asset (e.g. the bundled
10
+ * hivesuite hive_logo.png) so the icon stays sharp on retina and
11
+ * works offline; falls back to the official Hive logo from
12
+ * hive.io otherwise. */
13
+ hiveIconUrl?: string;
8
14
  }
9
15
  export declare function formatTimeAgo(date: string | Date): string;
10
- declare const UpvoteListModal: ({ author, permlink, onClose, currentUser, token, onClickUpvoteButton }: UpvoteListModalProps) => import("react/jsx-runtime").JSX.Element;
16
+ declare const UpvoteListModal: ({ author, permlink, onClose, currentUser, token, onClickUpvoteButton, hiveIconUrl, }: UpvoteListModalProps) => import("react/jsx-runtime").JSX.Element;
11
17
  export default UpvoteListModal;
@@ -0,0 +1,17 @@
1
+ export interface MoreActionsMenuProps {
2
+ /** Show the Reblog item. */
3
+ onReblog?: () => void;
4
+ /** Show the Share item. */
5
+ onShare?: () => void;
6
+ /** Show the Tip item. */
7
+ onTip?: () => void;
8
+ /** Show the Flag item. */
9
+ onReport?: () => void;
10
+ /** Tailwind classes for the trigger button (defaults match the kit's
11
+ * inline action buttons). */
12
+ buttonClassName?: string;
13
+ /** aria-label for the trigger. */
14
+ ariaLabel?: string;
15
+ }
16
+ export declare function MoreActionsMenu({ onReblog, onShare, onTip, onReport, buttonClassName, ariaLabel, }: MoreActionsMenuProps): import("react/jsx-runtime").JSX.Element;
17
+ export default MoreActionsMenu;
@@ -19,8 +19,10 @@ export interface PostActionButtonProps {
19
19
  /** Called when user submits a comment. Frontend handles signing/broadcast.
20
20
  * Return `false` to indicate the operation was cancelled — the composer text will be preserved.
21
21
  * `voteWeight` is non-null when the composer's upvote-on-publish toggle is enabled
22
- * (1–100, step 0.25) — consumer should broadcast vote+comment atomically. */
23
- onSubmitComment?: (parentAuthor: string, parentPermlink: string, body: string, voteWeight?: number | null) => void | boolean | Promise<void | boolean>;
22
+ * (1–100, step 0.25) — consumer should broadcast vote+comment atomically.
23
+ * `beneficiaries` is the post-lock beneficiary list selected in the composer
24
+ * (already includes threespeakfund 10% on video posts). */
25
+ onSubmitComment?: (parentAuthor: string, parentPermlink: string, body: string, voteWeight?: number | null, beneficiaries?: import('../../utils/beneficiaries').Beneficiary[]) => void | boolean | Promise<void | boolean>;
24
26
  /** Show the upvote-on-publish toggle in the comment composer.
25
27
  * Auto-hidden when the current user has already voted this post. */
26
28
  showVoteButton?: boolean;
@@ -28,6 +30,10 @@ export interface PostActionButtonProps {
28
30
  parentTags?: string[];
29
31
  /** Default reward routing seeded into the comment composer. */
30
32
  defaultReward?: import('../../utils/commentOptions').RewardOption;
33
+ /** Beneficiaries pre-populated into the comment composer. */
34
+ defaultBeneficiaries?: import('../../utils/beneficiaries').Beneficiary[];
35
+ /** Suggested beneficiary chips shown inside the composer's editor. */
36
+ beneficiaryFavorites?: import('../../utils/beneficiaries').Beneficiary[];
31
37
  /** Initial percent for the upvote slider when opened (1–100). Default 100. */
32
38
  defaultVotePercent?: number;
33
39
  /** Slider precision used by both the post upvote slider AND the comment composer's
@@ -76,6 +82,11 @@ export interface PostActionButtonProps {
76
82
  * Used to lazy-fetch the reply body the first time the user hovers
77
83
  * the comment icon, so the tooltip can show what they wrote. */
78
84
  myReplyKey?: string;
85
+ /** Collapse the secondary actions (reblog · share · tip · report)
86
+ * into a single 3-dot kebab popover. Upvote / comment counters and
87
+ * the payout chip stay inline. Useful in dense card layouts (videos,
88
+ * polls, community detail) where there isn't room for four icons. */
89
+ actionsAsMenu?: boolean;
79
90
  }
80
- export declare function PostActionButton({ author, permlink, currentUser: currentUserProp, hiveValue, hiveIconUrl, payoutTooltip, initialVotes, initialCommentsCount, onUpvote, onSubmitComment, onComments, onReblog, onShare, onTip, onReport, onClickCommentUpvote, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, disableCommentsModal, onClickCommentIcon, onClickCommentCount, hasCommented, myReplyKey, showVoteButton, parentTags, defaultReward, defaultVotePercent, voteWeightStep, allowLandscapeVideos, }: PostActionButtonProps): import("react/jsx-runtime").JSX.Element;
91
+ export declare function PostActionButton({ author, permlink, currentUser: currentUserProp, hiveValue, hiveIconUrl, payoutTooltip, initialVotes, initialCommentsCount, onUpvote, onSubmitComment, onComments, onReblog, onShare, onTip, onReport, onClickCommentUpvote, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, disableCommentsModal, onClickCommentIcon, onClickCommentCount, hasCommented, myReplyKey, showVoteButton, parentTags, defaultReward, defaultBeneficiaries, beneficiaryFavorites, defaultVotePercent, voteWeightStep, allowLandscapeVideos, actionsAsMenu, }: PostActionButtonProps): import("react/jsx-runtime").JSX.Element;
81
92
  export default PostActionButton;
@@ -1 +1,2 @@
1
1
  export { PostActionButton, type PostActionButtonProps } from "./PostActionButton";
2
+ export { MoreActionsMenu, type MoreActionsMenuProps } from "./MoreActionsMenu";
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { type RewardOption } from '../../utils/commentOptions';
3
+ import { type Beneficiary } from '../../utils/beneficiaries';
3
4
  import { type PostingSignMessageFn } from '../../services/hiveImageUpload';
4
5
  export interface PostComposerProps {
5
6
  onSubmit: (body: string) => void | boolean | Promise<void | boolean>;
@@ -61,6 +62,28 @@ export interface PostComposerProps {
61
62
  onRewardChange?: (reward: RewardOption) => void;
62
63
  /** Hide the reward routing toolbar button. */
63
64
  hideReward?: boolean;
65
+ /**
66
+ * Beneficiary list (controlled). When provided, the composer mirrors this
67
+ * list and emits changes through `onBeneficiariesChange`. The
68
+ * `threespeakfund` 10% lock is applied automatically while the body
69
+ * contains a 3Speak video URL or the embedded video uploader has produced
70
+ * one — there is no need for the consumer to inject it.
71
+ */
72
+ beneficiaries?: Beneficiary[];
73
+ /**
74
+ * Initial beneficiary list when uncontrolled. Useful for pre-populating the
75
+ * composer from a user's saved defaults.
76
+ */
77
+ defaultBeneficiaries?: Beneficiary[];
78
+ /** Called whenever the beneficiary list changes (after the 3Speak video lock is applied). */
79
+ onBeneficiariesChange?: (beneficiaries: Beneficiary[]) => void;
80
+ /**
81
+ * Suggested beneficiary chips shown inside the editor modal — typically the
82
+ * user's previously-used presets pulled from app settings.
83
+ */
84
+ beneficiaryFavorites?: Beneficiary[];
85
+ /** Hide the beneficiary toolbar button. */
86
+ hideBeneficiaries?: boolean;
64
87
  /**
65
88
  * Show the "upvote on publish" toggle in the toolbar (default false — opt-in).
66
89
  * Set this to `!alreadyVoted` so the button hides once the user has voted on the parent.
@@ -122,8 +145,8 @@ export interface PostComposerProps {
122
145
  }
123
146
  /** @deprecated Use PostComposerProps instead */
124
147
  export type AddCommentInputProps = PostComposerProps;
125
- declare const PostComposer: ({ onSubmit, onCancel, currentUser, placeholder, parentAuthor, parentPermlink, ecencyToken, onSignMessage, signingUsername, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, hideBold, hideItalic, hideLink, hideImage, hideAudio, hideVideo, hideEmoji, hideGif, hideCode, hideMention, hideTemplate, hidePreview, hidePoll, onPollChange, defaultTags, maxTags, onTagsChange, hideTags, reward, defaultReward, onRewardChange, hideReward, showVoteButton, defaultVoteEnabled, defaultVotePercent, voteWeightStep, allowLandscapeVideos, onVoteChange, voteLabel, showCancel, submitLabel, title, defaultPreviewOn, value, onChange, disabled, hideSubmitArea, submitRef, hideUserHeader, bgColor, borderColor, disableAutoFocus, walletApprovalLabel, awaitingWalletApproval, }: PostComposerProps) => import("react/jsx-runtime").JSX.Element;
148
+ declare const PostComposer: ({ onSubmit, onCancel, currentUser, placeholder, parentAuthor, parentPermlink, ecencyToken, onSignMessage, signingUsername, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, hideBold, hideItalic, hideLink, hideImage, hideAudio, hideVideo, hideEmoji, hideGif, hideCode, hideMention, hideTemplate, hidePreview, hidePoll, onPollChange, defaultTags, maxTags, onTagsChange, hideTags, reward, defaultReward, onRewardChange, hideReward, beneficiaries, defaultBeneficiaries, onBeneficiariesChange, beneficiaryFavorites, hideBeneficiaries, showVoteButton, defaultVoteEnabled, defaultVotePercent, voteWeightStep, allowLandscapeVideos, onVoteChange, voteLabel, showCancel, submitLabel, title, defaultPreviewOn, value, onChange, disabled, hideSubmitArea, submitRef, hideUserHeader, bgColor, borderColor, disableAutoFocus, walletApprovalLabel, awaitingWalletApproval, }: PostComposerProps) => import("react/jsx-runtime").JSX.Element;
126
149
  /** @deprecated Use PostComposer instead */
127
- declare const AddCommentInput: ({ onSubmit, onCancel, currentUser, placeholder, parentAuthor, parentPermlink, ecencyToken, onSignMessage, signingUsername, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, hideBold, hideItalic, hideLink, hideImage, hideAudio, hideVideo, hideEmoji, hideGif, hideCode, hideMention, hideTemplate, hidePreview, hidePoll, onPollChange, defaultTags, maxTags, onTagsChange, hideTags, reward, defaultReward, onRewardChange, hideReward, showVoteButton, defaultVoteEnabled, defaultVotePercent, voteWeightStep, allowLandscapeVideos, onVoteChange, voteLabel, showCancel, submitLabel, title, defaultPreviewOn, value, onChange, disabled, hideSubmitArea, submitRef, hideUserHeader, bgColor, borderColor, disableAutoFocus, walletApprovalLabel, awaitingWalletApproval, }: PostComposerProps) => import("react/jsx-runtime").JSX.Element;
150
+ declare const AddCommentInput: ({ onSubmit, onCancel, currentUser, placeholder, parentAuthor, parentPermlink, ecencyToken, onSignMessage, signingUsername, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, hideBold, hideItalic, hideLink, hideImage, hideAudio, hideVideo, hideEmoji, hideGif, hideCode, hideMention, hideTemplate, hidePreview, hidePoll, onPollChange, defaultTags, maxTags, onTagsChange, hideTags, reward, defaultReward, onRewardChange, hideReward, beneficiaries, defaultBeneficiaries, onBeneficiariesChange, beneficiaryFavorites, hideBeneficiaries, showVoteButton, defaultVoteEnabled, defaultVotePercent, voteWeightStep, allowLandscapeVideos, onVoteChange, voteLabel, showCancel, submitLabel, title, defaultPreviewOn, value, onChange, disabled, hideSubmitArea, submitRef, hideUserHeader, bgColor, borderColor, disableAutoFocus, walletApprovalLabel, awaitingWalletApproval, }: PostComposerProps) => import("react/jsx-runtime").JSX.Element;
128
151
  export { PostComposer };
129
152
  export default AddCommentInput;
@@ -1,4 +1,5 @@
1
1
  import { Discussion } from '@/types/comment';
2
+ import type { Beneficiary } from '../../utils/beneficiaries';
2
3
  interface CommentsModalProps {
3
4
  author: string;
4
5
  permlink: string;
@@ -12,14 +13,20 @@ interface CommentsModalProps {
12
13
  /** When provided, used instead of apiService.handleComment (e.g. for aioha wallet).
13
14
  * Return `false` to indicate the operation was cancelled — the composer text will be preserved.
14
15
  * `voteWeight` is non-null when the composer's upvote-on-publish toggle is enabled
15
- * (value in 1–100, step 0.25); consumer should broadcast vote+comment atomically. */
16
- onSubmitComment?: (parentAuthor: string, parentPermlink: string, body: string, voteWeight?: number | null) => Promise<void | boolean>;
16
+ * (value in 1–100, step 0.25); consumer should broadcast vote+comment atomically.
17
+ * `beneficiaries` is the post-lock beneficiary list selected in the composer
18
+ * (already includes threespeakfund 10% on video posts). */
19
+ onSubmitComment?: (parentAuthor: string, parentPermlink: string, body: string, voteWeight?: number | null, beneficiaries?: Beneficiary[]) => Promise<void | boolean>;
17
20
  /** Show the upvote-on-publish toggle in the composer (the parent decides — usually `!alreadyVoted`). */
18
21
  showVoteButton?: boolean;
19
22
  /** Locked default tags for the top-level composer (typically the parent post's tags, app tag first). */
20
23
  parentTags?: string[];
21
24
  /** Default reward routing seeded into the composer. */
22
25
  defaultReward?: import('../../utils/commentOptions').RewardOption;
26
+ /** Beneficiaries pre-populated into the comment composer (typically the user's app-wide defaults). */
27
+ defaultBeneficiaries?: Beneficiary[];
28
+ /** Suggested beneficiary chips in the composer's editor (typically previously-used presets). */
29
+ beneficiaryFavorites?: Beneficiary[];
23
30
  /** Ecency image hosting token — enables image upload in comment composer */
24
31
  ecencyToken?: string;
25
32
  /** 3Speak API key — enables audio/video upload in comment composer */
@@ -37,5 +44,5 @@ interface CommentsModalProps {
37
44
  /** Allow landscape videos in the comment composer. Default false. */
38
45
  allowLandscapeVideos?: boolean;
39
46
  }
40
- declare const CommentsModal: ({ author, permlink, onClose, currentUser, token, onClickCommentUpvote, onClickCommentReply, onClickUpvoteButton, onSubmitComment, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, showVoteButton, parentTags, defaultReward, defaultVotePercent, voteWeightStep, allowLandscapeVideos }: CommentsModalProps) => import("react/jsx-runtime").JSX.Element;
47
+ declare const CommentsModal: ({ author, permlink, onClose, currentUser, token, onClickCommentUpvote, onClickCommentReply, onClickUpvoteButton, onSubmitComment, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, showVoteButton, parentTags, defaultReward, defaultBeneficiaries, beneficiaryFavorites, defaultVotePercent, voteWeightStep, allowLandscapeVideos }: CommentsModalProps) => import("react/jsx-runtime").JSX.Element;
41
48
  export default CommentsModal;
@@ -25,8 +25,12 @@ export interface CommunityDetailProps {
25
25
  voteWeightStep?: number;
26
26
  allowLandscapeVideos?: boolean;
27
27
  defaultReward?: RewardOption;
28
+ /** Collapse the per-post secondary actions (reblog · share · tip ·
29
+ * flag) into a single 3-dot kebab menu inside the embedded
30
+ * `<BlogPostList/>`. */
31
+ actionsAsMenu?: boolean;
28
32
  onShare?: () => void;
29
33
  onRss?: () => void;
30
34
  }
31
- declare const CommunityDetail: ({ communityId, currentUser, onBack, onUserClick, onPostClick, onCommentClick, onUpvote, onSubmitComment, onClickCommentUpvote, onReblog, onTip, onSharePost, onReportPost, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, defaultVotePercent, voteWeightStep, allowLandscapeVideos, defaultReward, onShare, onRss, }: CommunityDetailProps) => import("react/jsx-runtime").JSX.Element;
35
+ declare const CommunityDetail: ({ communityId, currentUser, onBack, onUserClick, onPostClick, onCommentClick, onUpvote, onSubmitComment, onClickCommentUpvote, onReblog, onTip, onSharePost, onReportPost, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, defaultVotePercent, voteWeightStep, allowLandscapeVideos, defaultReward, actionsAsMenu, onShare, onRss, }: CommunityDetailProps) => import("react/jsx-runtime").JSX.Element;
32
36
  export default CommunityDetail;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * BeneficiariesEditor — modal that lets the user attach a list of Hive accounts
3
+ * that will automatically receive a portion of the rewards on the post being
4
+ * composed.
5
+ *
6
+ * Rules enforced by the UI:
7
+ * - Each beneficiary's percent is in [1, 100].
8
+ * - The total of all beneficiaries (including the locked threespeakfund row,
9
+ * if shown) is capped at 100%.
10
+ * - When `hasVideo` is true, the `threespeakfund` 10% row is auto-injected,
11
+ * not removable, and the remaining user-controlled allocation is capped at
12
+ * 100 - 10 = 90%.
13
+ * - The user can pick from `favorites` (typically previously-used beneficiary
14
+ * sets pulled from app settings/history) — clicking a favorite chip fills
15
+ * the staging row.
16
+ *
17
+ * The component is purely presentational: it owns its working copy of the
18
+ * list while open and emits the final list via `onSave`.
19
+ */
20
+ import React from 'react';
21
+ import { type Beneficiary } from '../../utils/beneficiaries';
22
+ export interface BeneficiariesEditorProps {
23
+ isOpen: boolean;
24
+ onClose: () => void;
25
+ onSave: (beneficiaries: Beneficiary[]) => void;
26
+ /** Initial list. Defaults are pre-populated when the editor opens. */
27
+ initialBeneficiaries?: Beneficiary[];
28
+ /**
29
+ * When true, the `threespeakfund` 10% row is added automatically and cannot
30
+ * be removed; user beneficiaries are capped at 90% in total.
31
+ */
32
+ hasVideo?: boolean;
33
+ /**
34
+ * Suggested chips (favourites / previously-used presets). Each entry is one
35
+ * beneficiary the user may want to add quickly. Click adds it at its weight
36
+ * (capped to remaining allocation).
37
+ */
38
+ favorites?: Beneficiary[];
39
+ /** Title shown in the header. */
40
+ title?: string;
41
+ /** Hint shown under the header. */
42
+ description?: string;
43
+ /** Save button label. */
44
+ saveLabel?: string;
45
+ /** Cancel button label. */
46
+ cancelLabel?: string;
47
+ }
48
+ declare const BeneficiariesEditor: React.FC<BeneficiariesEditorProps>;
49
+ export default BeneficiariesEditor;
@@ -0,0 +1,134 @@
1
+ /**
2
+ * ParentPostComposer — full-screen composer for top-level Hive posts (blogs /
3
+ * articles). Shares the same upload/picker infrastructure as PostComposer
4
+ * (image, audio, video, GIF, emoji, template, poll, beneficiaries) and
5
+ * always renders a side-by-side markdown preview on desktop / stacked
6
+ * preview on mobile. The preview is permanent — no toggle.
7
+ *
8
+ * The composer itself does not broadcast. It surfaces the user's choices via
9
+ * `onSubmit({ title, description, body, tags, reward, beneficiaries, poll })`
10
+ * and the consumer is responsible for assembling the Hive `comment` op.
11
+ */
12
+ import React from 'react';
13
+ import { type RewardOption } from '../../utils/commentOptions';
14
+ import { type Beneficiary } from '../../utils/beneficiaries';
15
+ import { type VideoUploadDetails } from './VideoUploader';
16
+ import type { PollData } from './PollCreator';
17
+ import { type PostingSignMessageFn } from '../../services/hiveImageUpload';
18
+ export interface ParentPostSubmitPayload {
19
+ title: string;
20
+ description: string;
21
+ body: string;
22
+ tags: string[];
23
+ reward: RewardOption;
24
+ beneficiaries: Beneficiary[];
25
+ poll: PollData | null;
26
+ audioEmbedUrl: string | null;
27
+ videoEmbedUrl: string | null;
28
+ videoUploadUrl: string | null;
29
+ videoAspectRatio: string | null;
30
+ /**
31
+ * Full 3Speak upload metadata when the user attached a video — populated
32
+ * by the kit's `<VideoUploader>` after a successful TUS upload. Consumers
33
+ * publishing via 3Speak Studio's `/upload_info` + `/update_info` APIs
34
+ * (the "Save" flow) need every field. `null` when the post has no video.
35
+ */
36
+ videoUploadDetails: VideoUploadDetails | null;
37
+ /** Convenience flag — `true` whenever `videoUploadDetails` is non-null. */
38
+ hasVideo: boolean;
39
+ /**
40
+ * NSFW flag, surfaced by the composer's NSFW toggle. 3Speak's
41
+ * `/update_info` accepts `isNsfwContent`; consumers publishing as a Hive
42
+ * post can fold it into `json_metadata` if they want.
43
+ */
44
+ isNsfw: boolean;
45
+ }
46
+ export interface ParentPostComposerProps {
47
+ /**
48
+ * Called when the user clicks Publish. Receive everything the composer
49
+ * gathered. Return `false` to indicate the broadcast was cancelled — the
50
+ * composer will preserve its state. Throw to surface an error.
51
+ */
52
+ onSubmit: (payload: ParentPostSubmitPayload) => void | boolean | Promise<void | boolean>;
53
+ /** Called when the user clicks the back/close button. Typically `navigate(-1)` or close the modal. */
54
+ onCancel?: () => void;
55
+ /** Logged-in Hive username — shown in the author chip and used for media uploads. */
56
+ currentUser?: string;
57
+ /** Initial values (uncontrolled). */
58
+ initialTitle?: string;
59
+ initialDescription?: string;
60
+ initialBody?: string;
61
+ initialTags?: string[];
62
+ /** Locked tags shown with a lock icon — e.g. an app identifier. Prepended to the merged tag list. */
63
+ lockedTags?: string[];
64
+ /** Total tag cap including locked entries. Default 10. */
65
+ maxTags?: number;
66
+ /** Reward routing default + favorites for the beneficiary editor. */
67
+ defaultReward?: RewardOption;
68
+ defaultBeneficiaries?: Beneficiary[];
69
+ beneficiaryFavorites?: Beneficiary[];
70
+ /** Upload tokens — same plumbing the kit's PostComposer uses. */
71
+ ecencyToken?: string;
72
+ onSignMessage?: PostingSignMessageFn;
73
+ signingUsername?: string;
74
+ threeSpeakApiKey?: string;
75
+ giphyApiKey?: string;
76
+ templateToken?: string;
77
+ templateApiBaseUrl?: string;
78
+ /** Toolbar visibility flags — mirror PostComposer for consistency. */
79
+ hideAudio?: boolean;
80
+ hideVideo?: boolean;
81
+ hideGif?: boolean;
82
+ hideEmoji?: boolean;
83
+ hideTemplate?: boolean;
84
+ hidePoll?: boolean;
85
+ hideTags?: boolean;
86
+ hideReward?: boolean;
87
+ hideBeneficiaries?: boolean;
88
+ /** Allow landscape videos (default true on the parent post composer). */
89
+ allowLandscapeVideos?: boolean;
90
+ /**
91
+ * When set, the composer auto-saves its state to `localStorage[draftKey]`
92
+ * (debounced, ~500 ms after the last change) and rehydrates from it on
93
+ * mount. Cleared automatically after a successful submit (i.e. when
94
+ * `onSubmit` returns anything other than `false`). Pass a per-user key so
95
+ * accounts on a shared device don't trample each other's drafts —
96
+ * e.g. `hivesuite-blog-draft-${username}`.
97
+ */
98
+ draftKey?: string;
99
+ /**
100
+ * Async pre-flight gate run after a video file is picked & validated, but
101
+ * before the TUS upload starts. Use it to check that the logged-in user
102
+ * has granted `threespeak` posting authority (3Speak's API requires it)
103
+ * and surface a "Grant Permission" modal when missing. Resolve `true` to
104
+ * let the upload proceed, `false` to abort. Errors are surfaced as the
105
+ * upload error message.
106
+ */
107
+ beforeVideoUpload?: () => Promise<boolean>;
108
+ /**
109
+ * Forwarded to the embedded `<VideoUploader/>`. When true, the TUS upload
110
+ * goes to `https://video.3speak.tv/files/` with the v2 metadata
111
+ * (`upload_id`, `owner`, `filename`, `filetype`) and the resulting
112
+ * `uploadId` is surfaced via `ParentPostSubmitPayload.videoUploadDetails`.
113
+ * Consumers running the v2 publish flow (`/api/upload/finalize`) need
114
+ * this to be `true`.
115
+ */
116
+ useThreeSpeakV2?: boolean;
117
+ /** Submit button label (default "Publish"). */
118
+ submitLabel?: string;
119
+ /**
120
+ * Submit button label used when the post has a 3Speak video attached
121
+ * (default "Save"). 3Speak's flow registers the video via its Studio
122
+ * API rather than broadcasting a Hive `comment` op, so calling the
123
+ * action "Save" is more accurate than "Publish".
124
+ */
125
+ submitLabelWithVideo?: string;
126
+ /** Page title shown in the sticky header (default "Create post"). */
127
+ title?: string;
128
+ /** Hint shown when the wallet is awaiting approval during the broadcast. */
129
+ walletApprovalLabel?: string;
130
+ /** When true, the composer renders a blinking "approve in wallet" banner. */
131
+ awaitingWalletApproval?: boolean;
132
+ }
133
+ declare const ParentPostComposer: React.FC<ParentPostComposerProps>;
134
+ export default ParentPostComposer;
@@ -1,8 +1,48 @@
1
1
  import React from 'react';
2
2
  import { type PostingSignMessageFn } from '../../services/hiveImageUpload';
3
+ /** Extra metadata about a completed 3Speak upload — surfaced for consumers
4
+ * that want to drive the publish step themselves (whether through the
5
+ * legacy `/upload_info` + `/update_info` pair or the v2 `/api/upload/finalize`
6
+ * endpoint). */
7
+ export interface VideoUploadDetails {
8
+ /** TUS filename — the trailing segment of the upload URL. Required by
9
+ * 3Speak's legacy `/upload_info` endpoint. Empty for v2 uploads where
10
+ * the `uploadId` field below is the canonical identifier. */
11
+ filename: string;
12
+ /** The user's original file name (e.g. `IMG_1234.mp4`). */
13
+ originalFilename: string;
14
+ /** File size in bytes. */
15
+ fileSize: number;
16
+ /** Video duration in seconds (rounded). */
17
+ videoDuration: number;
18
+ /** Aspect ratio string (e.g. `"16/9"` or `"9/16"`). */
19
+ aspectRatio: string;
20
+ /** The 3Speak embed URL — `https://3speak.tv/embed?v=author/permlink`.
21
+ * Empty when uploading via the v2 endpoint (the embed URL is only
22
+ * knowable after the consumer runs `/api/upload/finalize`). */
23
+ embedUrl: string;
24
+ /** The TUS upload URL — `https://embed.3speak.tv/uploads/<filename>` or
25
+ * `https://video.3speak.tv/files/<filename>` depending on mode. */
26
+ uploadUrl: string;
27
+ /** Local thumbnail blob (JPEG). The kit always keeps this around so
28
+ * consumers can ship it to whichever thumbnail endpoint they use. */
29
+ thumbnailBlob: Blob | null;
30
+ /** Client-generated `upload_id` used by 3Speak's v2 finalize endpoint.
31
+ * Empty when the upload used the legacy embed.3speak.tv endpoint. */
32
+ uploadId: string;
33
+ /** `true` when the upload used the v2 `video.3speak.tv/files/` endpoint. */
34
+ isV2: boolean;
35
+ }
3
36
  export interface VideoUploaderProps {
4
37
  /** Called with embed URL, upload URL, aspect ratio, and optional local file for preview */
5
38
  onVideoUploaded: (videoEmbedUrl: string, uploadUrl: string, aspectRatio: string, localPreviewFile?: File) => void;
39
+ /**
40
+ * Called alongside `onVideoUploaded` with the full set of 3Speak-specific
41
+ * metadata. Consumers wiring the 3Speak Studio API (publish-via-3Speak)
42
+ * need every field to call `/upload_info` + `/update_info`. Existing
43
+ * snap composers don't need this path so the prop is optional.
44
+ */
45
+ onVideoUploadDetails?: (details: VideoUploadDetails) => void;
6
46
  /** Hive username for the upload */
7
47
  username?: string;
8
48
  /** Ecency image hosting token for thumbnail upload */
@@ -15,6 +55,62 @@ export interface VideoUploaderProps {
15
55
  /** When true, accept landscape videos too. Default false — only portrait
16
56
  * (vertical) clips are accepted, matching the hSnaps Moments contract. */
17
57
  allowLandscape?: boolean;
58
+ /**
59
+ * When true, the upload panel renders as a floating bottom-right card
60
+ * instead of a full-screen backdrop modal. The rest of the page stays
61
+ * interactive so the user can keep editing the post body, tags, etc.
62
+ * while the upload runs in the background. Default `false` keeps the
63
+ * existing modal behaviour for snap composers.
64
+ */
65
+ inline?: boolean;
66
+ /**
67
+ * Open-state controller (controlled mode). When provided, the parent owns
68
+ * panel visibility — useful in inline mode where the parent surfaces a
69
+ * minimized progress bar elsewhere on screen and reopens the panel on
70
+ * demand. When omitted the component manages its own state.
71
+ */
72
+ isOpen?: boolean;
73
+ /**
74
+ * Called whenever the panel's open state should change — when the user
75
+ * picks a file (`true`) or clicks the X button (`false`). Pair with
76
+ * `isOpen` for full control.
77
+ */
78
+ onIsOpenChange?: (open: boolean) => void;
79
+ /**
80
+ * Called with the current TUS upload progress, or `null` when no upload
81
+ * is in flight (idle / success / error). Lets the parent render a
82
+ * minimized progress chip while the panel is hidden.
83
+ */
84
+ onUploadProgress?: (progress: {
85
+ percentage: number;
86
+ bytesUploaded: number;
87
+ bytesTotal: number;
88
+ } | null) => void;
89
+ /**
90
+ * Optional async gate run after a file is selected and validated, but
91
+ * before the TUS upload starts. The consumer can use this to check
92
+ * external preconditions — e.g. that the user has granted `threespeak`
93
+ * posting authority — and resolve `false` to abort the upload (after
94
+ * showing its own UI). Resolving `true` lets the upload proceed.
95
+ *
96
+ * If omitted the upload starts unconditionally (existing behaviour).
97
+ */
98
+ beforeUpload?: () => Promise<boolean>;
99
+ /**
100
+ * When true, route the TUS upload through 3Speak's v2 endpoint at
101
+ * `https://video.3speak.tv/files/` with TUS metadata
102
+ * `{ upload_id, owner, filename, filetype }`. The kit generates a
103
+ * client-side `upload_id` (format `<owner>_<unix-ms>_<hex>`) and
104
+ * surfaces it via `VideoUploadDetails.uploadId` so the consumer can
105
+ * call `/api/upload/finalize` to publish the video. The Ecency /
106
+ * Hive thumbnail upload + `setThumbnailOn3Speak` step is skipped
107
+ * because the v2 frontend posts thumbnails to
108
+ * `/api/upload/thumbnail/<videoId>` after finalize.
109
+ *
110
+ * Default false keeps the legacy `embed.3speak.tv/uploads` flow used
111
+ * by the snap composer.
112
+ */
113
+ useThreeSpeakV2?: boolean;
18
114
  }
19
115
  declare const VideoUploader: React.FC<VideoUploaderProps>;
20
116
  export default VideoUploader;
@@ -3,7 +3,7 @@ export type { ImageUploaderProps } from './ImageUploader';
3
3
  export { default as AudioUploader } from './AudioUploader';
4
4
  export type { AudioUploaderProps } from './AudioUploader';
5
5
  export { default as VideoUploader } from './VideoUploader';
6
- export type { VideoUploaderProps } from './VideoUploader';
6
+ export type { VideoUploaderProps, VideoUploadDetails } from './VideoUploader';
7
7
  export { default as GiphyPicker } from './GiphyPicker';
8
8
  export type { GiphyPickerProps } from './GiphyPicker';
9
9
  export { default as EmojiPicker } from './EmojiPicker';
@@ -12,3 +12,7 @@ export { default as TemplatePicker } from './TemplatePicker';
12
12
  export type { TemplatePickerProps } from './TemplatePicker';
13
13
  export { default as PollCreator } from './PollCreator';
14
14
  export type { PollCreatorProps, PollData } from './PollCreator';
15
+ export { default as BeneficiariesEditor } from './BeneficiariesEditor';
16
+ export type { BeneficiariesEditorProps } from './BeneficiariesEditor';
17
+ export { default as ParentPostComposer } from './ParentPostComposer';
18
+ export type { ParentPostComposerProps, ParentPostSubmitPayload } from './ParentPostComposer';
@@ -51,6 +51,9 @@ export interface SnapsFeedCardProps {
51
51
  * menu with Edit / Delete / Flag). Receives the post so the host can
52
52
  * own edit/delete/flag state per card. */
53
53
  renderHeaderActions?: (post: Post) => ReactNode;
54
+ /** Collapse the per-card secondary actions (reblog · share · tip ·
55
+ * flag) into a single 3-dot kebab menu inside the action bar. */
56
+ actionsAsMenu?: boolean;
54
57
  }
55
58
  declare const SnapsFeedCard: FC<SnapsFeedCardProps>;
56
59
  export default SnapsFeedCard;
@@ -72,6 +72,10 @@ export interface SnapsFeedViewProps {
72
72
  /** Optional render slot for a per-card right-side header action menu
73
73
  * (Edit / Delete / Flag). Forwarded to every <SnapsFeedCard/>. */
74
74
  renderHeaderActions?: (post: import('@/types/post').Post) => ReactNode;
75
+ /** Collapse the per-card secondary actions (reblog · share · tip ·
76
+ * flag) into a single 3-dot kebab menu. Forwarded to every
77
+ * <SnapsFeedCard/>. */
78
+ actionsAsMenu?: boolean;
75
79
  }
76
- export declare function SnapsFeedView({ feeds, labels, avatars, defaultPrimary, currentUser, onUpvote, onSubmitComment, onClickCommentUpvote, onReblog, onTip, onSharePost, onCommentClick, onClickCommentIcon, onClickCommentCount, onReportPost, onUserClick, onPostClick, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, defaultVotePercent, voteWeightStep, allowLandscapeVideos, defaultReward, toolbar, footer, renderHeaderActions, }: SnapsFeedViewProps): import("react/jsx-runtime").JSX.Element;
80
+ export declare function SnapsFeedView({ feeds, labels, avatars, defaultPrimary, currentUser, onUpvote, onSubmitComment, onClickCommentUpvote, onReblog, onTip, onSharePost, onCommentClick, onClickCommentIcon, onClickCommentCount, onReportPost, onUserClick, onPostClick, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, defaultVotePercent, voteWeightStep, allowLandscapeVideos, defaultReward, toolbar, footer, renderHeaderActions, actionsAsMenu, }: SnapsFeedViewProps): import("react/jsx-runtime").JSX.Element;
77
81
  export default SnapsFeedView;
@@ -1,11 +1,12 @@
1
1
  import { Discussion } from '@/types/comment';
2
2
  import type { RewardOption } from '../../utils/commentOptions';
3
+ import type { Beneficiary } from '../../utils/beneficiaries';
3
4
  interface InlineCommentItemProps {
4
5
  comment: Discussion;
5
6
  allComments: Discussion[];
6
7
  onReply: (author: string, permlink: string) => void;
7
8
  onCancelReply: () => void;
8
- onCommentSubmit: (parentAuthor: string, parentPermlink: string, body: string) => Promise<void | boolean>;
9
+ onCommentSubmit: (parentAuthor: string, parentPermlink: string, body: string, beneficiaries?: Beneficiary[]) => Promise<void | boolean>;
9
10
  /** "author/permlink" key of the comment currently being replied to (null = none) */
10
11
  activeReplyKey: string | null;
11
12
  currentUser?: string;
@@ -29,6 +30,10 @@ interface InlineCommentItemProps {
29
30
  onUserClick?: (username: string) => void;
30
31
  /** Default reward routing seeded into every reply composer. */
31
32
  defaultReward?: RewardOption;
33
+ /** Beneficiaries pre-populated into every reply composer. */
34
+ defaultBeneficiaries?: Beneficiary[];
35
+ /** Suggested beneficiary chips shown inside every reply composer's editor. */
36
+ beneficiaryFavorites?: Beneficiary[];
32
37
  /** Initial percent for the comment-upvote slider AND reply composer's
33
38
  * upvote-on-publish slider. Default 100. */
34
39
  defaultVotePercent?: number;
@@ -44,5 +49,5 @@ interface InlineCommentItemProps {
44
49
  ipfsGateway?: string;
45
50
  };
46
51
  }
47
- export default function InlineCommentItem({ comment, allComments, onReply, onCancelReply, onCommentSubmit, activeReplyKey, currentUser, token, depth, onVotedRefresh, onClickCommentUpvote, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, hiveIconUrl, onShareComment, onTipComment, onReportComment, onNavigateToPost, onUserClick, defaultReward, defaultVotePercent, voteWeightStep, allowLandscapeVideos, renderOptions, }: InlineCommentItemProps): import("react/jsx-runtime").JSX.Element;
52
+ export default function InlineCommentItem({ comment, allComments, onReply, onCancelReply, onCommentSubmit, activeReplyKey, currentUser, token, depth, onVotedRefresh, onClickCommentUpvote, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, hiveIconUrl, onShareComment, onTipComment, onReportComment, onNavigateToPost, onUserClick, defaultReward, defaultBeneficiaries, beneficiaryFavorites, defaultVotePercent, voteWeightStep, allowLandscapeVideos, renderOptions, }: InlineCommentItemProps): import("react/jsx-runtime").JSX.Element;
48
53
  export {};
@@ -1,11 +1,13 @@
1
1
  import type { RewardOption } from '../../utils/commentOptions';
2
+ import type { Beneficiary } from '../../utils/beneficiaries';
2
3
  interface InlineCommentSectionProps {
3
4
  author: string;
4
5
  permlink: string;
5
6
  currentUser?: string;
6
7
  token?: string;
7
- /** `voteWeight` is non-null when the top-level composer's upvote-on-publish toggle is on (only fires for the post-reply composer). */
8
- onSubmitComment?: (parentAuthor: string, parentPermlink: string, body: string, voteWeight?: number | null) => void | boolean | Promise<void | boolean>;
8
+ /** `voteWeight` is non-null when the top-level composer's upvote-on-publish toggle is on (only fires for the post-reply composer).
9
+ * `beneficiaries` is the post-lock beneficiary list selected in the composer that triggered the submit. */
10
+ onSubmitComment?: (parentAuthor: string, parentPermlink: string, body: string, voteWeight?: number | null, beneficiaries?: Beneficiary[]) => void | boolean | Promise<void | boolean>;
9
11
  onClickCommentUpvote?: (author: string, permlink: string, percent: number) => void | Promise<void>;
10
12
  /** Show the upvote-on-publish toggle on the top-level composer. Auto-hidden when `alreadyVoted`. */
11
13
  showVoteButton?: boolean;
@@ -15,6 +17,10 @@ interface InlineCommentSectionProps {
15
17
  parentTags?: string[];
16
18
  /** Default reward routing seeded into every reply composer in this section. */
17
19
  defaultReward?: RewardOption;
20
+ /** Beneficiaries pre-populated into every reply composer in this section. */
21
+ defaultBeneficiaries?: Beneficiary[];
22
+ /** Suggested beneficiary chips shown inside every reply composer's editor. */
23
+ beneficiaryFavorites?: Beneficiary[];
18
24
  /** Initial percent for the "upvote on publish" slider in every reply composer. Default 100. */
19
25
  defaultVotePercent?: number;
20
26
  /** Slider precision (0.25, 0.5, or 1) used by every reply composer. Default 0.25. */
@@ -49,5 +55,5 @@ interface InlineCommentSectionProps {
49
55
  /** Intercept intra-body Hive profile links in comment bodies. */
50
56
  onUserClick?: (username: string) => void;
51
57
  }
52
- export default function InlineCommentSection({ author, permlink, currentUser, token, onSubmitComment, onClickCommentUpvote, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, reportedAuthors, reportedPosts, hiveIconUrl, onShareComment, onTipComment, onReportComment, onNavigateToPost, onUserClick, showVoteButton, alreadyVoted, parentTags, defaultReward, defaultVotePercent, voteWeightStep, allowLandscapeVideos, renderOptions, }: InlineCommentSectionProps): import("react/jsx-runtime").JSX.Element;
58
+ export default function InlineCommentSection({ author, permlink, currentUser, token, onSubmitComment, onClickCommentUpvote, ecencyToken, threeSpeakApiKey, giphyApiKey, templateToken, templateApiBaseUrl, reportedAuthors, reportedPosts, hiveIconUrl, onShareComment, onTipComment, onReportComment, onNavigateToPost, onUserClick, showVoteButton, alreadyVoted, parentTags, defaultReward, defaultBeneficiaries, beneficiaryFavorites, defaultVotePercent, voteWeightStep, allowLandscapeVideos, renderOptions, }: InlineCommentSectionProps): import("react/jsx-runtime").JSX.Element;
53
59
  export {};