From b643a8b1083b590b2115e9dfa617bbf8ec9b6617 Mon Sep 17 00:00:00 2001 From: Gregory Moskaliuk Date: Thu, 18 Jun 2026 21:46:48 +0200 Subject: [PATCH 1/3] feat: add selectionMenuConfig and formatMenuConfig props to EnrichedMarkdownTextInput Co-authored-by: Cursor --- docs/API_REFERENCE.md | 33 ++++++++ docs/COPY_OPTIONS.md | 11 +++ .../input/EnrichedMarkdownTextInputManager.kt | 14 ++++ .../input/toolbar/InputContextMenu.kt | 18 ++++- .../EnrichedMarkdownTextInput+ContextMenu.mm | 81 +++++++++++-------- .../EnrichedMarkdownTextInput+Internal.h | 6 ++ .../ios/input/EnrichedMarkdownTextInput.mm | 27 +++++-- .../src/EnrichedMarkdownTextInput.tsx | 33 ++++++++ ...nrichedMarkdownTextInputNativeComponent.ts | 11 +++ .../src/index.tsx | 1 + 10 files changed, 188 insertions(+), 47 deletions(-) diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index ce350ef2..bebb312b 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -689,6 +689,39 @@ interface ContextMenuItem { /> ``` +### `selectionMenuConfig` + +Controls built-in items in the text selection context menu. The Format submenu and the Copy as Markdown action can each be hidden independently. Custom app-provided actions are controlled separately with `contextMenuItems`. + +| Type | Default Value | Platform | +| -------------------------- | -------------------------------------- | ------------------- | +| `InputSelectionMenuConfig` | `{ format: true, copyAsMarkdown: true }` | iOS, Android, macOS | + +**`InputSelectionMenuConfig` shape:** + +```ts +interface InputSelectionMenuConfig { + /** Shows the built-in "Format" submenu (Bold, Italic, Underline, etc.). */ + format?: boolean; + /** Shows the built-in "Copy as Markdown" action. */ + copyAsMarkdown?: boolean; +} +``` + +**Example:** + +```tsx +// Hide both the Format submenu and the Copy as Markdown action + + +// Keep Format but hide Copy as Markdown + +``` + ### Ref Methods All methods are called imperatively on the ref (`ref.current?.methodName()`). diff --git a/docs/COPY_OPTIONS.md b/docs/COPY_OPTIONS.md index 6d4d944e..0ca0f71d 100644 --- a/docs/COPY_OPTIONS.md +++ b/docs/COPY_OPTIONS.md @@ -43,3 +43,14 @@ Use `selectionMenuConfig` to hide built-in selection menu actions while keeping }} /> ``` + +`EnrichedMarkdownTextInput` supports the same prop. In addition to `copyAsMarkdown`, the input's `selectionMenuConfig` can hide the built-in **Format** submenu: + +```tsx + +``` diff --git a/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt b/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt index 257d7548..0352d177 100644 --- a/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +++ b/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt @@ -31,6 +31,7 @@ import com.swmansion.enriched.markdown.input.events.OnRequestMarkdownResultEvent import com.swmansion.enriched.markdown.input.events.OnStartMentionEvent import com.swmansion.enriched.markdown.input.layout.InputMeasurementStore import com.swmansion.enriched.markdown.input.model.StyleType +import com.swmansion.enriched.markdown.input.toolbar.InputSelectionMenuConfig import com.swmansion.enriched.markdown.utils.input.BorderPropsApplicator import com.swmansion.enriched.markdown.utils.input.MarkdownStyleParser @@ -263,6 +264,19 @@ class EnrichedMarkdownTextInputManager : view.setContextMenuItems(items) } + @ReactProp(name = "selectionMenuConfig") + override fun setSelectionMenuConfig( + view: EnrichedMarkdownTextInputView?, + value: ReadableMap?, + ) { + if (view == null || value == null) return + view.contextMenu.selectionMenuConfig = + InputSelectionMenuConfig( + format = value.getBoolean("format"), + copyAsMarkdown = value.getBoolean("copyAsMarkdown"), + ) + } + @ReactProp(name = "linkRegex") override fun setLinkRegex( view: EnrichedMarkdownTextInputView?, diff --git a/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt b/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt index 38c0b70d..f2ec225d 100644 --- a/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +++ b/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt @@ -16,10 +16,16 @@ import com.swmansion.enriched.markdown.input.model.StyleType // TODO: Wrap all user-facing strings for localization support. +data class InputSelectionMenuConfig( + val format: Boolean = true, + val copyAsMarkdown: Boolean = true, +) + class InputContextMenu( private val view: EnrichedMarkdownTextInputView, ) { private var customItemTexts: List = emptyList() + var selectionMenuConfig: InputSelectionMenuConfig = InputSelectionMenuConfig() fun setContextMenuItems(items: List) { customItemTexts = items @@ -42,13 +48,17 @@ class InputContextMenu( menu.removeGroup(FORMAT_MENU_GROUP_ID) menu.removeGroup(CUSTOM_MENU_GROUP_ID) - val formatSubMenu = menu.addSubMenu(FORMAT_MENU_GROUP_ID, MENU_FORMAT_ID, 100, "Format") - FORMAT_ITEMS.forEachIndexed { index, (title, _) -> - formatSubMenu.add(Menu.NONE, MENU_FORMAT_ITEM_BASE + index, index, title) + if (selectionMenuConfig.format) { + val formatSubMenu = menu.addSubMenu(FORMAT_MENU_GROUP_ID, MENU_FORMAT_ID, 100, "Format") + FORMAT_ITEMS.forEachIndexed { index, (title, _) -> + formatSubMenu.add(Menu.NONE, MENU_FORMAT_ITEM_BASE + index, index, title) + } } if (view.selectionStart < view.selectionEnd) { - menu.add(FORMAT_MENU_GROUP_ID, MENU_COPY_MARKDOWN_ID, 101, "Copy as Markdown") + if (selectionMenuConfig.copyAsMarkdown) { + menu.add(FORMAT_MENU_GROUP_ID, MENU_COPY_MARKDOWN_ID, 101, "Copy as Markdown") + } customItemTexts.forEachIndexed { index, text -> menu diff --git a/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm b/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm index ced1c17c..9aa70a76 100644 --- a/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +++ b/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm @@ -25,14 +25,15 @@ - (UIMenu *)textView:(UITextView *)textView return nil; } + ENRMInputSelectionMenuConfig menuConfig = [self inputSelectionMenuConfig]; __weak EnrichedMarkdownTextInput *weakSelf = self; + // TODO: Localize titles with NSLocalizedString. static const struct { NSString *title; NSString *icon; ENRMInputStyleType styleType; } kFormatItems[] = { - // TODO: Localize titles with NSLocalizedString. {@"Bold", @"bold", ENRMInputStyleTypeStrong}, {@"Italic", @"italic", ENRMInputStyleTypeEmphasis}, {@"Underline", @"underline", ENRMInputStyleTypeUnderline}, @@ -91,8 +92,13 @@ - (UIMenu *)textView:(UITextView *)textView break; } } - [systemActions insertObject:formatMenu atIndex:insertIndex]; - [systemActions insertObject:copyMarkdownAction atIndex:insertIndex + 1]; + if (menuConfig.format) { + [systemActions insertObject:formatMenu atIndex:insertIndex]; + insertIndex++; + } + if (menuConfig.copyAsMarkdown) { + [systemActions insertObject:copyMarkdownAction atIndex:insertIndex]; + } [allActions addObjectsFromArray:systemActions]; return [UIMenu menuWithChildren:allActions]; @@ -104,6 +110,7 @@ - (NSMenu *)enrichedMenuForEvent:(NSEvent *)event defaultMenu:(NSMenu *)menu tex return menu; } + ENRMInputSelectionMenuConfig menuConfig = [self inputSelectionMenuConfig]; __weak EnrichedMarkdownTextInput *weakSelf = self; NSArray *customItems = ENRMBuildContextMenuItems([self contextMenuItemTexts], [self contextMenuItemIcons], textView, @@ -114,41 +121,45 @@ - (NSMenu *)enrichedMenuForEvent:(NSEvent *)event defaultMenu:(NSMenu *)menu tex [menu addItem:[NSMenuItem separatorItem]]; - NSMenuItem *copyMarkdownItem = [[NSMenuItem alloc] initWithTitle:@"Copy as Markdown" - action:@selector(copySelectedRangeAsMarkdown) - keyEquivalent:@""]; - copyMarkdownItem.target = self; - [menu addItem:copyMarkdownItem]; - - NSMenu *formatSubmenu = [[NSMenu alloc] initWithTitle:@"Format"]; - struct { - NSString *title; - SEL action; - NSString *key; - NSEventModifierFlags modifiers; - } const items[] = { - {@"Bold", @selector(toggleBold), @"b", NSEventModifierFlagCommand}, - {@"Italic", @selector(toggleItalic), @"i", NSEventModifierFlagCommand}, - {@"Underline", @selector(toggleUnderline), @"u", NSEventModifierFlagCommand}, - {@"Strikethrough", @selector(toggleStrikethrough), @"", 0}, - {@"Spoiler", @selector(toggleSpoiler), @"", 0}, - {@"Link", @selector(showLinkPrompt), @"", 0}, - }; + if (menuConfig.copyAsMarkdown) { + NSMenuItem *copyMarkdownItem = [[NSMenuItem alloc] initWithTitle:@"Copy as Markdown" + action:@selector(copySelectedRangeAsMarkdown) + keyEquivalent:@""]; + copyMarkdownItem.target = self; + [menu addItem:copyMarkdownItem]; + } - for (NSUInteger i = 0; i < sizeof(items) / sizeof(items[0]); i++) { - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:items[i].title - action:items[i].action - keyEquivalent:items[i].key]; - if (items[i].modifiers) { - item.keyEquivalentModifierMask = items[i].modifiers; + if (menuConfig.format) { + NSMenu *formatSubmenu = [[NSMenu alloc] initWithTitle:@"Format"]; + struct { + NSString *title; + SEL action; + NSString *key; + NSEventModifierFlags modifiers; + } const items[] = { + {@"Bold", @selector(toggleBold), @"b", NSEventModifierFlagCommand}, + {@"Italic", @selector(toggleItalic), @"i", NSEventModifierFlagCommand}, + {@"Underline", @selector(toggleUnderline), @"u", NSEventModifierFlagCommand}, + {@"Strikethrough", @selector(toggleStrikethrough), @"", 0}, + {@"Spoiler", @selector(toggleSpoiler), @"", 0}, + {@"Link", @selector(showLinkPrompt), @"", 0}, + }; + + for (NSUInteger i = 0; i < sizeof(items) / sizeof(items[0]); i++) { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:items[i].title + action:items[i].action + keyEquivalent:items[i].key]; + if (items[i].modifiers) { + item.keyEquivalentModifierMask = items[i].modifiers; + } + item.target = self; + [formatSubmenu addItem:item]; } - item.target = self; - [formatSubmenu addItem:item]; - } - NSMenuItem *formatItem = [[NSMenuItem alloc] initWithTitle:@"Format" action:nil keyEquivalent:@""]; - formatItem.submenu = formatSubmenu; - [menu addItem:formatItem]; + NSMenuItem *formatItem = [[NSMenuItem alloc] initWithTitle:@"Format" action:nil keyEquivalent:@""]; + formatItem.submenu = formatSubmenu; + [menu addItem:formatItem]; + } return menu; } diff --git a/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput+Internal.h b/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput+Internal.h index f02ae612..4319880a 100644 --- a/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput+Internal.h +++ b/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput+Internal.h @@ -5,6 +5,11 @@ NS_ASSUME_NONNULL_BEGIN +typedef struct { + BOOL format; + BOOL copyAsMarkdown; +} ENRMInputSelectionMenuConfig; + @interface EnrichedMarkdownTextInput (Internal) - (void)toggleBold; @@ -20,6 +25,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)emitContextMenuItemPress:(NSString *)itemText; - (NSArray *)contextMenuItemTexts; - (NSArray *)contextMenuItemIcons; +- (ENRMInputSelectionMenuConfig)inputSelectionMenuConfig; #if TARGET_OS_OSX - (NSMenu *)enrichedMenuForEvent:(NSEvent *)event defaultMenu:(NSMenu *)menu textView:(NSTextView *)textView; diff --git a/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput.mm b/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput.mm index bbf822b5..c243edaa 100644 --- a/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput.mm +++ b/packages/react-native-enriched-markdown/ios/input/EnrichedMarkdownTextInput.mm @@ -1,5 +1,4 @@ #import "EnrichedMarkdownTextInput.h" -#import #import "ContextMenuUtils.h" #import "ENRMAutoLinkDetector.h" #import "ENRMDetectorPipeline.h" @@ -17,9 +16,11 @@ #import "ENRMStyleMergingConfig.h" #import "ENRMUIKit.h" #import "ENRMWordsUtils.h" +#import "EnrichedMarkdownTextInput+Internal.h" #import "InputStylePropsUtils.h" #import "ParagraphStyleUtils.h" #import "SelectionColorUtils.h" +#import #import #if TARGET_OS_OSX #import @@ -91,6 +92,8 @@ @implementation EnrichedMarkdownTextInput { ENRMWritingDirectionMode _writingDirectionMode; NSWritingDirection _resolvedLayoutDirection; + + ENRMInputSelectionMenuConfig _inputSelectionMenuConfig; } #pragma mark - Fabric lifecycle @@ -128,6 +131,7 @@ - (instancetype)initWithFrame:(CGRect)frame _writingDirectionMode = ENRMWritingDirectionModeFirstStrong; _resolvedLayoutDirection = [[RCTI18nUtil sharedInstance] isRTL] ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight; + _inputSelectionMenuConfig = (ENRMInputSelectionMenuConfig){.format = YES, .copyAsMarkdown = YES}; [self setupTextView]; @@ -352,6 +356,11 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & _contextMenuItemIcons = ENRMContextMenuIconsFromItems(newViewProps.contextMenuItems); } + _inputSelectionMenuConfig = (ENRMInputSelectionMenuConfig){ + .format = newViewProps.selectionMenuConfig.format, + .copyAsMarkdown = newViewProps.selectionMenuConfig.copyAsMarkdown, + }; + if (newViewProps.mentionIndicators != oldViewProps.mentionIndicators) { NSMutableArray *indicators = [NSMutableArray array]; for (const auto &indicator : newViewProps.mentionIndicators) { @@ -964,8 +973,8 @@ - (void)resetPendingStylesForSelectionChange // Skip system-driven selection adjustments (e.g., predictive text) that fire // immediately after a text edit. static const CFTimeInterval kPostEditGracePeriod = 0.1; - BOOL isPostEditAdjustment = (_lastTextChangeTime > 0 && - (CACurrentMediaTime() - _lastTextChangeTime) < kPostEditGracePeriod); + BOOL isPostEditAdjustment = + (_lastTextChangeTime > 0 && (CACurrentMediaTime() - _lastTextChangeTime) < kPostEditGracePeriod); if (isPostEditAdjustment) { return; } @@ -983,11 +992,8 @@ - (void)rebuildPendingStylesFromContext } static const ENRMInputStyleType inlineStyles[] = { - ENRMInputStyleTypeStrong, - ENRMInputStyleTypeEmphasis, - ENRMInputStyleTypeUnderline, - ENRMInputStyleTypeStrikethrough, - ENRMInputStyleTypeSpoiler, + ENRMInputStyleTypeStrong, ENRMInputStyleTypeEmphasis, ENRMInputStyleTypeUnderline, + ENRMInputStyleTypeStrikethrough, ENRMInputStyleTypeSpoiler, }; for (NSUInteger i = 0; i < sizeof(inlineStyles) / sizeof(inlineStyles[0]); i++) { @@ -1236,6 +1242,11 @@ - (void)emitCaretRectChangeIfNeeded return _contextMenuItemIcons ?: @[]; } +- (ENRMInputSelectionMenuConfig)inputSelectionMenuConfig +{ + return _inputSelectionMenuConfig; +} + - (void)emitContextMenuItemPress:(NSString *)itemText { auto eventEmitter = [self getEventEmitter]; diff --git a/packages/react-native-enriched-markdown/src/EnrichedMarkdownTextInput.tsx b/packages/react-native-enriched-markdown/src/EnrichedMarkdownTextInput.tsx index 017ea3b4..3aaa5f6d 100644 --- a/packages/react-native-enriched-markdown/src/EnrichedMarkdownTextInput.tsx +++ b/packages/react-native-enriched-markdown/src/EnrichedMarkdownTextInput.tsx @@ -112,6 +112,21 @@ export interface EnrichedMarkdownTextInputInstance { getCaretRect: () => Promise; } +export interface InputSelectionMenuConfig { + /** + * Shows the built-in "Format" submenu (Bold, Italic, Underline, etc.) + * in the text selection context menu. + * @default true + */ + format?: boolean; + /** + * Shows the built-in "Copy as Markdown" action in the text selection + * context menu. + * @default true + */ + copyAsMarkdown?: boolean; +} + export interface EnrichedMarkdownTextInputProps extends Omit< ViewProps, 'style' | 'children' @@ -142,6 +157,14 @@ export interface EnrichedMarkdownTextInputProps extends Omit< onFocus?: () => void; onBlur?: () => void; contextMenuItems?: ContextMenuItem[]; + /** + * Controls built-in items in the text selection context menu. + * Omitting the prop or any field reproduces today's exact menu. + * Custom app-provided actions are controlled separately via `contextMenuItems`. + * @default { format: true, copyAsMarkdown: true } + * @platform ios, android, macos + */ + selectionMenuConfig?: InputSelectionMenuConfig; linkRegex?: RegExp | null; /** * Paragraph writing direction. @@ -203,6 +226,7 @@ export const EnrichedMarkdownTextInput = ({ onFocus, onBlur, contextMenuItems, + selectionMenuConfig, linkRegex: _linkRegex, writingDirection = 'first-strong', ...rest @@ -251,6 +275,14 @@ export const EnrichedMarkdownTextInput = ({ const normalizedStyle = normalizeMarkdownTextInputStyle(markdownStyle); + const normalizedSelectionMenuConfig = useMemo( + () => ({ + format: selectionMenuConfig?.format ?? true, + copyAsMarkdown: selectionMenuConfig?.copyAsMarkdown ?? true, + }), + [selectionMenuConfig] + ); + const linkRegex = useMemo( () => toNativeRegexConfig(_linkRegex), [_linkRegex] @@ -461,6 +493,7 @@ export const EnrichedMarkdownTextInput = ({ handleCaretRectChange as NativeProps['onCaretRectChange'] } contextMenuItems={nativeContextMenuItems} + selectionMenuConfig={normalizedSelectionMenuConfig} mentionIndicators={mentionIndicators} onContextMenuItemPress={ handleContextMenuItemPress as NativeProps['onContextMenuItemPress'] diff --git a/packages/react-native-enriched-markdown/src/EnrichedMarkdownTextInputNativeComponent.ts b/packages/react-native-enriched-markdown/src/EnrichedMarkdownTextInputNativeComponent.ts index 041435dd..46292345 100644 --- a/packages/react-native-enriched-markdown/src/EnrichedMarkdownTextInputNativeComponent.ts +++ b/packages/react-native-enriched-markdown/src/EnrichedMarkdownTextInputNativeComponent.ts @@ -113,6 +113,11 @@ export interface ContextMenuItemConfig { icon?: string; } +export interface InputSelectionMenuConfigInternal { + format: boolean; + copyAsMarkdown: boolean; +} + export interface OnContextMenuItemPressEvent { itemText: string; selectedText: string; @@ -198,6 +203,12 @@ export interface NativeProps extends ViewProps { */ contextMenuItems?: ReadonlyArray>; + /** + * Controls built-in items in the text selection context menu. + * `format` toggles the Format submenu; `copyAsMarkdown` toggles the Copy as Markdown action. + */ + selectionMenuConfig: Readonly; + /** * Regex configuration for automatic link detection. * Omit or pass undefined to use platform defaults. diff --git a/packages/react-native-enriched-markdown/src/index.tsx b/packages/react-native-enriched-markdown/src/index.tsx index b180ff42..4d7ac2b9 100644 --- a/packages/react-native-enriched-markdown/src/index.tsx +++ b/packages/react-native-enriched-markdown/src/index.tsx @@ -20,6 +20,7 @@ export type { MarkdownTextInputStyle, StyleState, ContextMenuItem, + InputSelectionMenuConfig, OnLinkDetected, OnStartMentionEvent, OnChangeMentionEvent, From e637e9463737fd74c457f0187a877e46b50ac093 Mon Sep 17 00:00:00 2001 From: Gregory Moskaliuk Date: Fri, 19 Jun 2026 11:25:05 +0200 Subject: [PATCH 2/3] fix: handle null value in selectionMenuConfig for EnrichedMarkdownTextInput --- .../input/EnrichedMarkdownTextInputManager.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt b/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt index 0352d177..391d5061 100644 --- a/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +++ b/packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt @@ -269,12 +269,16 @@ class EnrichedMarkdownTextInputManager : view: EnrichedMarkdownTextInputView?, value: ReadableMap?, ) { - if (view == null || value == null) return + if (view == null) return view.contextMenu.selectionMenuConfig = - InputSelectionMenuConfig( - format = value.getBoolean("format"), - copyAsMarkdown = value.getBoolean("copyAsMarkdown"), - ) + if (value == null) { + InputSelectionMenuConfig() + } else { + InputSelectionMenuConfig( + format = value.getBoolean("format"), + copyAsMarkdown = value.getBoolean("copyAsMarkdown"), + ) + } } @ReactProp(name = "linkRegex") From 5b975f9286b5b9f2caa0d7026a87acc7415a94a9 Mon Sep 17 00:00:00 2001 From: Gregory Moskaliuk Date: Fri, 19 Jun 2026 11:54:49 +0200 Subject: [PATCH 3/3] feat: add story for SelectionMenu in EnrichedMarkdownTextInput --- .../props/SelectionMenu.stories.tsx | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 apps/example/.rnstorybook/stories/components/EnrichedMarkdownTextInput/props/SelectionMenu.stories.tsx diff --git a/apps/example/.rnstorybook/stories/components/EnrichedMarkdownTextInput/props/SelectionMenu.stories.tsx b/apps/example/.rnstorybook/stories/components/EnrichedMarkdownTextInput/props/SelectionMenu.stories.tsx new file mode 100644 index 00000000..9585b415 --- /dev/null +++ b/apps/example/.rnstorybook/stories/components/EnrichedMarkdownTextInput/props/SelectionMenu.stories.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { EnrichedMarkdownTextInputStory } from '../EnrichedMarkdownTextInputStory'; +import { storyMeta } from '../shared/storyMeta'; +import type { InputStory } from '../shared/storyTypes'; + +type SelectionMenuStoryExtra = { + format: boolean; + copyAsMarkdown: boolean; +}; + +const MARKDOWN = + 'Select this text and open the context menu to see the built-in actions.'; + +const argTypes = { + format: { + control: 'boolean', + description: + 'selectionMenuConfig.format — show the "Format" submenu (Bold, Italic, etc.) in the selection menu.', + }, + copyAsMarkdown: { + control: 'boolean', + description: + 'selectionMenuConfig.copyAsMarkdown — show "Copy as Markdown" in the selection menu.', + }, +}; + +export default storyMeta('Props', 'Selection Menu'); + +export const Default: InputStory = { + args: { + initialMarkdown: MARKDOWN, + format: true, + copyAsMarkdown: true, + }, + argTypes, + render: ({ format, copyAsMarkdown, ...args }) => ( + + ), +};