Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions ui-kit/ios/compact-message-composer.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<Tabs>
<Tab title="Swift">
```swift
let compactComposer = CometChatCompactMessageComposer()

Check warning on line 21 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L21

Did you really mean 'compactComposer'?
compactComposer.set(user: user)
compactComposer.set(controller: self)
compactComposer.translatesAutoresizingMaskIntoConstraints = false
Expand Down Expand Up @@ -143,13 +143,13 @@
<Tabs>
<Tab title="Swift">
```swift
var customStyle = CompactMessageComposerStyle()

Check warning on line 146 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L146

Did you really mean 'customStyle'?
customStyle.activeSendButtonBackgroundColor = UIColor(hex: "#F76808")

Check warning on line 147 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L147

Did you really mean 'customStyle'?
customStyle.attachmentImageTint = UIColor(hex: "#F76808")
customStyle.voiceRecordingImageTint = UIColor(hex: "#F76808")
customStyle.stickersImageTint = UIColor(hex: "#F76808")

let compactComposer = CometChatCompactMessageComposer()

Check warning on line 152 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L152

Did you really mean 'compactComposer'?
compactComposer.style = customStyle
```
</Tab>
Expand Down Expand Up @@ -340,10 +340,10 @@

| Property | Description | Code |
| -------- | ----------- | ---- |
| backgroundColor | Background color of the toolbar. | `toolbarStyle.backgroundColor = CometChatTheme.backgroundColor02` |

Check warning on line 343 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L343

Did you really mean 'backgroundColor'?
| borderColor | Border color of the toolbar. | `toolbarStyle.borderColor = CometChatTheme.borderColorLight` |

Check warning on line 344 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L344

Did you really mean 'borderColor'?
| buttonSize | Size of format buttons. | `toolbarStyle.buttonSize = 30` |

Check warning on line 345 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L345

Did you really mean 'buttonSize'?
| buttonSpacing | Spacing between format buttons. | `toolbarStyle.buttonSpacing = CometChatSpacing.Spacing.s2` |

Check warning on line 346 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L346

Did you really mean 'buttonSpacing'?
| iconTintColor | Tint color for inactive format icons. | `toolbarStyle.iconTintColor = CometChatTheme.iconColorSecondary` |
| activeIconTintColor | Tint color for active format icons. | `toolbarStyle.activeIconTintColor = CometChatTheme.primaryColor` |
| buttonBackgroundColor | Background color for inactive buttons. | `toolbarStyle.buttonBackgroundColor = .clear` |
Expand All @@ -351,13 +351,147 @@

---

### Trailing toolbar actions

`set(richTextToolbarActions:)` appends your own buttons at the trailing end of the built-in toolbar — after the format buttons, separated by a divider — without replacing the toolbar. It takes the same closure shape as `set(attachmentOptions:)`, receiving the current `User?` and `Group?`, and returns a list of `CometChatRichTextToolbarAction` items.

| Property | Type | Description |
| -------- | ---- | ----------- |
| `id` | `String` | Identifies the action, and looks the rendered button up in `CometChatRichTextToolbar.trailingActionButtons`. |
| `icon` | `UIImage?` | The button glyph. Rendered as-is — apply `.withRenderingMode(.alwaysTemplate)` for `tint` or the toolbar's `iconTintColor` to take effect. |
| `onClick` | `(CometChatComposerInput) -> Void` | Called on tap with a live handle onto the composer's input. |
| `tint` | `UIColor?` | Overrides `RichTextToolbarStyle.iconTintColor` when non-nil. |
| `accessibilityLabel` | `String?` | VoiceOver label. Falls back to `id`, so a button is never unlabelled. |

Each action's `onClick` receives a **`CometChatComposerInput`** — a live handle for reading and mutating the draft, so the composer stays the owner of the field:

| Member | Description |
| ------ | ----------- |
| `text: String` | The input's contents without attributes. |
| `attributedText: NSAttributedString` | The contents, including formatting attributes. |
| `selectedRange: NSRange` | The current selection, or a zero-length range at the caret. |
| `hasSelection: Bool` | Whether text is selected, as opposed to a caret being placed. |
| `typingAttributes: [NSAttributedString.Key: Any]` | Attributes the next typed character inherits — set this to format text typed next rather than a selection. |
| `mentionRanges: [NSRange]` | The ranges currently occupied by mentions. |
| `attributes(at:)` | The attributes at a location, or empty if out of bounds. |
| `insertAtCaret(_:)` | Insert at the caret, replacing any selection; the caret lands after the inserted text. |
| `setAttributedText(_:preservingSelection:)` | Replace the contents, keeping the selection by default. |
| `setSelectedRange(_:)` | Move the caret or change the selection, clamped to the current length. |
| `applyAttributes(_:to:protectingKitRuns:)` / `removeAttributes(_:from:protectingKitRuns:)` | Add or strip attributes over a range. |
| `applyAttributesToSelection(_:protectingKitRuns:)` / `removeAttributesFromSelection(_:protectingKitRuns:)` | The same over the current selection; each returns whether there was a selection to act on. |
| `commit()` | Resync the toolbar and send button partway through a long edit. |

Check warning on line 382 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L382

Did you really mean 'Resync'?

<Tabs>
<Tab title="Swift">
```swift
compactComposer.set(richTextToolbarActions: { user, group in
[
CometChatRichTextToolbarAction(
id: "insert_greeting",
icon: UIImage(systemName: "hand.wave")?.withRenderingMode(.alwaysTemplate),
accessibilityLabel: "Greeting"

Check warning on line 392 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L392

Did you really mean 'accessibilityLabel'?
) { input in
input.insertAtCaret(NSAttributedString(string: "Hello! "))
}
]
})
```
</Tab>
</Tabs>

Actions are registered per composer instance, so a thread composer can offer a different set from the main one.

<Note>

The trailing section lives **inside** the rich-text toolbar — it is not rendered when the toolbar is hidden (`showRichTextFormattingOptions = false`) or rich text is disabled (`enableRichTextFormatting = false`).

The `CometChatComposerInput` is valid only for the duration of the `onClick` call; don't retain it. The action itself is retained by the toolbar, so capture `self` weakly.

The composer serializes to markdown on send. The built-in formats survive, and so does text colour — see [Colour that survives send](#colour-that-survives-send). Any other attribute you apply is composer-local: markdown has no representation for it, so it is dropped from the sent message. Use those for affordances that are meant to be transient, such as marking a range while the action's own picker or sheet is open.

Check warning on line 410 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L410

Did you really mean 'affordances'?

</Note>

Mutations apply immediately, but composer state that derives from the text — the toolbar's active formats and the send button — resyncs once when `onClick` returns rather than per mutation, so a multi-step edit resyncs once. Call `commit()` to resync earlier.

Check warning on line 414 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L414

Did you really mean 'resyncs'?

Check warning on line 414 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L414

Did you really mean 'resyncs'?

Check warning on line 414 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L414

Did you really mean 'resync'?

#### Leaving Kit-owned runs alone

An action that restyles a range will happily run over a mention or a link, which the Kit repaints on its own schedule — so your attribute is reverted on the next repaint anyway, and removing one of the Kit's attributes deletes it rather than restoring the Kit's value.

The mutating methods therefore take `protectingKitRuns`, which defaults to `true`. With it on, the following are carved out of the target range and left untouched:

- mentions
- links, including a URL still being typed
- inline code and code blocks, and any monospaced run

Check warning on line 424 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L424

Did you really mean 'monospaced'?
- fully transparent runs, so an action cannot repaint hidden text into view

Pass `protectingKitRuns: false` to opt out and write over the whole range. To make a narrower decision yourself, read `mentionRanges` — the ranges are read at call time, so re-read them after a mutation rather than caching, as they shift with the text. Note that `mentionRanges` covers mentions only; the other carve-outs above have no public accessor.

Check warning on line 427 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L427

Did you really mean 'accessor'?

<Tabs>
<Tab title="Swift">
```swift
CometChatRichTextToolbarAction(
id: "red_text",

Check warning on line 433 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L433

Did you really mean 'red_text'?
icon: UIImage(systemName: "paintpalette")?.withRenderingMode(.alwaysTemplate),
accessibilityLabel: "Red text"
) { input in
// Colouring applies to a selection; with only a caret there is nothing
// to restyle, so leave the text alone rather than guessing at a range.
guard input.hasSelection else { return }

// Kit-owned runs are protected by default and keep their own styling.
input.applyAttributesToSelection([
.foregroundColor: UIColor.systemRed,
RichTextFormatterManager.textColorKey: UIColor.systemRed
])
}
```
</Tab>
</Tabs>

#### Colour that survives send

Text colour is the one value-carrying style with a wire representation: the composer serializes it as `<color=#rrggbb>…</color>`, and the message bubble parses it back. Colour therefore reaches the recipient, unlike other attributes you might apply.

Setting `.foregroundColor` on its own is not enough. That key is written by six different things — mentions, links, inline code, code blocks, ordinary text and the user — so it records nothing about *who* set it. `RichTextFormatterManager.textColorKey` is the marker that identifies a run the user deliberately coloured, and it is what the serializer looks for. Always write and remove the two together.

<Tabs>
<Tab title="Swift">
```swift
// Applies colour, and marks the run so it survives send.
input.applyAttributesToSelection([
.foregroundColor: UIColor.systemRed,
RichTextFormatterManager.textColorKey: UIColor.systemRed
])

// Clearing colour removes both keys; the text falls back to the
// composer's own colour rather than to a value hard-coded here.
input.removeAttributesFromSelection([
.foregroundColor,
RichTextFormatterManager.textColorKey
])
```
</Tab>
</Tabs>

<Note>

Use opaque colours. Only `#rgb` and `#rrggbb` are valid on the wire — eight-digit `#rrggbbaa` is rejected deliberately, since a fully transparent run would be an invisible message.

A translucent `UIColor` is **not** rejected locally: it renders in the composer, then is dropped on send, because a colour with alpha below 1 has no wire representation. That is the silent loss this section exists to prevent, so pass a fully opaque colour.

</Note>

The UI Kit ships no colour button of its own: the wire format and the serializer are provided, the button is yours. That is what the trailing-actions slot is for.

Check warning on line 484 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L484

Did you really mean 'serializer'?

---

## Advanced

For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component.

### setTextFormatters

Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel check out [CometChatMentionsFormatter](/ui-kit/ios/mentions-formatter-guide)

Check warning on line 494 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L494

Did you really mean 'formatters'?

Check warning on line 494 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L494

Did you really mean 'formatters'?

**Example**

Expand All @@ -373,7 +507,7 @@

let customMentionFormatter = CometChatMentionsFormatter()
.set(composerTextStyle: composerTextStyle)

Check warning on line 510 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L510

Did you really mean 'compactComposer'?
let compactComposer = CometChatCompactMessageComposer()
compactComposer.set(textFormatter: [customMentionFormatter])
```
Expand Down Expand Up @@ -402,7 +536,7 @@

<Tabs>
<Tab title="Swift">
```swift

Check warning on line 539 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L539

Did you really mean 'compactComposer'?
let compactComposer = CometChatCompactMessageComposer()

compactComposer.set(attachmentOptions: { user, group, controller in
Expand Down Expand Up @@ -455,7 +589,7 @@
<Tabs>
<Tab title="Swift">
```swift
compactComposer.reply(message: baseMessage)

Check warning on line 592 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L592

Did you really mean 'baseMessage'?
```
</Tab>
</Tabs>
Expand All @@ -465,9 +599,9 @@
<Tabs>
<Tab title="Swift">
```swift
compactComposer.preview(message: baseMessage, mode: .edit)

Check warning on line 602 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L602

Did you really mean 'baseMessage'?
// or
compactComposer.preview(message: baseMessage, mode: .reply)

Check warning on line 604 in ui-kit/ios/compact-message-composer.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/compact-message-composer.mdx#L604

Did you really mean 'baseMessage'?
```
</Tab>
</Tabs>
Expand Down