[SBISSUE-21270] feat: Export useMentionTextInput, EditInput and add placeholder prop#301
[SBISSUE-21270] feat: Export useMentionTextInput, EditInput and add placeholder prop#301OnestarLee wants to merge 2 commits intomainfrom
Conversation
Codecov Report❌ Patch coverage is
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. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
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) andEditInputas public APIs. - Export
ChannelInputPropsas a public type and extend it with an optionalplaceholderprop. - Plumb
placeholderthrough Group/Open/Thread fragments and domain prop types intoChannelInput, 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.
| 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; |
There was a problem hiding this comment.
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.
| // 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. */ |
There was a problem hiding this comment.
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.
| /** 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. | |
| */ |
| @@ -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 }; | |||
There was a problem hiding this comment.
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.
bang9
left a comment
There was a problem hiding this comment.
Reviewed via roc-pr-review
| } | ||
|
|
||
| export interface UseMentionTextInputReturn { | ||
| textInputRef: RefObject<TextInput | undefined>; |
There was a problem hiding this comment.
[P2] 공개 hook의 ref 타입이 실제 TextInput ref와 바로 호환되지 않습니다
UseMentionTextInputReturn가 textInputRef: 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 타입과 일치시키는 편이 안전합니다.
| textInputRef: RefObject<TextInput | undefined>; | |
| textInputRef: RefObject<TextInput | null>; |
For Internal Contributors
SBISSUE-21270
Description Of Changes
배경
Samsara 고객이 커스텀 ChannelInput 구현을 위해 내부 경로에서 직접 import하고 있던 항목들을 public API로 제공합니다.
고객이 커스텀 Input을 만든 이유:
고객이 내부 import에 의존하던 5개 항목 중 3개(
useChannelInputItems,MessageToReplyPreview,GroupChannelPreviewContainer)는 고객이 이미 public API로 자체 구현 완료했으며, 남은 2개(useMentionTextInput,EditInput)와 타입(ChannelInputProps)을 이번에 공식 export합니다.구현 방식 선택 이유
내부 hook/component를 직접 export하는 방식(Approach A)을 선택했습니다.
검토한 대안 (Approach B: renderInput prop):
renderInput콜백 prop을 추가하여 UIKit이 프레임워크(keyboard, safe area, mention state)를 관리하고 고객은 콘텐츠만 커스터마이징하는 방식renderMessage등 하위 렌더러 override 패턴과 개념이 다름 (모듈 콘텐츠 전체 교체)선택한 방식 (Approach A: Export):
useConnection,usePushTokenRegistration)과 동일변경 내용
useMentionTextInputhook을 public export + 명시적 파라미터/반환 타입(UseMentionTextInputParams,UseMentionTextInputReturn) 추가EditInputcomponent를 public exportChannelInputPropstype을 public exportChannelInputProps에placeholderoptional prop 추가Types Of Changes