Custom File "New Document" to show template-picker in a document-based app

I am writing a document-based app for macOS using SwiftUI. I want the File menu's New Document command to show a template picker/wizard, and then let the wizard create the document.

How do I structure this? Is there documentation? Examples?

I tried this pattern

@main struct DocDemoApp: App {
    var body: some Scene {
        WindowGroup { NewDocWizard() }
        DocumentGroup(newDocument: { DocDemoDocument() }) { 
            ContentView(document: $0.document)
        }
    }
}

The NewDocWizard calls newDocument({ DocDemoDocument() }). But the WindowGroup makes a File > New Window command while DocumentGroup makes the File > New Document command. I need just New Document and it should show the NewDocWizard.

Answered by LogicalLight in 742324022

Answering my own question. I want to use Commands. See newItem.

Here's an example:

struct DocDemoApp: App {
    @Environment(\.openWindow) var openWindow
    @Environment(\.openDocument) private var openDocument
    var body: some Scene {
        DocumentGroup(newDocument: { DocDemoDocument() }) { config in
            ContentView(document: config.document)
        }
        Window("Choose Template", id: "wizard") {
            NewDocWizard()
        }
        .commands {
            CommandGroup(replacing: .newItem) {
                Section {
                    // Menu File >
                    Button("New") { openWindow(id: "wizard") }.keyboardShortcut(KeyboardShortcut("N"))
                    Button("Open") { open() }.keyboardShortcut(KeyboardShortcut("o"))
                    Button("Open Recent...") { print("NYI") }
                }
            }
            CommandGroup(replacing: .singleWindowList) {
                // Menu Window > Choose Template, ... (list of single windows)
                // Hide and force user to use File > New for this window
            }
        }
    }
    private func open() {
        let panel = NSOpenPanel()
        panel.allowedContentTypes = [.exampleText]
        panel.allowsMultipleSelection = true
        panel.canChooseDirectories = false
        panel.runModal()
        if let url = panel.url {
            Task {
                try! await openDocument(at: url)
            }
        }
    }
}
Accepted Answer

Answering my own question. I want to use Commands. See newItem.

Here's an example:

struct DocDemoApp: App {
    @Environment(\.openWindow) var openWindow
    @Environment(\.openDocument) private var openDocument
    var body: some Scene {
        DocumentGroup(newDocument: { DocDemoDocument() }) { config in
            ContentView(document: config.document)
        }
        Window("Choose Template", id: "wizard") {
            NewDocWizard()
        }
        .commands {
            CommandGroup(replacing: .newItem) {
                Section {
                    // Menu File >
                    Button("New") { openWindow(id: "wizard") }.keyboardShortcut(KeyboardShortcut("N"))
                    Button("Open") { open() }.keyboardShortcut(KeyboardShortcut("o"))
                    Button("Open Recent...") { print("NYI") }
                }
            }
            CommandGroup(replacing: .singleWindowList) {
                // Menu Window > Choose Template, ... (list of single windows)
                // Hide and force user to use File > New for this window
            }
        }
    }
    private func open() {
        let panel = NSOpenPanel()
        panel.allowedContentTypes = [.exampleText]
        panel.allowsMultipleSelection = true
        panel.canChooseDirectories = false
        panel.runModal()
        if let url = panel.url {
            Task {
                try! await openDocument(at: url)
            }
        }
    }
}
Custom File "New Document" to show template-picker in a document-based app
 
 
Q