ExpandedSurfaceProviding
A provider of expanded surfaces: content, size, and the far end of the host's lifecycle.
@MainActor protocol ExpandedSurfaceProviding : AnyObject
Deliberately AnyObject rather than Droplet, the same split QuickActionBarProviding makes and for the same reason: the object that knows whether a session is running is usually a long-lived manager the droplet owns, not the droplet itself. Vend one by adopting ExpandedSurfaceHosting.
The split matters more here than it does for the action bar. The host resolves this provider through the droplet registry, so there is exactly one instance and both sides agree on which. The shipping code this replaces used a shared singleton reachable from anywhere in the app, which is why eight unrelated host sites ended up reading it directly and why none of that could survive the move out of the host process boundary.
- Note: Maturity: Provisional. The shapes here are derived from a shipping host takeover, but no host mounts this protocol yet, so it is published for design feedback ahead of that wiring and may change in a minor release. Requires the
expanded-surfacecapability.
Properties
expandedSurfaces
@MainActor var expandedSurfaces: [ExpandedSurfaceDescriptor] { get }
The surfaces this droplet can present. Read at activation and again after every host state-change broadcast; keep it stable and cheap.
Methods
expandedSurfaceDidDismiss(_:presentation:reason:)
@MainActor func expandedSurfaceDidDismiss(_ id: ExpandedSurfaceID, presentation: ExpandedSurfacePresentation, reason: ExpandedSurfaceDismissalReason)
The host has taken the surface down.
Called once per presentation, after the close, for every reason including your own dismissExpandedSurface(_:). Compare presentation against the one you started, because a delayed teardown can arrive after the user has already summoned the surface again.
expandedSurfaceDidDismiss(_:presentation:reason:)
@MainActor func expandedSurfaceDidDismiss(_ id: ExpandedSurfaceID, presentation: ExpandedSurfacePresentation, reason: ExpandedSurfaceDismissalReason)
Default: nothing to tear down.
expandedSurfaceSize(_:fitting:)
@MainActor func expandedSurfaceSize(_ id: ExpandedSurfaceID, fitting proposal: ExpandedSurfaceSizeProposal) -> CGSize?
How big the surface wants to be, or nil for the host's standard size.
Called on layout passes rather than once per presentation, because a surface whose content grows (a transcript arriving a word at a time, a list gaining rows) has to be able to change its answer. Keep it pure and cheap: no side effects, no allocation you can avoid, and no animation of your own. The host clamps to maximumSize and holds your answer still across its springs.
expandedSurfaceSize(_:fitting:)
@MainActor func expandedSurfaceSize(_ id: ExpandedSurfaceID, fitting proposal: ExpandedSurfaceSizeProposal) -> CGSize?
Default: no preference, so the host uses its standard expanded size.
makeExpandedSurfaceView(_:context:)
@MainActor func makeExpandedSurfaceView(_ id: ExpandedSurfaceID, context: ExpandedSurfaceContext) -> AnyView
Builds the surface's live view. Views render on dark shelf surfaces; use light foreground colors and the DroppyKit design tokens.
Return an empty view for an id you do not recognize rather than trapping. A host can ask about a surface you published a moment ago and have since stopped offering.