# Native Markup Language (NML) Specification Version 1.0 ## 1. Overview Native Markup Language (NML) is a markup language derived from SGML, designed to represent composable UI frameworks. This specification defines the conversion from SwiftUI to NML. ## 2. Document Headers and Type ### 2.1 HTTP Headers When serving NML documents: Request Headers: ``` ACCEPT: application/swiftui ``` Response Headers: ``` CONTENT-TYPE: application/swiftui ``` ### 2.2 Document Type Declaration NML documents must begin with a doctype declaration. For SwiftUI documents: ```html <!doctype swiftui> <nml> <head> <Style url="/styles/main.nss"/> </head> <body> <Text>Hello World</Text> </body> </nml> ``` The doctype declaration is used for document annotation only and is ignored by parsers. ## 3. Document Structure ### 3.1 Basic Structure NML documents require the following structure: ```html <nml> <head> <Style url="/styles/main.nss"/> </head> <body> <!-- Application views go here --> <NavigationStack> <Text>Hello World</Text> </NavigationStack> </body> </nml> ``` ### 3.2 Head Section The head section contains: - Style references using the `Style` tag - Template definitions for lifecycle views - Other client configuration elements Example of style inclusion: ```html <head> <Style url="/base.nss"/> <Style url="/components.nss"/> <Style url="/theme-dark.nss"/> </head> ``` ### 3.3 Body Section The `body` tag is required and must contain the application's view hierarchy: ```html <body> <TabView> <VStack tabItem="Home"> <Text>Welcome to the Home Tab</Text> <Button>Get Started</Button> </VStack> <ScrollView tabItem="Settings"> <VStack spacing="16"> <Toggle isOn="true">Dark Mode</Toggle> <Toggle isOn="false">Notifications</Toggle> </VStack> </ScrollView> </TabView> </body> ``` ### 3.4 Lifecycle Templates Clients can define views for different UI lifecycle states in the head section: #### SwiftUI Lifecycle States ##### Disconnected State ```html <head> <VStack template="disconnected" spacing="16"> <Image source="cloud.slash"/> <Text style="font(.headline)">Connection Lost</Text> <Text style="foregroundStyle(.secondary)"> Attempting to reconnect... </Text> <ProgressView/> </VStack> </head> ``` ##### Reconnecting State ```html <head> <VStack template="reconnecting" spacing="16"> <ProgressView style="progressViewStyle(.circular)"/> <Text>Reconnecting...</Text> <Button style="buttonStyle(.bordered)"> Cancel </Button> </VStack> </head> ``` ##### Error State ```html <head> <VStack template="error" spacing="16"> <Image source="exclamationmark.triangle.fill"/> <Text style="font(.headline)">An Error Occurred</Text> <Text style="foregroundStyle(.secondary)"> Unable to complete the requested operation </Text> <Button style="buttonStyle(.bordered)"> Retry </Button> </VStack> </head> ``` ## 4. Basic Conversion Rules ### 4.1 Views to Elements SwiftUI views convert directly to NML elements with exact case preservation of the view name: ```swift LazyVStack(alignment: .leading) { Text("Hello") ScrollView(.horizontal) { Text("World") } } ``` Converts to: ```html <LazyVStack alignment="leading"> <Text>Hello</Text> <ScrollView axis="horizontal"> <Text>World</Text> </ScrollView> </LazyVStack> ``` ### 4.2 Arguments to Attributes View initialization arguments become element attributes with exact case preservation: ```swift NavigationLink(destination: DetailView(), isActive: true, label: "Settings") .buttonStyle(.bordered) ``` Converts to: ```html <NavigationLink destination="DetailView" isActive="true" label="Settings"> ``` The values maintain their string representation, but the client infers: - `isActive="true"` as `Bool` because `isActive` is `Bool` in SwiftUI - `label="Settings"` as `String` because `label` is `String` in SwiftUI - `destination="DetailView"` as `View` because `destination` is `View` in SwiftUI ### 4.3 Boolean Attributes Unlike HTML, NML requires explicit boolean values for attributes: ```swift Toggle("Light", isOn: true) Toggle("Dark", isOn: false) ``` Converts to: ```html <Toggle isOn="true">Light</Toggle> <Toggle isOn="false">Dark</Toggle> ``` The following are invalid in NML: ```html <!-- Invalid: boolean attribute without value --> <Toggle isOn>Light</Toggle> <!-- Invalid: omitted boolean attribute --> <Toggle>Light</Toggle> ``` ### 4.4 Attribute Value Encoding - All attribute values are strings - Special characters must be encoded using HTML character entities: - `"` becomes `"` - `&` becomes `&` - `<` becomes `<` - `>` becomes `>` JSON encoding is only allowed for arrays and lists in attribute values: ```swift Text(items: [1, 2, 3]) ``` Converts to: ```html <Text items="[1,2,3]"/> ``` ### 4.5 The id Modifier The `id` modifier is unique in that it's the only modifier that converts to an attribute rather than being included in the style attribute: ```swift Text("Hello") .id("greeting") .padding() ``` Converts to: ```html <Text id="greeting" style="padding()">Hello</Text> ``` ### 4.6 Modifiers to Style Attributes SwiftUI view modifiers convert to style attributes, with member expressions retaining their leading dots: ```swift Text("Hello") .padding() .foregroundStyle(.green) ``` Converts to: ```html <Text style="padding(); foregroundStyle(.green)">Hello</Text> ``` ### 4.7 View Builder Closures and Templates View builder closures in modifiers use template references. Templates must be defined as direct children of the element that references them, and template names must only be unique among siblings: ```swift VStack { RoundedRectangle(cornerRadius: 8) .overlay(alignment: .topLeading) { Star(color: .red) } Circle() .overlay { Star(color: .blue) } } ``` Converts to: ```html <VStack> <RoundedRectangle cornerRadius="8" style="overlay(alignment: .topLeading, content: :starOverlay)" > <Star color="red" template="starOverlay"/> </RoundedRectangle> <Circle style="overlay(content: :starOverlay)"> <Star color="blue" template="starOverlay"/> </Circle> </VStack> ``` ## 5. The attr Helper The `attr` helper provides a way to reference element attribute values within style declarations: ```swift VStack { } .navigationTitle("Home") ``` Converts to: ```html <VStack navTitle="Home" style="navigationTitle(attr(:navTitle))"> ``` Multiple attr references can be used within the same style string: ```swift Circle() .fill(.blue) .frame(width: 100, height: 100) .padding(.horizontal, 20) ``` Converts to: ```html <Circle fillColor="blue" frameWidth="100" frameHeight="100" padAmount="20" style="fill(attr(:fillColor)); frame(width: attr(:frameWidth), height: attr(:frameHeight)); padding(.horizontal, attr(:padAmount))" /> ``` ## 6. Stylesheets Similar to HTML, NML supports extracting styles into separate stylesheets that can be referenced using class names: ```swift Button("Submit") { } .padding() .background(.blue) .foregroundStyle(.white) ``` Can be represented using a class reference: ```html <Button class="primary-button">Submit</Button> ``` The definition and structure of stylesheets are defined in the Native Stylesheet (NSS) specification document. ## 7. SwiftUI Documentation Conversion ### 7.1 Initialize with Arguments SwiftUI: ```swift /// Creates a toggle that generates its label from a string. /// /// - Parameters: /// - title: A string that describes the purpose of the toggle. /// - isOn: A binding to a Boolean value that determines the toggle's state. public init(_ title: String, isOn: Binding<Bool>) ``` SwiftUI usage: ```swift Toggle("Switch Theme", isOn: $isDarkMode) ``` Converts to: ```html <Toggle isOn="true">Switch Theme</Toggle> ``` ### 7.2 Multiple Initializer Variants SwiftUI: ```swift extension Button where Label == Text { /// Creates a button that displays a text label. public init(_ title: String, action: @escaping () -> Void) /// Creates a button that displays a localized text label. public init(_ titleKey: LocalizedStringKey, action: @escaping () -> Void) } ``` SwiftUI usage: ```swift Button("Save") { saveData() } Button("welcome.message") { showWelcome() } ``` Converts to: ```html <Button>Save</Button> <Button localized="true">welcome.message</Button> ``` ## 8. Validation Rules 1. Elements must be properly nested and closed 2. Template names must be unique only among sibling elements 3. Templates must be defined as direct children of the element referencing them 4. All attribute values must be properly encoded 5. Member expressions within style values must retain their leading dot (e.g., `.green`), while attribute values on elements must not have leading dots (e.g., `alignment="leading"`) 6. Only arrays and lists may be JSON-encoded in attribute values 7. All attr references must point to existing attributes on the current element 8. Boolean attributes must have explicit values 9. Application views must be contained within the body tag 10. Lifecycle templates must be defined in the head section ## 9. File Format - File extension: `.nml` - Encoding: UTF-8 - Whitespace is preserved within text content