@sendbird/ai-agent-messenger-react 1.26.1 → 1.28.0

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/dist/index.d.ts CHANGED
@@ -238,7 +238,7 @@ queryParams?: AIAgentQueryParams;
238
238
  * @public
239
239
  * @description AIAgent global default config.
240
240
  * */
241
- config?: AIAgentConfig;
241
+ config?: DeepPartial<AIAgentConfig_2>;
242
242
  /** @internal */
243
243
  deskParams?: {
244
244
  customApiHost?: string;
@@ -392,6 +392,14 @@ declare type AIAgentChatSDKParams = ChatSDKSendbirdChatParams<[ChatSDKGroupChann
392
392
 
393
393
  declare interface AIAgentClientHandlers {
394
394
  onCustomEvent?: (event: CustomEvent_2) => void;
395
+ /**
396
+ * Called whenever the SDK opens an external URL — markdown links, admin-message
397
+ * URLs, citation links, CTA buttons, and non-media file-preview clicks.
398
+ * Provide this to intercept link navigation (analytics, deep links, custom
399
+ * schemes). When omitted, the SDK falls back to `window.open` on web and
400
+ * `Linking.openURL` on React Native.
401
+ */
402
+ onClickLink?: (params: { url: string }) => void;
395
403
  }
396
404
 
397
405
  declare type AIAgentCommonIconName =
@@ -426,69 +434,98 @@ declare type AIAgentCommonIconName =
426
434
  | 'download'
427
435
  | 'memory';
428
436
 
429
- export declare interface AIAgentConfig {
430
- conversation?: {
431
- /**
432
- * Whether to show the "Start new conversation" button at the end of the message list.
433
- * @default true
434
- * */
435
- isTalkToAgentViewEnabled?: boolean;
436
- /**
437
- * Controls the scroll behavior of the conversation.
438
- * - `auto`: Automatically scrolls to bottom on new messages and streaming.
439
- * - `fixed`: Pins new messages at viewport top, maintains position during streaming.
440
- * @default 'auto'
441
- * */
442
- scrollMode?: ConversationScrollMode;
443
- /**
444
- * Whether to show the new message indicator button when scrolled away from bottom.
445
- * @default true
446
- * */
447
- newMessageIndicatorEnabled?: boolean;
448
- /**
449
- * Whether to show the sender's avatar image next to each message.
450
- * @default true
451
- * */
452
- senderAvatarEnabled?: boolean;
453
- header?: {
437
+ /**
438
+ * Public input shape for the AI Agent config. Deep-partial of the canonical
439
+ * resolved config the SDK consumes internally — every field is optional so
440
+ * callers only supply the values they want to override. `mergeAIAgentConfig`
441
+ * fills in the rest before reaching React contexts.
442
+ */
443
+ export declare type AIAgentConfig = DeepPartial<AIAgentConfig_2>;
444
+
445
+ /**
446
+ * Canonical AI Agent config every field is required after `mergeAIAgentConfig`.
447
+ * User-facing input uses `DeepPartial<AIAgentConfig>`.
448
+ */
449
+ declare interface AIAgentConfig_2 {
450
+ conversation: {
451
+ /** @deprecated Use `list.isTalkToAgentViewEnabled` instead. */
452
+ isTalkToAgentViewEnabled: boolean;
453
+ /** @deprecated Use `list.scrollMode` instead. */
454
+ scrollMode: ConversationScrollMode;
455
+ /** @deprecated Use `list.newMessageIndicatorEnabled` instead. */
456
+ newMessageIndicatorEnabled: boolean;
457
+ /** @deprecated Use `list.senderAvatarEnabled` instead. */
458
+ senderAvatarEnabled: boolean;
459
+ list: {
460
+ /**
461
+ * Whether to show the "Start new conversation" button at the end of the message list.
462
+ * @default true
463
+ * */
464
+ isTalkToAgentViewEnabled: boolean;
465
+ /**
466
+ * Controls the scroll behavior of the conversation.
467
+ * - `auto`: Automatically scrolls to bottom on new messages and streaming.
468
+ * - `fixed`: Pins new messages at viewport top, maintains position during streaming.
469
+ * @default 'auto'
470
+ * */
471
+ scrollMode: ConversationScrollMode;
472
+ /**
473
+ * Whether to show the new message indicator button when scrolled away from bottom.
474
+ * @default true
475
+ * */
476
+ newMessageIndicatorEnabled: boolean;
477
+ /**
478
+ * Whether to show the sender's avatar image next to each message.
479
+ * @default true
480
+ * */
481
+ senderAvatarEnabled: boolean;
482
+ /**
483
+ * Controls how markdown images are displayed while a message is streaming.
484
+ * - `default`: Renders partial markdown as-is.
485
+ * - `complete-only`: Hides incomplete image markdown until the image token is complete.
486
+ * @default 'default'
487
+ * */
488
+ markdownImageRenderMode: MarkdownImageRenderMode;
489
+ };
490
+ header: {
454
491
  /**
455
492
  * Whether to show the avatar in the conversation header.
456
493
  * @default true
457
494
  * */
458
- avatarEnabled?: boolean;
495
+ avatarEnabled: boolean;
459
496
  };
460
- input?: {
497
+ input: {
461
498
  /**
462
499
  * (React-Native only) Whether to enable the camera option in the attachment menu.
463
500
  * */
464
- camera?: {
465
- photoEnabled?: boolean;
501
+ camera: {
502
+ photoEnabled: boolean;
466
503
  };
467
504
  /**
468
505
  * Whether to enable the gallery/photo option in the attachment menu.
469
506
  * */
470
- gallery?: {
471
- photoEnabled?: boolean;
507
+ gallery: {
508
+ photoEnabled: boolean;
472
509
  };
473
510
  /**
474
511
  * Whether to enable the file option in the attachment menu.
475
512
  * */
476
- fileEnabled?: boolean;
513
+ fileEnabled: boolean;
477
514
  };
478
515
  /**
479
516
  * (React only) Whether to play an alert sound when a message is received from the AI agent while the browser is not focused.
480
517
  * @default false
481
518
  * */
482
- messageAlertSoundEnabled?: boolean;
519
+ messageAlertSoundEnabled: boolean;
483
520
  /**
484
521
  * File viewer configuration.
485
522
  * */
486
- fileViewer?: {
523
+ fileViewer: {
487
524
  /**
488
525
  * Whether to show the download button in the file viewer.
489
526
  * @default true
490
527
  * */
491
- downloadEnabled?: boolean;
528
+ downloadEnabled: boolean;
492
529
  };
493
530
  };
494
531
  }
@@ -513,7 +550,7 @@ declare interface AIAgentContextValue {
513
550
  networkStateAdapter?: NetworkStateAdapter;
514
551
 
515
552
  queryParams?: AIAgentQueryParams;
516
- config?: AIAgentConfig;
553
+ config: AIAgentConfig_2;
517
554
 
518
555
  handlers?: AIAgentClientHandlers;
519
556
  }
@@ -651,9 +688,9 @@ declare interface AIAgentInterface {
651
688
  readonly session: AIAgentSession | null;
652
689
  /** The Desk client. Available after authenticate(). */
653
690
  readonly deskClient: DeskClientInterface;
654
- // TODO: Change to `AIAgentConfig` (non-optional) once the context migration lands and all usages are updated
655
- /** The AI Agent configuration */
656
- config: AIAgentConfig | undefined;
691
+ /** The AI Agent configuration. */
692
+ get config(): AIAgentConfig_2;
693
+ set config(value: DeepPartial<AIAgentConfig_2> | undefined);
657
694
  /** The query parameters for AI Agent */
658
695
  queryParams?: AIAgentQueryParams;
659
696
  /** The adapter for detecting online/offline network state */
@@ -887,7 +924,7 @@ export declare type AIAgentProps = PropsWithChildren<{
887
924
  * @public
888
925
  * @description AIAgent global default config.
889
926
  * */
890
- config?: AIAgentConfig;
927
+ config?: DeepPartial<AIAgentConfig_2>;
891
928
  /** @internal */
892
929
  deskParams?: {
893
930
  customApiHost?: string;
@@ -1100,6 +1137,7 @@ declare interface AIAgentStringSet {
1100
1137
  a11y_hint_open_conversation: string;
1101
1138
  a11y_hint_open_conversations: string;
1102
1139
  a11y_hint_close_conversation: string;
1140
+ a11y_hint_close_messenger: string;
1103
1141
  a11y_hint_open_menu: string;
1104
1142
  a11y_hint_connect_to_agent: string;
1105
1143
  a11y_hint_attach_file: string;
@@ -1258,6 +1296,7 @@ declare type BaseMessageProps<T> = T & {
1258
1296
  onClickMedia?: (params: { url: string; type: string }) => void;
1259
1297
  onClickMediaFiles?: (params: { files: Array<{ url: string; type: string; name?: string }>; index: number }) => void;
1260
1298
  onClickFile?: (params: { url: string; type: string }) => void;
1299
+ onClickLink?: (params: { url: string }) => void;
1261
1300
 
1262
1301
  children?: ReactNode;
1263
1302
  };
@@ -2155,14 +2194,12 @@ declare interface ConversationListContextProps {
2155
2194
  conversationListLimit?: number;
2156
2195
  conversationListFilter?: Partial<AIAgentGroupChannelFilter>;
2157
2196
  onOpenConversationView?: (channelUrl: string, status: 'open' | 'closed') => void;
2158
- announcementsEnabled?: boolean;
2159
2197
  }
2160
2198
 
2161
- export declare function ConversationListContextProvider({ conversationListLimit, conversationListFilter, onOpenConversationView, announcementsEnabled, children, }: PropsWithChildren<ConversationListContextProps>): JSX.Element;
2199
+ export declare function ConversationListContextProvider({ conversationListLimit, conversationListFilter, onOpenConversationView, children, }: PropsWithChildren<ConversationListContextProps>): JSX.Element;
2162
2200
 
2163
2201
  declare interface ConversationListContextValue extends AIAgentConversationListContextValue {
2164
2202
  onOpenConversationView: (channelUrl: string, status: 'open' | 'closed') => void;
2165
- announcementsEnabled: boolean;
2166
2203
  }
2167
2204
 
2168
2205
  export declare const ConversationListHeaderLayout: {
@@ -2397,6 +2434,11 @@ export declare type DateSeparatorProps = SBUFoundationProps<{
2397
2434
  date?: Date | number;
2398
2435
  }>;
2399
2436
 
2437
+ /**
2438
+ * Recursively makes every property of T optional, including nested objects.
2439
+ */
2440
+ declare type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
2441
+
2400
2442
  export declare const DefaultMessenger: ForwardRefExoticComponent<MessengerProps & RefAttributes<MessengerSessionRef>>;
2401
2443
 
2402
2444
  export declare interface DeskClientInterface {
@@ -2667,6 +2709,7 @@ BaseMessageProps<{
2667
2709
  isFeedbackEnabled?: boolean;
2668
2710
  isFeedbackCommentEnabled?: boolean;
2669
2711
  isSenderAvatarVisible?: boolean;
2712
+ markdownImageRenderMode?: MarkdownImageRenderMode;
2670
2713
 
2671
2714
  // handlers
2672
2715
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
@@ -2746,6 +2789,7 @@ export declare const IncomingMessageLayout: {
2746
2789
  isFeedbackEnabled?: boolean;
2747
2790
  isFeedbackCommentEnabled?: boolean;
2748
2791
  isSenderAvatarVisible?: boolean;
2792
+ markdownImageRenderMode?: MarkdownImageRenderMode;
2749
2793
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
2750
2794
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
2751
2795
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -2794,6 +2838,9 @@ export declare const IncomingMessageLayout: {
2794
2838
  url: string;
2795
2839
  type: string;
2796
2840
  }) => void;
2841
+ onClickLink?: (params: {
2842
+ url: string;
2843
+ }) => void;
2797
2844
  children?: ReactNode;
2798
2845
  }) | ({
2799
2846
  messageType: "file";
@@ -2819,6 +2866,7 @@ export declare const IncomingMessageLayout: {
2819
2866
  isFeedbackEnabled?: boolean;
2820
2867
  isFeedbackCommentEnabled?: boolean;
2821
2868
  isSenderAvatarVisible?: boolean;
2869
+ markdownImageRenderMode?: MarkdownImageRenderMode;
2822
2870
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
2823
2871
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
2824
2872
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -2867,6 +2915,9 @@ export declare const IncomingMessageLayout: {
2867
2915
  url: string;
2868
2916
  type: string;
2869
2917
  }) => void;
2918
+ onClickLink?: (params: {
2919
+ url: string;
2920
+ }) => void;
2870
2921
  children?: ReactNode;
2871
2922
  }) | ({
2872
2923
  messageType: "multipleFiles";
@@ -2892,6 +2943,7 @@ export declare const IncomingMessageLayout: {
2892
2943
  isFeedbackEnabled?: boolean;
2893
2944
  isFeedbackCommentEnabled?: boolean;
2894
2945
  isSenderAvatarVisible?: boolean;
2946
+ markdownImageRenderMode?: MarkdownImageRenderMode;
2895
2947
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
2896
2948
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
2897
2949
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -2940,6 +2992,9 @@ export declare const IncomingMessageLayout: {
2940
2992
  url: string;
2941
2993
  type: string;
2942
2994
  }) => void;
2995
+ onClickLink?: (params: {
2996
+ url: string;
2997
+ }) => void;
2943
2998
  children?: ReactNode;
2944
2999
  })) => ReactNode;
2945
3000
  CTAButton: ({ extendedMessagePayload, onClickCTA, }: IncomingMessageProps) => ReactNode;
@@ -2996,6 +3051,7 @@ export declare const IncomingMessageLayout: {
2996
3051
  isFeedbackEnabled?: boolean;
2997
3052
  isFeedbackCommentEnabled?: boolean;
2998
3053
  isSenderAvatarVisible?: boolean;
3054
+ markdownImageRenderMode?: MarkdownImageRenderMode;
2999
3055
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3000
3056
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3001
3057
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3044,6 +3100,9 @@ export declare const IncomingMessageLayout: {
3044
3100
  url: string;
3045
3101
  type: string;
3046
3102
  }) => void;
3103
+ onClickLink?: (params: {
3104
+ url: string;
3105
+ }) => void;
3047
3106
  children?: ReactNode;
3048
3107
  }) | ({
3049
3108
  messageType: "file";
@@ -3069,6 +3128,7 @@ export declare const IncomingMessageLayout: {
3069
3128
  isFeedbackEnabled?: boolean;
3070
3129
  isFeedbackCommentEnabled?: boolean;
3071
3130
  isSenderAvatarVisible?: boolean;
3131
+ markdownImageRenderMode?: MarkdownImageRenderMode;
3072
3132
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3073
3133
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3074
3134
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3117,6 +3177,9 @@ export declare const IncomingMessageLayout: {
3117
3177
  url: string;
3118
3178
  type: string;
3119
3179
  }) => void;
3180
+ onClickLink?: (params: {
3181
+ url: string;
3182
+ }) => void;
3120
3183
  children?: ReactNode;
3121
3184
  }) | ({
3122
3185
  messageType: "multipleFiles";
@@ -3142,6 +3205,7 @@ export declare const IncomingMessageLayout: {
3142
3205
  isFeedbackEnabled?: boolean;
3143
3206
  isFeedbackCommentEnabled?: boolean;
3144
3207
  isSenderAvatarVisible?: boolean;
3208
+ markdownImageRenderMode?: MarkdownImageRenderMode;
3145
3209
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3146
3210
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3147
3211
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3190,6 +3254,9 @@ export declare const IncomingMessageLayout: {
3190
3254
  url: string;
3191
3255
  type: string;
3192
3256
  }) => void;
3257
+ onClickLink?: (params: {
3258
+ url: string;
3259
+ }) => void;
3193
3260
  children?: ReactNode;
3194
3261
  })) => ReactNode;
3195
3262
  CTAButton: ({ extendedMessagePayload, onClickCTA, }: IncomingMessageProps) => ReactNode;
@@ -3241,6 +3308,7 @@ export declare const IncomingMessageLayout: {
3241
3308
  isFeedbackEnabled?: boolean;
3242
3309
  isFeedbackCommentEnabled?: boolean;
3243
3310
  isSenderAvatarVisible?: boolean;
3311
+ markdownImageRenderMode?: MarkdownImageRenderMode;
3244
3312
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3245
3313
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3246
3314
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3289,6 +3357,9 @@ export declare const IncomingMessageLayout: {
3289
3357
  url: string;
3290
3358
  type: string;
3291
3359
  }) => void;
3360
+ onClickLink?: (params: {
3361
+ url: string;
3362
+ }) => void;
3292
3363
  children?: ReactNode;
3293
3364
  }) | ({
3294
3365
  messageType: "file";
@@ -3314,6 +3385,7 @@ export declare const IncomingMessageLayout: {
3314
3385
  isFeedbackEnabled?: boolean;
3315
3386
  isFeedbackCommentEnabled?: boolean;
3316
3387
  isSenderAvatarVisible?: boolean;
3388
+ markdownImageRenderMode?: MarkdownImageRenderMode;
3317
3389
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3318
3390
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3319
3391
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3362,6 +3434,9 @@ export declare const IncomingMessageLayout: {
3362
3434
  url: string;
3363
3435
  type: string;
3364
3436
  }) => void;
3437
+ onClickLink?: (params: {
3438
+ url: string;
3439
+ }) => void;
3365
3440
  children?: ReactNode;
3366
3441
  }) | ({
3367
3442
  messageType: "multipleFiles";
@@ -3387,6 +3462,7 @@ export declare const IncomingMessageLayout: {
3387
3462
  isFeedbackEnabled?: boolean;
3388
3463
  isFeedbackCommentEnabled?: boolean;
3389
3464
  isSenderAvatarVisible?: boolean;
3465
+ markdownImageRenderMode?: MarkdownImageRenderMode;
3390
3466
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3391
3467
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3392
3468
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3435,6 +3511,9 @@ export declare const IncomingMessageLayout: {
3435
3511
  url: string;
3436
3512
  type: string;
3437
3513
  }) => void;
3514
+ onClickLink?: (params: {
3515
+ url: string;
3516
+ }) => void;
3438
3517
  children?: ReactNode;
3439
3518
  })) => ReactNode;
3440
3519
  CTAButton: ({ extendedMessagePayload, onClickCTA, }: IncomingMessageProps) => ReactNode;
@@ -3509,6 +3588,7 @@ export declare const IncomingMessageLayout: {
3509
3588
  isFeedbackEnabled?: boolean;
3510
3589
  isFeedbackCommentEnabled?: boolean;
3511
3590
  isSenderAvatarVisible?: boolean;
3591
+ markdownImageRenderMode?: MarkdownImageRenderMode;
3512
3592
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3513
3593
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3514
3594
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3557,6 +3637,9 @@ export declare const IncomingMessageLayout: {
3557
3637
  url: string;
3558
3638
  type: string;
3559
3639
  }) => void;
3640
+ onClickLink?: (params: {
3641
+ url: string;
3642
+ }) => void;
3560
3643
  children?: ReactNode;
3561
3644
  }) | ({
3562
3645
  messageType: "file";
@@ -3582,6 +3665,7 @@ export declare const IncomingMessageLayout: {
3582
3665
  isFeedbackEnabled?: boolean;
3583
3666
  isFeedbackCommentEnabled?: boolean;
3584
3667
  isSenderAvatarVisible?: boolean;
3668
+ markdownImageRenderMode?: MarkdownImageRenderMode;
3585
3669
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3586
3670
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3587
3671
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3630,6 +3714,9 @@ export declare const IncomingMessageLayout: {
3630
3714
  url: string;
3631
3715
  type: string;
3632
3716
  }) => void;
3717
+ onClickLink?: (params: {
3718
+ url: string;
3719
+ }) => void;
3633
3720
  children?: ReactNode;
3634
3721
  }) | ({
3635
3722
  messageType: "multipleFiles";
@@ -3655,6 +3742,7 @@ export declare const IncomingMessageLayout: {
3655
3742
  isFeedbackEnabled?: boolean;
3656
3743
  isFeedbackCommentEnabled?: boolean;
3657
3744
  isSenderAvatarVisible?: boolean;
3745
+ markdownImageRenderMode?: MarkdownImageRenderMode;
3658
3746
  onGetCachedMessageTemplate?: (templateKey: string) => string | null;
3659
3747
  onRequestMessageTemplate?: (templateKey: string) => Promise<string>;
3660
3748
  onHandleTemplateInternalAction?: (action: Action) => void;
@@ -3703,6 +3791,9 @@ export declare const IncomingMessageLayout: {
3703
3791
  url: string;
3704
3792
  type: string;
3705
3793
  }) => void;
3794
+ onClickLink?: (params: {
3795
+ url: string;
3796
+ }) => void;
3706
3797
  children?: ReactNode;
3707
3798
  })) => ReactNode;
3708
3799
  }) => null;
@@ -3853,6 +3944,8 @@ declare interface ManualSessionInfoParams {
3853
3944
  sessionHandler: AIAgentSessionHandler;
3854
3945
  }
3855
3946
 
3947
+ declare type MarkdownImageRenderMode = 'default' | 'complete-only';
3948
+
3856
3949
  declare interface MemoryInfo {
3857
3950
  enabled: boolean;
3858
3951
  showIndicator: boolean;
@@ -3932,7 +4025,7 @@ declare type MessageType_2 = OutgoingMessageProps['messageType'];
3932
4025
  declare interface MessengerContextValue extends AIAgentContextValue {
3933
4026
  rootElement: HTMLElement;
3934
4027
  agentPreviewConfigs?: AgentPreviewConfigs;
3935
- handlers?: AgentClientHandlers;
4028
+ handlers: ResolvedHandlers;
3936
4029
  state: {
3937
4030
  opened: boolean;
3938
4031
  setOpened: (value: boolean) => void;
@@ -4454,6 +4547,12 @@ declare type ReleaseDisabledByValue =
4454
4547
  | 'reconnecting'
4455
4548
  | 'handoff_pending';
4456
4549
 
4550
+ declare interface ResolvedHandlers extends AgentClientHandlers {
4551
+ onClickLink: (params: {
4552
+ url: string;
4553
+ }) => void;
4554
+ }
4555
+
4457
4556
  declare type SBUFoundationProps<T = NonNullable<unknown>> = T & {
4458
4557
  className?: string;
4459
4558
  children?: ReactNode;