mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-11-03 14:17:19 +01:00
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
82 lines
4.0 KiB
Swift
82 lines
4.0 KiB
Swift
#if canImport(UIKit)
|
|
import UIKit
|
|
import RichTextEditorCore
|
|
|
|
/// A framework-agnostic description of the table row/column structural menu the editor wants shown.
|
|
/// The editor hands this to its host (via `RichTextEditorView.onRequestTableStructuralMenu`); the host
|
|
/// presents its own menu (a Telegram `ContextController`) however it sees fit. The editor owns WHAT the
|
|
/// menu contains (adapted to the table state); the host owns HOW it is presented (title strings, icons,
|
|
/// styling, coordinate conversion). References only UIKit + Core — never ContextUI/Display.
|
|
@available(iOS 13.0, *)
|
|
public final class TableStructuralMenuRequest {
|
|
/// The view whose coordinate space `sourceRect` is expressed in — the editor's canvas. Weak so the
|
|
/// host does not retain editor internals past presentation.
|
|
public weak var view: UIView?
|
|
/// The tapped handle's rect in `view` coordinates — the anchor the host presents the menu from.
|
|
public let sourceRect: CGRect
|
|
/// Add/Delete actions, already adapted to the table state (header row → no Add-Above/Delete;
|
|
/// all-columns range → no Delete Column). Ordered for display.
|
|
public let actions: [Action]
|
|
/// The alignment control for the selected cells (present for both row and column selections): the
|
|
/// data is carried now, the host renders it as a custom control (deferred).
|
|
public let alignment: Alignment?
|
|
/// The header/highlight toggle for the selected cells (present for both row and column selections).
|
|
public let header: Header?
|
|
|
|
public init(view: UIView?, sourceRect: CGRect, actions: [Action], alignment: Alignment?, header: Header?) {
|
|
self.view = view
|
|
self.sourceRect = sourceRect
|
|
self.actions = actions
|
|
self.alignment = alignment
|
|
self.header = header
|
|
}
|
|
|
|
/// One menu action. `kind` is a stable semantic identity from which the host derives the (localizable)
|
|
/// title, destructive styling, and icon — no presentation state is carried here. `perform` runs the
|
|
/// edit AND clears the structural selection.
|
|
public struct Action {
|
|
public let kind: Kind
|
|
public let perform: () -> Void
|
|
public init(kind: Kind, perform: @escaping () -> Void) {
|
|
self.kind = kind
|
|
self.perform = perform
|
|
}
|
|
}
|
|
|
|
public enum Kind: Equatable {
|
|
case addColumnLeft, addColumnRight, deleteColumn
|
|
case addRowAbove, addRowBelow, deleteRow
|
|
/// Merge the `.cells` selection's covered cells into one spanning cell (offered when the
|
|
/// selection covers ≥2 anchors); split a single merged cell back into a dense grid (offered
|
|
/// when the selection resolves to exactly one already-merged anchor). Phase 2c.
|
|
case mergeCells, splitCell
|
|
}
|
|
|
|
/// The alignment control for the selected cells: the uniform current value per axis (nil = the selected
|
|
/// cells disagree, "mixed"), and `apply` to set one or both axes on all selected cells (a nil argument
|
|
/// leaves that axis unchanged). Present for both row and column selections.
|
|
public struct Alignment {
|
|
public let horizontal: TextAlignment?
|
|
public let vertical: VerticalAlignment?
|
|
public let apply: (TextAlignment?, VerticalAlignment?) -> Void
|
|
public init(horizontal: TextAlignment?, vertical: VerticalAlignment?, apply: @escaping (TextAlignment?, VerticalAlignment?) -> Void) {
|
|
self.horizontal = horizontal
|
|
self.vertical = vertical
|
|
self.apply = apply
|
|
}
|
|
}
|
|
|
|
/// The header/highlight toggle for the selected cells: the uniform current value (nil = the cells
|
|
/// disagree, "mixed"/indeterminate), and `apply` to toggle every selected cell. Present for both
|
|
/// row and column selections.
|
|
public struct Header {
|
|
public let isHeader: Bool?
|
|
public let apply: () -> Void
|
|
public init(isHeader: Bool?, apply: @escaping () -> Void) {
|
|
self.isHeader = isHeader
|
|
self.apply = apply
|
|
}
|
|
}
|
|
}
|
|
#endif
|