Skip to content

[SBISSUE-21270] feat: Export useMentionTextInput, EditInput and add placeholder prop#301

Open
OnestarLee wants to merge 2 commits intomainfrom
feat/channel-input-customization
Open

[SBISSUE-21270] feat: Export useMentionTextInput, EditInput and add placeholder prop#301
OnestarLee wants to merge 2 commits intomainfrom
feat/channel-input-customization

Conversation

@OnestarLee
Copy link
Copy Markdown
Collaborator

@OnestarLee OnestarLee commented Mar 31, 2026

For Internal Contributors

SBISSUE-21270

Description Of Changes

배경

Samsara 고객이 커스텀 ChannelInput 구현을 위해 내부 경로에서 직접 import하고 있던 항목들을 public API로 제공합니다.

고객이 커스텀 Input을 만든 이유:

  • 전송 흐름에 analytics 주입 (conversation type, sender role, reply status)
  • 자체 디자인 시스템의 입력 레이아웃 사용
  • 자체 번역 시스템의 placeholder 텍스트 제공
  • 커스텀 첨부파일 시트 및 멘션 리스트 사용

고객이 내부 import에 의존하던 5개 항목 중 3개(useChannelInputItems, MessageToReplyPreview, GroupChannelPreviewContainer)는 고객이 이미 public API로 자체 구현 완료했으며, 남은 2개(useMentionTextInput, EditInput)와 타입(ChannelInputProps)을 이번에 공식 export합니다.

구현 방식 선택 이유

내부 hook/component를 직접 export하는 방식(Approach A)을 선택했습니다.

검토한 대안 (Approach B: renderInput prop):

  • ChannelInput에 renderInput 콜백 prop을 추가하여 UIKit이 프레임워크(keyboard, safe area, mention state)를 관리하고 고객은 콘텐츠만 커스터마이징하는 방식
  • 장기적 유지보수에 유리하나, 기존 renderMessage 등 하위 렌더러 override 패턴과 개념이 다름 (모듈 콘텐츠 전체 교체)
  • 고객의 기존 코드 전면 재작성 필요

선택한 방식 (Approach A: Export):

  • 기존 hook export 패턴(useConnection, usePushTokenRegistration)과 동일
  • 고객 코드 변경 최소 (내부 import 경로 → public import 경로 변경만)
  • 반환 인터페이스가 텍스트 입력 + 멘션의 본질적 상태라 실질적으로 안정적

변경 내용

  • useMentionTextInput hook을 public export + 명시적 파라미터/반환 타입(UseMentionTextInputParams, UseMentionTextInputReturn) 추가
  • EditInput component를 public export
  • ChannelInputProps type을 public export
  • ChannelInputPropsplaceholder optional prop 추가
    • 커스텀 placeholder가 모든 기본 localization 문자열(muted/frozen/disabled 포함)보다 우선 적용
    • GroupChannel, OpenChannel, GroupChannelThread의 Fragment → Module.Input으로 pass-through

Types Of Changes

  • Bugfix
  • New feature
  • Documentation (correction or otherwise)
  • Cosmetics (whitespace, appearance (ex) Prettier)
  • Build configuration
  • Improvement (refactor code)
  • Test

@OnestarLee OnestarLee requested review from bang9 and Copilot March 31, 2026 06:10
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Mar 31, 2026

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 10.84%. Comparing base (03f53ed) to head (c81c277).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
...t-native/src/components/ChannelInput/SendInput.tsx 0.00% 1 Missing ⚠️
...ikit-react-native/src/hooks/useMentionTextInput.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #301      +/-   ##
==========================================
- Coverage   10.84%   10.84%   -0.01%     
==========================================
  Files         360      360              
  Lines        9083     9084       +1     
  Branches     2577     2442     -135     
==========================================
  Hits          985      985              
- Misses       8022     8098      +76     
+ Partials       76        1      -75     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR exposes previously internal ChannelInput building blocks as public APIs and adds a placeholder prop to support fully customized input implementations without relying on internal import paths.

Changes:

  • Export useMentionTextInput (with explicit param/return types) and EditInput as public APIs.
  • Export ChannelInputProps as a public type and extend it with an optional placeholder prop.
  • Plumb placeholder through Group/Open/Thread fragments and domain prop types into ChannelInput, with override precedence over all default localized placeholders.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/uikit-react-native/src/index.ts Publicly exports ChannelInputProps, EditInput, and useMentionTextInput (+ types).
packages/uikit-react-native/src/hooks/useMentionTextInput.ts Adds explicit exported param/return interfaces and updates hook signature accordingly.
packages/uikit-react-native/src/fragments/createOpenChannelFragment.tsx Accepts placeholder and passes it through to Module.Input.
packages/uikit-react-native/src/fragments/createGroupChannelThreadFragment.tsx Accepts placeholder and passes it through to Module.Input.
packages/uikit-react-native/src/fragments/createGroupChannelFragment.tsx Accepts placeholder and passes it through to Module.Input.
packages/uikit-react-native/src/domain/openChannel/types.ts Adds placeholder to Fragment props and Input pick list.
packages/uikit-react-native/src/domain/groupChannelThread/types.ts Adds placeholder to Fragment props and Input pick list.
packages/uikit-react-native/src/domain/groupChannel/types.ts Adds placeholder to Fragment props and Input pick list.
packages/uikit-react-native/src/components/ChannelInput/SendInput.tsx Implements placeholder override priority in getPlaceholder().
packages/uikit-react-native/src/components/ChannelInput/index.tsx Adds placeholder?: string to ChannelInputProps with documentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 177 to 182
const getPlaceholder = () => {
if (placeholder) return placeholder;

if (inputMuted) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_MUTED;
if (inputFrozen) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
if (inputDisabled) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

placeholder is checked with a truthy condition (if (placeholder) ...), so passing an empty string (valid for some translation systems) won’t override the default placeholders and will fall back to the localized strings. Consider checking for placeholder !== undefined / placeholder != null instead so an explicit empty string still takes precedence as documented.

Copilot uses AI. Check for mistakes.
// TextInput props - only safe properties that don't interfere with UIKit functionality
partialTextInputProps?: Partial<Pick<TextInputProps, 'autoCorrect'>>;

/** Custom placeholder text that overrides all default localization strings including muted/frozen/disabled states. */
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The placeholder prop is documented as overriding default localization strings, but it’s currently only applied in SendInput (edit mode still uses STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_ACTIVE). Either apply placeholder to EditInput as well or clarify this doc comment to indicate it only affects the send input placeholder logic.

Suggested change
/** Custom placeholder text that overrides all default localization strings including muted/frozen/disabled states. */
/**
* Custom placeholder text for the send input.
* Overrides default localization strings (including muted/frozen/disabled states) for send mode only.
* Edit mode continues to use the default localized edit placeholder.
*/

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +16
@@ -7,8 +7,21 @@ import { SendbirdFileMessage, SendbirdUserMessage, replace, useFreshCallback } f
import type { MentionedUser } from '../types';
import { useSendbirdChat } from './useContext';

export interface UseMentionTextInputParams {
messageToEdit?: SendbirdUserMessage | SendbirdFileMessage;
}

export interface UseMentionTextInputReturn {
textInputRef: React.RefObject<TextInput | undefined>;
selection: { start: number; end: number };
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React default import is only used for the React.RefObject type reference, so it will remain as an extra (unused-at-runtime) default import in the emitted JS. Consider switching to type-only imports (e.g., import type RefObject from react and use RefObject<...>) so the runtime bundle doesn’t pull in an unnecessary default binding.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

@bang9 bang9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed via roc-pr-review

}

export interface UseMentionTextInputReturn {
textInputRef: RefObject<TextInput | undefined>;
Copy link
Copy Markdown
Collaborator

@bang9 bang9 Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 공개 hook의 ref 타입이 실제 TextInput ref와 바로 호환되지 않습니다

UseMentionTextInputReturntextInputRef: RefObject<TextInput | undefined>를 public API로 노출합니다. 그런데 UIKit 내부 구현도 이 ref를 다시 연결할 때 ref={textInputRef as never} 캐스트로 우회하고 있습니다. 외부 소비자가 useMentionTextInput를 써서 custom input을 만들면, strict TypeScript 환경에서는 같은 unsafe cast를 강요받게 됩니다.

Suggestion: useRef<TextInput>(null)처럼 RN ref prop이 직접 받을 수 있는 shape로 맞추고, 공개 타입도 RefObject<TextInput | null> 또는 실제 사용 컴포넌트가 허용하는 ref 타입과 일치시키는 편이 안전합니다.

Suggested change
textInputRef: RefObject<TextInput | undefined>;
textInputRef: RefObject<TextInput | null>;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants