### Setup and verification commands Source: https://getdroppy.app/docs/droppykit/add-spm Commands to clone the SDK, set PATH, and verify the droppykit tool; a Swift Package.swift example; and shell commands to check the link. ```bash git clone https://gitlab.com/droppyformac1/droppykit.git export PATH="$PWD/droppykit/Scripts:$PATH" droppykit ``` ```bash droppykit version # which SDK this is, which one the PATH finds, what a droplet pins droppykit update # pull the newest SDK; inside a droplet, move its pin too ``` ```swift // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "WorldClock", platforms: [.macOS(.v14)], products: [ .library(name: "WorldClock", type: .dynamic) ], dependencies: [ .package(url: "https://gitlab.com/droppyformac1/droppykit.git", from: "15.3.0") ], targets: [ .target( name: "WorldClock", dependencies: ["DroppyKit"] ) ] ) ``` ```bash # 0 in a correct bundle, non-zero in a broken one. nm -u WorldClock.droplet/Contents/MacOS/WorldClock | grep -c '9DroppyKit.*vau' # Must name the framework, and must not name libDroppyKit. otool -L WorldClock.droplet/Contents/MacOS/WorldClock | grep DroppyKit ``` -------------------------------- ### Settings Pane Examples Source: https://getdroppy.app/docs/droppykit-handbook Swift code examples for building a settings pane in a Droppy droplet. ```swift extension WorldClockDroplet: SettingsPaneProviding { public func makeSettingsPane(context: SettingsPaneContext) -> AnyView { AnyView(WorldClockSettings(droplet: self)) } public var settingsSearchEntries: [SettingsSearchEntry] { [SettingsSearchEntry(title: "Show seconds", keywords: ["time", "clock"])] } } ``` ```swift VStack(alignment: .leading, spacing: DroppySpacing.lg) { DropletSettingsCard { DropletToggleRow( title: "Show seconds", subtitle: "Ticks the shelf widget every second instead of every minute.", isOn: droplet.showsSecondsBinding ) DropletSettingsDivider() DropletSliderRow( title: "Refresh", value: "\(Int(interval))s", binding: $interval, range: 1...60 ) DropletSettingsDivider() DropletControlRow(title: "Clocks") { DropletValuePill(text: "\(droplet.clockCount)") } } } ``` ```swift var showsSecondsBinding: Binding { Binding( get: { self.host?.preferences.value(forKey: "showsSeconds", default: true) ?? true }, set: { self.host?.preferences.setValue($0, forKey: "showsSeconds") } ) } ``` -------------------------------- ### Icon and Avatar Configuration Examples Source: https://getdroppy.app/docs/droppykit/icons Two code examples: the structure of a .icon directory and a JSON snippet for the creator avatar configuration. ```text WorldClock.icon/ icon.json the document: groups, layers, fills, specializations Assets/ dial.png every image icon.json names by `image-name` ``` ```json "creator": { "name": "Jane Doe", "kind": "community", "url": "https://jane.example", "avatar": "Creator.png" } ``` -------------------------------- ### Expanded Surface Code Examples Source: https://getdroppy.app/docs/droppykit/expanded-surfaces Code examples demonstrating how to declare an expanded surface, provide its size, and present it. ```swift extension WorldClockDroplet: ExpandedSurfaceProviding { public var expandedSurfaces: [ExpandedSurfaceDescriptor] { [ ExpandedSurfaceDescriptor( id: "clocks-detail", title: "World Clock", systemImage: "globe", suppresses: [.shelfWidgets, .autoCollapse] ) ] } } ``` ```swift public func expandedSurfaceSize( _ id: ExpandedSurfaceID, fitting proposal: ExpandedSurfaceSizeProposal ) -> CGSize? { CGSize(width: proposal.standardSize.width, height: CGFloat(clocks.count) * 44 + 64) } ``` ```swift let presentation = host.notchSurface.presentExpandedSurface( ExpandedSurfacePresentationRequest(surfaceID: "clocks-detail", opensShelf: true) ) ``` -------------------------------- ### DroppyKit Harness Code Examples Source: https://getdroppy.app/docs/droppykit-handbook Code examples from the DroppyKit handbook: a Swift harness entry point, shell commands for running the harness, and shell commands for generating screenshots. ```swift import DroppyKit import DroppyKitHarness @main struct WorldClockHarness: DropletHarnessApp { static func makeDroplet() -> any Droplet { WorldClockDroplet() } } ``` ```bash droppykit run # or Scripts/run-harness.sh WorldClockHarness droppykit run --page shelf-widget # open straight onto one surface ``` ```bash droppykit run -- --shots ./shots droppykit run -- --shots ./shots --shot-height 1900 ``` -------------------------------- ### Droppy Live Activity Code Examples Source: https://getdroppy.app/docs/droppykit-handbook Code examples from the Droppy Live Activity documentation, including publishing state, compact presentation, yielding, and interactive rows. ```swift extension WorldClockDroplet: LiveActivityProviding { public var liveActivityState: AnyPublisher { activitySubject.eraseToAnyPublisher() } private func publishActivity() { activitySubject.send( LiveActivityState( priority: 200, accessibilityTitle: "Amsterdam \(time)", isInteractive: false ) ) } } ``` ```swift public func makeCompactLeading() -> AnyView { AnyView( Image(systemName: "globe") .font(.system(size: DroppyLiveActivityMetrics.iconSize, weight: .medium)) .foregroundStyle(AdaptiveColors.notchSurfacePrimaryText) .padding(.trailing, DroppySpacing.sm) ) } public func makeCompactTrailing() -> AnyView { AnyView( Image(systemName: "globe") .font(.system(size: DroppyLiveActivityMetrics.iconSize, weight: .medium)) .foregroundStyle(AdaptiveColors.notchSurfacePrimaryText) .padding(.trailing, DroppySpacing.sm) ) } ``` ```swift host.liveActivity.yield(reason: .idle) ``` ```swift Button { skip() } label: { Image(systemName: "forward.fill") } .buttonStyle(DroppyLiveActivityControlStyle(prominence: .accent)) ``` -------------------------------- ### DroppyKit Widget Examples Source: https://getdroppy.app/docs/droppykit-handbook Code examples from the DroppyKit handbook demonstrating widget declaration, view body branching, and layout invalidation. ```swift extension WorldClockDroplet: ShelfWidgetProviding { public var widgetDescriptors: [ShelfWidgetDescriptor] { [ ShelfWidgetDescriptor( id: "clocks", title: "World Clock", systemImage: "globe", layoutTraits: ShelfWidgetLayoutTraits( preferredSoloWidth: 420, preferredPairedWidth: 210, contentHeight: .fixed(150) ), searchKeywords: ["time", "timezone"] ) ] } } ``` ```swift var body: some View { VStack(alignment: .leading, spacing: DroppySpacing.sm) { header if context.isCompact { compactBody } else { fullBody } } } ``` ```swift host.shelf.invalidateLayout(for: "clocks") ``` -------------------------------- ### Creator metadata example Source: https://getdroppy.app/docs/droppykit-handbook Example of the creator metadata object in the icon document, specifying the creator's name, kind, URL, and avatar image file. ```json "creator": { "name": "Jane Doe", "kind": "community", "url": "https://jane.example", "avatar": "Creator.png" } ``` -------------------------------- ### Package.swift for a DroppyKit droplet Source: https://getdroppy.app/docs/droppykit-handbook Example Package.swift for a droplet. The product must be a dynamic library; the harness target is for development and is not shipped. ```swift // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "WorldClock", platforms: [.macOS(.v14)], products: [ .library(name: "WorldClock", type: .dynamic, targets: ["WorldClock"]) ], dependencies: [ .package(url: "https://gitlab.com/droppyformac1/droppykit.git", from: "1.2.0") ], targets: [ .target( name: "WorldClock", dependencies: [.product(name: "DroppyKit", package: "droppykit")] ), .executableTarget( name: "WorldClockHarness", dependencies: [ "WorldClock", .product(name: "DroppyKitHarness", package: "droppykit") ] ) ] ) ``` -------------------------------- ### Droplet installation path Source: https://getdroppy.app/docs/droppykit/playground Shows the file path where a droplet bundle is copied after installation in the Playground. The path includes the droplet ID and the original bundle name. ```text ~/Library/Application Support/Droppy Playground/Droplets//.droplet ``` -------------------------------- ### WorldClockDroplet implementation Source: https://getdroppy.app/docs/droppykit/api/droplet-host Example of a droplet class that stores the host and uses its services. ```swift final class WorldClockDroplet: Droplet, ShelfWidgetProviding { static let id: DropletID = "worldclock" private var host: DropletHost? func activate(host: DropletHost) throws { self.host = host let zone = host.preferences.value(forKey: "zone", default: "UTC") host.log.info("activated for \(zone)") } func deactivate() { host = nil } } ``` -------------------------------- ### DroppyKit CLI Commands and Installation Path Source: https://getdroppy.app/docs/droppykit-handbook Commands and paths used in the DroppyKit workflow: validation, submission, and installation location. ```bash droppykit validate ``` ```bash droppykit submit ``` ```bash ~/Library/Application Support/Droppy/Droplets//.droplet ``` -------------------------------- ### Handle HUD presentation refusal Source: https://getdroppy.app/docs/droppykit/host-support Example of handling a refusal when presenting a HUD surface, showing that a failed presentation is not an error and should not be retried. ```unknown if !host.hud.present(request) { // Not an error. The surface was taken, or this Droppy does not // mount it. Either way the moment has passed; do not retry. host.log.debug("HUD not shown") } ``` -------------------------------- ### Settings pane UI components Source: https://getdroppy.app/docs/droppykit/settings-panes Build the settings pane UI using SDK components like DropletSettingsCard, DropletToggleRow, DropletSliderRow, and DropletControlRow. The example shows a VStack with a card containing a toggle, slider, and a control row with a value pill. ```swift VStack(alignment: .leading, spacing: DroppySpacing.lg) { DropletSettingsCard { DropletToggleRow( title: "Show seconds", subtitle: "Ticks the shelf widget every second instead of every minute.", isOn: droplet.showsSecondsBinding ) DropletSettingsDivider() DropletSliderRow( title: "Refresh", value: "\(Int(interval))s", binding: $interval, range: 1...60 ) DropletSettingsDivider() DropletControlRow(title: "Clocks") { DropletValuePill(text: "\(droplet.clockCount)") } } } ``` -------------------------------- ### AdaptiveColors foreground style Source: https://getdroppy.app/docs/droppykit-handbook Example of using AdaptiveColors for foreground text on dark surfaces. ```swift Text(title).foregroundStyle(AdaptiveColors.notchSurfacePrimaryText) Text(detail).foregroundStyle(AdaptiveColors.notchSurfacePrimaryText) ``` -------------------------------- ### init(priority:accessibilityTitle:isInteractive:joinsPersistentActivitySet:compactPresentation:) Source: https://getdroppy.app/docs/droppykit/api/live-activity-state Creates an activity state, optionally describing a product-owned leading compact accessory that the host may hoist safely. This is the 0.6.2 ABI entry point. ```APIDOC ## init(priority:accessibilityTitle:isInteractive:joinsPersistentActivitySet:compactPresentation:) ### Description Creates an activity state, optionally describing a product-owned leading compact accessory that the host may hoist safely. This is the 0.6.2 ABI entry point. ### Method Initializer ### Signature `init(priority: Int, accessibilityTitle: String, isInteractive: Bool = false, joinsPersistentActivitySet: Bool = false, compactPresentation: CompactLiveActivityPresentationMetadata?)` ### Parameters - **priority** (Int) - Required - Priority when several droplets want the compact slot at once. Higher wins; the host resolves ties in registration order. - **accessibilityTitle** (String) - Required - Accessibility title for the activity pill. - **isInteractive** (Bool) - Optional - True when the expanded activity accepts pointer interaction. Defaults to `false`. - **joinsPersistentActivitySet** (Bool) - Optional - True when the activity joins the host's persistent live-activity set. Defaults to `false`. - **compactPresentation** (CompactLiveActivityPresentationMetadata?) - Optional - Product-neutral metadata for a host that mounts a shadowing droplet's leading compact accessory outside the clipping surface. `nil` means the activity uses the ordinary compact mount only. ``` -------------------------------- ### init() Source: https://getdroppy.app/docs/droppykit/api/droppy-markdown-editor-commands Creates an unbound command bus. ```APIDOC ## init() ### Description Creates an unbound command bus. ### Method init ### Signature `@MainActor init()` ### Parameters None. ### Return Value A new instance of DroppyMarkdownEditorCommands. ### Example ```swift let commands = DroppyMarkdownEditorCommands() ``` ``` -------------------------------- ### init(preferredSoloWidth:preferredPairedWidth:pairWeight:minimumWidth:contentHeight:) Source: https://getdroppy.app/docs/droppykit/api/shelf-widget-layout-traits Initializer for creating layout traits for a shelf widget. ```APIDOC ## init(preferredSoloWidth:preferredPairedWidth:pairWeight:minimumWidth:contentHeight:) ### Description Creates layout traits for a shelf widget. The optional width defaults preserve existing source and binary call sites, but they do not create a host-layout fallback. A current Droppy host refuses a widget descriptor unless both `preferredSoloWidth` and `preferredPairedWidth` are explicit. ### Method Initializer ### Signature `init(preferredSoloWidth: CGFloat? = nil, preferredPairedWidth: CGFloat? = nil, pairWeight: Double = 1, minimumWidth: CGFloat? = nil, contentHeight: ShelfWidgetContentHeight = .standard)` ### Parameters - **preferredSoloWidth** (CGFloat?) - Optional - Preferred width in points when the widget is shown alone. Must be explicit for current Droppy hosts. - **preferredPairedWidth** (CGFloat?) - Optional - Preferred width in points when the widget shares a row with one to three other widgets. Must be explicit for current Droppy hosts. - **pairWeight** (Double) - Optional - Relative weight when the shelf splits space across a grouped row. Default is 1 (even share). - **minimumWidth** (CGFloat?) - Optional - Hard minimum width in points. `nil` uses the shelf's floor. - **contentHeight** (ShelfWidgetContentHeight) - Optional - Content height request. Default is `.standard`. ### Return Value A `ShelfWidgetLayoutTraits` instance. ``` -------------------------------- ### init(surface:seat:slotSize:) Source: https://getdroppy.app/docs/droppykit/api/compact-live-activity-context Creates a compact context with the given surface kind, seat type, and slot size. This initializer is constructed by hosts and read by droplets. ```APIDOC ## init(surface:seat:slotSize:) ### Description Creates a compact context. Constructed by hosts, read by droplets. ### Signature `init(surface: DropletSurfaceKind, seat: DropletLiveActivitySeat, slotSize: CGSize)` ### Parameters - **surface** (DropletSurfaceKind) - The surface family hosting the accessory. - **seat** (DropletLiveActivitySeat) - The seat the accessory is being rendered for. - **slotSize** (CGSize) - The resolved content slot, in points. ### Notes - The seat `.compact` is the island/notch owner seat; `.secondary` is the detached companion pill. - For the companion pill, slotSize is the round content area inside the puck; for owner wings, it is the wing rect the accessory may fill. ``` -------------------------------- ### Run the droplet Source: https://getdroppy.app/docs/droppykit/first-droplet Run the droplet in the harness to preview it. ```shell droppykit run ``` -------------------------------- ### Build, validate, and submit Source: https://getdroppy.app/docs/droppykit/first-droplet Build, validate, and submit the droplet using the CLI. ```shell droppykit build # produces WorldClock.droplet droppykit validate # the same checks the submission runs droppykit submit # open the submission form, filled in from this checkout ``` -------------------------------- ### init(rawValue:) Source: https://getdroppy.app/docs/droppykit/api/grouped-corners Creates an option set from raw bits. ```APIDOC ## init(rawValue:) ### Description Creates an option set from raw bits. ### Signature `init(rawValue: UInt8)` ### Parameters - **rawValue** (UInt8) - The raw bits to initialize the option set. ``` -------------------------------- ### init(availableSize:surface:displayID:isHostShelfTransitioning:isPreview:presentation:) Source: https://getdroppy.app/docs/droppykit/api/expanded-surface-context Creates an ExpandedSurfaceContext instance. This initializer is constructed by hosts and read by droplets, providing contextual information about the surface mount. ```APIDOC ## init(availableSize:surface:displayID:isHostShelfTransitioning:isPreview:presentation:) ### Description Creates a context. Constructed by hosts, read by droplets. ### Method Initializer ### Signature `init(availableSize: CGSize, surface: DropletSurfaceKind = .builtInNotch, displayID: UInt32, isHostShelfTransitioning: Bool = false, isPreview: Bool = false, presentation: ExpandedSurfacePresentation)` ### Parameters - **availableSize** (CGSize) - Required - The size the host is laying the surface out at. - **surface** (DropletSurfaceKind) - Optional - Defaults to `.builtInNotch`. The surface kind hosting it. - **displayID** (UInt32) - Required - The display hosting it. - **isHostShelfTransitioning** (Bool) - Optional - Defaults to `false`. True while the shelf's open or close spring is in flight. - **isPreview** (Bool) - Optional - Defaults to `false`. True when the view is mounted in a non-interactive preview. - **presentation** (ExpandedSurfacePresentation) - Required. The presentation this mount belongs to. ### Example ```swift let context = ExpandedSurfaceContext( availableSize: CGSize(width: 320, height: 200), surface: .builtInNotch, displayID: 1, isHostShelfTransitioning: false, isPreview: false, presentation: someExpandedSurfacePresentation ) ``` ``` -------------------------------- ### static func isValid(_:) Source: https://getdroppy.app/docs/droppykit/api/droplet-id Whether `rawValue` is a usable droplet id. The rule: 3 to 40 characters, ASCII letters, digits and hyphens only, starting with a letter and ending with a letter or digit. ```APIDOC ## static func isValid(_:) ### Description Whether `rawValue` is a usable droplet id. The rule: 3 to 40 characters, ASCII letters, digits and hyphens only, starting with a letter and ending with a letter or digit. ### Signature `static func isValid(_ rawValue: String) -> Bool` ### Parameters - **rawValue** (String) - The string to validate. ### Returns `true` if the string is a valid droplet id, otherwise `false`. ### Validation Rules - Length: 3 to 40 characters inclusive. - Characters: ASCII letters, digits, and hyphens only. - Must start with a letter and end with a letter or digit. - Rejects `/`, `\`, `.`, spaces, leading/trailing hyphens, and empty string. ``` -------------------------------- ### init(stringLiteral:) Source: https://getdroppy.app/docs/droppykit/api/droplet-id String-literal convenience initializer, so `static let id: DropletID = "worldclock"` reads naturally. ```APIDOC ## init(stringLiteral:) ### Description String-literal convenience initializer, so `static let id: DropletID = "worldclock"` reads naturally. ### Signature `init(stringLiteral value: String)` ### Parameters - **value** (String) - The string literal value. ``` -------------------------------- ### init(closedWidth:closedHeight:cornerRadius:isHardwareNotch:displayID:) Source: https://getdroppy.app/docs/droppykit/api/droplet-notch-geometry Initializes a DropletNotchGeometry instance with the specified closed width, closed height, corner radius, hardware notch flag, and display ID. ```APIDOC ## init(closedWidth:closedHeight:cornerRadius:isHardwareNotch:displayID:) ### Description Initializes a DropletNotchGeometry instance with the specified closed width, closed height, corner radius, hardware notch flag, and display ID. ### Method Initializer ### Parameters - **closedWidth** (CGFloat) - Required - Width of the closed notch, in points. - **closedHeight** (CGFloat) - Required - Height of the closed notch, in points. - **cornerRadius** (CGFloat) - Required - Corner radius the host rounds its surfaces to. - **isHardwareNotch** (Bool) - Required - Whether this display has a real hardware notch. `false` means the host is drawing a simulated island near the top edge. - **displayID** (UInt32) - Required - The display this geometry describes. ### Response No return value. ``` -------------------------------- ### ShelfWidgetContext Initializers Source: https://getdroppy.app/docs/droppykit/api/shelf-widget-context Initializers for creating a ShelfWidgetContext instance. ```APIDOC ## init(availableSize:isPaired:isShelfTransitioning:isPreview:surface:) ### Description Creates a context. Constructed by hosts, read by droplets. ### Method init ### Parameters - **availableSize** (CGSize) - Required - The host-owned layout size for this widget mount. - **isPaired** (Bool) - Optional - Defaults to `false`. True when the widget shares its row with one to three other widgets. - **isShelfTransitioning** (Bool) - Optional - Defaults to `false`. True while the shelf itself is animating open or closed. - **isPreview** (Bool) - Optional - Defaults to `false`. True when the view is mounted in a non-interactive preview. - **surface** (DropletSurfaceKind) - Optional - Defaults to `.builtInNotch`. The surface kind hosting the widget. ### Example ```swift ShelfWidgetContext(availableSize: CGSize(width: 100, height: 50), isPaired: true, isShelfTransitioning: false, isPreview: false, surface: .builtInNotch) ``` ``` ```APIDOC ## init(availableSize:isPaired:placement:isCompact:isShelfTransitioning:isPreview:surface:usesIslandCurvature:usesAdaptiveForegrounds:) ### Description Creates a context with the complete host-owned presentation facts. The legacy initializer above remains intact for already compiled droplets and older source clients. ### Method init ### Parameters - **availableSize** (CGSize) - Required - The host-owned layout size for this widget mount. - **isPaired** (Bool) - Required - True when the widget shares its row with one to three other widgets. - **placement** (ShelfWidgetPlacement) - Required - The widget's exact row placement. - **isCompact** (Bool) - Required - Whether the host requested the widget's compact composition. - **isShelfTransitioning** (Bool) - Required - True while the shelf itself is animating open or closed. - **isPreview** (Bool) - Required - True when the view is mounted in a non-interactive preview. - **surface** (DropletSurfaceKind) - Required - The surface kind hosting the widget. - **usesIslandCurvature** (Bool) - Required - Whether a solo card sits inside the dynamic-island curvature. - **usesAdaptiveForegrounds** (Bool) - Required - Whether the shelf is drawn over a transparent notch material and the product should select adaptive foreground colors. ### Example ```swift ShelfWidgetContext(availableSize: CGSize(width: 100, height: 50), isPaired: true, placement: .middle, isCompact: true, isShelfTransitioning: false, isPreview: false, surface: .builtInNotch, usesIslandCurvature: true, usesAdaptiveForegrounds: true) ``` ``` -------------------------------- ### ShelfWidgetDynamicLayoutProviding Source: https://getdroppy.app/docs/droppykit/api/shelf-widget-dynamic-layout-providing Documentation for the ShelfWidgetDynamicLayoutProviding protocol, including methods and properties that can be called directly. ```APIDOC ## GET /shelf-widget-dynamic-layout-providing ### Description Provides dynamic layout traits for shelf widgets. This protocol allows a product to supply layout traits that override the static descriptor traits, and to signal when those traits change. ### Method GET ### Endpoint /shelf-widget-dynamic-layout-providing ### Parameters #### Query Parameters - **id** (ShelfWidgetID) - Required - The identifier of the widget whose layout traits are requested. ### Response #### Success Response (200) - **traits** (ShelfWidgetLayoutTraits?) - The current layout traits for the widget, or null to keep the descriptor's static traits. #### Response Example ```json { "traits": { "width": 200, "height": 100 } } ``` ## GET /shelf-widget-layout-invalidation-publisher ### Description Provides a publisher that emits when a product-owned layout input changes. The emitted value identifies the widget whose traits the host should re-read. ### Method GET ### Endpoint /shelf-widget-layout-invalidation-publisher ### Parameters #### Query Parameters - **id** (ShelfWidgetID) - Required - The identifier of the widget whose layout invalidation is being observed. ### Response #### Success Response (200) - **publisher** (AnyPublisher) - A publisher that emits the widget ID when layout inputs change. #### Response Example ```json { "publisher": "AnyPublisher" } ``` ``` -------------------------------- ### Running the harness Source: https://getdroppy.app/docs/droppykit/harness Commands to run the harness and write a JSON report, optionally with screenshots. ```bash droppykit run -- --shots ./shots --report ./shots/report.json ``` ```bash droppykit run -- --report ./report.json ``` -------------------------------- ### CompactLiveActivityPresentationMetadata Source: https://getdroppy.app/docs/droppykit/api/compact-live-activity-presentation-metadata Documentation for the CompactLiveActivityPresentationMetadata struct, including its initializers and properties. ```APIDOC ## CompactLiveActivityPresentationMetadata A struct that provides compact presentation metadata for a live activity's leading accessory. ### Initializers #### init(id:accessibilityLabel:accessibilityValue:) Creates compact presentation metadata. - Parameters: - id: A stable identity for the compact presentation. - accessibilityLabel: An accessible name for the leading accessory. - accessibilityValue: An accessible state or detail for the leading accessory. #### init(id:accessibilityLabel:accessibilityValue:preferredWidth:) Creates compact presentation metadata with a preferred width. - Parameters: - id: A stable identity for the compact presentation. - accessibilityLabel: An accessible name for the leading accessory. - accessibilityValue: An accessible state or detail for the leading accessory. - preferredWidth: An optional preferred compact width. #### init(id:accessibilityLabel:accessibilityValue:preferredWidth:expandedShelfAutoCollapseDelay:) Creates compact presentation metadata with an explicit shelf auto-collapse delay. - Parameters: - id: A stable identity for the compact presentation. - accessibilityLabel: An accessible name for the leading accessory. - accessibilityValue: An accessible state or detail for the leading accessory. - preferredWidth: An optional preferred compact width. - expandedShelfAutoCollapseDelay: An optional fixed delay for auto-collapsing an expanded shelf. ### Properties #### accessibilityLabel - Type: `String` - Description: Accessible name for the product-owned leading accessory. #### accessibilityValue - Type: `String` - Description: Accessible state or detail for the product-owned leading accessory. #### expandedShelfAutoCollapseDelay - Type: `TimeInterval?` - Description: Optional fixed delay the host should use before auto-collapsing an expanded shelf while this compact activity is live. #### id - Type: `String` - Description: Stable identity for this compact presentation while it is live. #### preferredWidth - Type: `CGFloat?` - Description: Optional preferred compact width. The host still owns all clamping, placement, and hit testing. ``` -------------------------------- ### Submit a droplet with droppykit submit Source: https://getdroppy.app/docs/droppykit/submitting Push your repository, then run this command to open getdroppy.app/submit-droplet with the repository, commit, and id filled in from your checkout. It refuses if there are uncommitted changes or HEAD is not on the remote, because the intake clones exactly that commit. You then add your name and an address for replies, or you can open the page and enter the three by hand. ```bash droppykit submit ``` -------------------------------- ### Run the harness with droppykit run Source: https://getdroppy.app/docs/droppykit/harness Runs the harness as a signed .app via open; the optional --page flag opens directly onto a surface. A bare swift run produces an unbundled binary with fallback window chrome. ```shell droppykit run # or Scripts/run-harness.sh WorldClockHarness ``` ```shell droppykit run --page shelf-widget # open straight onto one surface ``` -------------------------------- ### init(priority:accessibilityTitle:isInteractive:joinsPersistentActivitySet:) Source: https://getdroppy.app/docs/droppykit/api/live-activity-state Creates an activity state without a hoisted compact presentation. This overload remains the DroppyKit 0.6.1 ABI entry point. ```APIDOC ## init(priority:accessibilityTitle:isInteractive:joinsPersistentActivitySet:) ### Description Creates an activity state without a hoisted compact presentation. This overload remains the DroppyKit 0.6.1 ABI entry point. ### Method Initializer ### Signature `init(priority: Int, accessibilityTitle: String, isInteractive: Bool = false, joinsPersistentActivitySet: Bool = false)` ### Parameters - **priority** (Int) - Required - Priority when several droplets want the compact slot at once. Higher wins; the host resolves ties in registration order. - **accessibilityTitle** (String) - Required - Accessibility title for the activity pill. - **isInteractive** (Bool) - Optional - True when the expanded activity accepts pointer interaction. Defaults to `false`. - **joinsPersistentActivitySet** (Bool) - Optional - True when the activity joins the host's persistent live-activity set. Defaults to `false`. ### Notes This overload is kept for ABI compatibility with DroppyKit 0.6.1. ``` -------------------------------- ### makeBody(configuration:) method Source: https://getdroppy.app/docs/droppykit/api/droppy-live-activity-control-style Returns the view body for the control style. The method is marked @MainActor and returns some View. ```swift @MainActor func makeBody(configuration: Configuration) -> some View ``` -------------------------------- ### DropletSurfaceAppearance.init(rawValue:) Source: https://getdroppy.app/docs/droppykit/api/droplet-surface-appearance Initializer that creates a DropletSurfaceAppearance from a raw string value. ```APIDOC ## DropletSurfaceAppearance.init(rawValue:) ### Description Initializes a DropletSurfaceAppearance from a raw string value. ### Declaration `init?(rawValue: String)` ``` -------------------------------- ### LiveActivityContext Source: https://getdroppy.app/docs/droppykit/api/live-activity-context Documentation for the LiveActivityContext struct, including its initializers and properties. ```APIDOC ## init(surface:availableWidth:) ### Description Creates a context. Constructed by hosts, read by droplets. This exact overload remains the legacy ABI entry point and supplies the same settled presentation old hosts implicitly provided. ### Method init ### Endpoint init(surface:availableWidth:) ### Parameters #### Parameters - **surface** (DropletSurfaceKind) - Required - The surface kind hosting the activity. - **availableWidth** (CGFloat) - Required - The width the card's content is given, inside the host's insets. ### Return Value A LiveActivityContext instance. ## init(surface:availableWidth:presentation:) ### Description Creates a context with the current host presentation state. ### Method init ### Endpoint init(surface:availableWidth:presentation:) ### Parameters #### Parameters - **surface** (DropletSurfaceKind) - Required - The surface kind hosting the activity. - **availableWidth** (CGFloat) - Required - The width the card's content is given, inside the host's insets. - **presentation** (LiveActivityPresentationState) - Required - Live host presentation facts. Product views use these to freeze local animation or metering while the host is transitioning or concealed. ### Return Value A LiveActivityContext instance. ## availableWidth ### Description The width the card's content is given, inside the host's insets. The host has already cleared the camera housing above and the opened shoulders either side, so this is the width you may actually use. The content is `cardContentHeight` tall. ### Method property ### Endpoint availableWidth ### Parameters None ### Return Value CGFloat ## presentation ### Description Live host presentation facts. Product views use these to freeze local animation or metering while the host is transitioning or concealed. ### Method property ### Endpoint presentation ### Parameters None ### Return Value LiveActivityPresentationState ## surface ### Description The surface kind hosting the activity. ### Method property ### Endpoint surface ### Parameters None ### Return Value DropletSurfaceKind ``` -------------------------------- ### init(title:icon:iconColor:subtitle:isOn:) Source: https://getdroppy.app/docs/droppykit/api/droplet-toggle-row Creates a toggle row with a title, optional icon, icon color, subtitle, and a binding to the toggle state. ```APIDOC ## Initializer: init(title:icon:iconColor:subtitle:isOn:) ### Description Creates a toggle row with a title, optional SF Symbol icon, icon tint, subtitle, and a binding to the toggle state. ### Signature `@MainActor init(title: String, icon: String? = nil, iconColor: Color? = nil, subtitle: String = "", isOn: Binding)` ### Parameters - **title** (String) - Required - Row title, sentence case. - **icon** (String?) - Optional - Optional SF Symbol before the title. - **iconColor** (Color?) - Optional - Icon tint, defaults to secondary. - **subtitle** (String) - Optional - Info tip text; empty hides the tip. - **isOn** (Binding) - Required - The toggle binding. ### Example ```swift DropletToggleRow( title: "Enable Notifications", icon: "bell", iconColor: .blue, subtitle: "Receive alerts", isOn: $notificationsEnabled ) ``` ``` -------------------------------- ### init(id:duration:priority:accessibilityLabel:content:) Source: https://getdroppy.app/docs/droppykit/api/droplet-hudrequest Creates a HUD request with a strip-only content view. Use this initializer when the HUD does not need an expanded card shape. ```APIDOC ## init(id:duration:priority:accessibilityLabel:content:) ### Description Creates a HUD request with a strip-only content view. Use this initializer when the HUD does not need an expanded card shape. ### Signature `init(id: String, duration: TimeInterval? = 2.0, priority: DropletHUDPriority = .normal, accessibilityLabel: String, @ViewBuilder content: @escaping @MainActor @Sendable () -> some View)` ### Parameters - **id** (String) - Required - Stable id. A second request with the same id replaces the first in place instead of queueing behind it. - **duration** (TimeInterval?) - Optional - How long the HUD stays up. `nil` keeps it until it is replaced or the droplet dismisses it. Defaults to 2.0. - **priority** (DropletHUDPriority) - Optional - Priority band. Defaults to `.normal`. - **accessibilityLabel** (String) - Required - Spoken description for VoiceOver. - **content** (some View) - Required - The HUD's content. Built on demand and may be rebuilt on layout changes, so keep it a pure function of your model. ``` -------------------------------- ### Render screenshots of every surface with --shots Source: https://getdroppy.app/docs/droppykit/harness Renders every harness page to a PNG and exits without a window; --shot-height renders a page taller than the default height in one image. A relative directory is resolved from the package root. ```shell droppykit run -- --shots ./shots ``` ```shell droppykit run -- --shots ./shots --shot-height 1900 ``` -------------------------------- ### DropletHarnessApp entry point (not main.swift) Source: https://getdroppy.app/docs/droppykit/harness Defines the harness entry point for a droplet in an executable target using the DropletHarnessApp protocol. The file must not be named main.swift because Swift treats that as top-level code that cannot coexist with @main. ```swift import DroppyKit import DroppyKitHarness @main struct WorldClockHarness: DropletHarnessApp { static func makeDroplet() -> any Droplet { WorldClockDroplet() } } ``` -------------------------------- ### open(_:) Source: https://getdroppy.app/docs/droppykit/api/droplet-workspace-service Opens a URL in the user's default handler. Returns `false` when the host refused, which it does for schemes outside `http`, `https`, `mailto`, and `file` unless the droplet declared them. ```APIDOC ## open(_:) ### Description Opens a URL in the user's default handler. Returns `false` when the host refused, which it does for schemes outside `http`, `https`, `mailto`, and `file` unless the droplet declared them. ### Method `@discardableResult @MainActor func open(_ url: URL) -> Bool` ### Parameters - **url** (URL) - Required - The URL to open. ### Return Value - **Bool** - Returns `true` if the URL was opened successfully, otherwise `false`. ### Example ```swift let opened = dropletWorkspace.open(URL(string: "https://example.com")!) ``` ``` -------------------------------- ### apply(_:) Source: https://getdroppy.app/docs/droppykit/api/droppy-markdown-editor-commands Applies a formatting command to the bound editor. ```APIDOC ## apply(_:) ### Description Applies a formatting command to the bound editor. ### Method apply ### Signature `@MainActor func apply(_ action: DroppyMarkdownToolbarAction)` ### Parameters - **action** (DroppyMarkdownToolbarAction) - Required - The formatting command to apply. ### Return Value Void ### Example ```swift commands.apply(.bold) ``` ``` -------------------------------- ### SettingsPaneProviding implementation Source: https://getdroppy.app/docs/droppykit/settings-panes Conform to SettingsPaneProviding to provide a settings pane for your droplet. makeSettingsPane returns the pane view, and settingsSearchEntries adds search entries so users can find the pane via Settings search. ```swift extension WorldClockDroplet: SettingsPaneProviding { public func makeSettingsPane(context: SettingsPaneContext) -> AnyView { AnyView(WorldClockSettings(droplet: self)) } public var settingsSearchEntries: [SettingsSearchEntry] { [SettingsSearchEntry(title: "Show seconds", keywords: ["time", "clock"])] } } ``` -------------------------------- ### init(_:) Source: https://getdroppy.app/docs/droppykit/api/droplet-id Creates an identifier from a raw string. This initializer is unchecked and should be used when the raw value is already trusted. ```APIDOC ## init(_:) ### Description Creates an identifier from a raw string. This initializer is unchecked and should be used when the raw value is already trusted. ### Signature `init(_ rawValue: String)` ### Parameters - **rawValue** (String) - The raw string value of the identifier. ### Notes This initializer does not validate the raw value. Use `init(validating:)` for values from outside the process. ``` -------------------------------- ### Check droplet link with nm and otool Source: https://getdroppy.app/docs/droppykit-handbook Verify the droplet bundle's link. The nm command returns 0 for a correct bundle and non-zero for a broken one; otool must name the framework and must not name libDroppyKit. ```bash # 0 in a correct bundle, non-zero in a broken one. nm -u WorldClock.droplet/Contents/MacOS/WorldClock | grep -c '9DroppyKit.*vau' # Must name the framework, and must not name libDroppyKit. otool -L WorldClock.droplet/Contents/MacOS/WorldClock | grep DroppyKit ``` -------------------------------- ### init(id:duration:priority:accessibilityLabel:isExpanded:expandedContentHeight:content:expanded:) Source: https://getdroppy.app/docs/droppykit/api/droplet-hudrequest Creates a HUD that has both shapes: a strip and an expanded card. Use this initializer when the HUD can grow from a strip into a card. ```APIDOC ## init(id:duration:priority:accessibilityLabel:isExpanded:expandedContentHeight:content:expanded:) ### Description Creates a HUD that has both shapes: a strip and an expanded card. Use this initializer when the HUD can grow from a strip into a card. ### Signature `init(id: String, duration: TimeInterval? = 2.0, priority: DropletHUDPriority = .normal, accessibilityLabel: String, isExpanded: Bool, expandedContentHeight: CGFloat? = nil, @ViewBuilder content: @escaping @MainActor @Sendable () -> some View, @ViewBuilder expanded: @escaping @MainActor @Sendable () -> some View)` ### Parameters - **id** (String) - Required - Stable id. A second request with the same id replaces the first in place instead of queueing behind it. - **duration** (TimeInterval?) - Optional - How long the HUD stays up. `nil` keeps it until it is replaced or the droplet dismisses it. Defaults to 2.0. - **priority** (DropletHUDPriority) - Optional - Priority band. Defaults to `.normal`. - **accessibilityLabel** (String) - Required - Spoken description for VoiceOver. - **isExpanded** (Bool) - Required - Whether the card is showing rather than the strip. Drive this from your own state and re-present with the SAME id. - **expandedContentHeight** (CGFloat?) - Optional - Height the card wants, in points, or `nil` for the host's standard expanded height. Defaults to `nil`. - **content** (some View) - Required - The HUD's content. Built on demand and may be rebuilt on layout changes, so keep it a pure function of your model. - **expanded** (some View) - Required - The card this HUD grows into. ``` -------------------------------- ### Publishing LiveActivityState Source: https://getdroppy.app/docs/droppykit/live-activities Implement the LiveActivityProviding protocol to emit state updates. Use a priority value to compete for the compact seat and publish nil when the task concludes. ```swift extension WorldClockDroplet: LiveActivityProviding { public var liveActivityState: AnyPublisher { activitySubject.eraseToAnyPublisher() } private func publishActivity() { activitySubject.send( LiveActivityState( priority: 200, accessibilityTitle: "Amsterdam \(time)", isInteractive: false ) ) } } ``` -------------------------------- ### init(from:) Source: https://getdroppy.app/docs/droppykit/api/droplet-id Initializes a DropletID by decoding from a decoder. This is part of the Decodable conformance. ```APIDOC ## init(from:) ### Description Initializes a DropletID by decoding from a decoder. This is part of the Decodable conformance. ### Signature `init(from decoder: Decoder) throws` ### Parameters - **decoder** (Decoder) - The decoder to read data from. ### Throws An error if decoding fails. ``` -------------------------------- ### LockScreenStatusEntry Source: https://getdroppy.app/docs/droppykit/api/lock-screen-status-entry Documentation for the LockScreenStatusEntry struct, including its initializers and properties. ```APIDOC ## LockScreenStatusEntry A single entry in the lock screen status widget strip. ### Initializers #### init(from:) `init(from decoder: Decoder) throws` Older persisted entries predate an explicit cadence flag. Preserve their established interpretation by deriving cadence from progress when the new key is absent. #### init(id:systemImage:text:detail:roundedCenterText:roundedBottomText:progress:) `init(id: String, systemImage: String, text: String, detail: String? = nil, roundedCenterText: String? = nil, roundedBottomText: String? = nil, progress: Double? = nil)` Creates an entry. Everything past `text` is optional chip payload; omitting all of it produces the plain horizontal strip entry. This is the original ABI entry point. Keep its exact symbol and infer cadence from ring progress so pre-cadence droplets retain their behavior. #### init(id:systemImage:text:detail:roundedCenterText:roundedBottomText:progress:ticksEverySecond:) `init(id: String, systemImage: String, text: String, detail: String? = nil, roundedCenterText: String? = nil, roundedBottomText: String? = nil, progress: Double? = nil, ticksEverySecond: Bool)` Creates an entry with an explicit display cadence. ### Properties #### detail `let detail: String?` Secondary label beside `text` in the horizontal strip style, for example a mode name. `nil` shows the primary text alone. #### id `let id: String` Stable identifier within the droplet. #### progress `let progress: Double?` Ring progress in `0...1` for the rounded strip style, for example a timer's remaining fraction. `nil` draws the idle arc. #### roundedBottomText `let roundedBottomText: String?` Caption under the ring in the rounded strip style. `nil` falls back to `text`. #### roundedCenterText `let roundedCenterText: String?` Compact value rendered inside the ring in the rounded strip style. `nil` falls back to the SF Symbol. #### systemImage `let systemImage: String` SF Symbol shown in the strip. #### text `let text: String` Short status text, for example a remaining time. #### ticksEverySecond `let ticksEverySecond: Bool` Whether the host should re-render this entry at second cadence while the display is awake. This is intentionally independent from `progress`: a timer can update its text every second without rendering a rounded progress ring. ``` -------------------------------- ### DroppyOpacity.medium Source: https://getdroppy.app/docs/droppykit/api/droppy-opacity Medium overlay (0.1), hover states. ```APIDOC ## DroppyOpacity.medium ### Description Medium overlay (0.1), hover states. ### Type Double ### Value 0.1 ``` -------------------------------- ### DroppyOpacity.strong Source: https://getdroppy.app/docs/droppykit/api/droppy-opacity Strong overlay (0.2), emphasized elements. ```APIDOC ## DroppyOpacity.strong ### Description Strong overlay (0.2), emphasized elements. ### Type Double ### Value 0.2 ```