diff --git a/Sources/HTMLKitComponents/Components/Button.swift b/Sources/HTMLKitComponents/Components/Button.swift
index 7551cc0c..e0cb8e4f 100644
--- a/Sources/HTMLKitComponents/Components/Button.swift
+++ b/Sources/HTMLKitComponents/Components/Button.swift
@@ -6,12 +6,21 @@
import HTMLKit
import Foundation
-/// A component that initiates an action.
+/// A view that represents a button.
+///
+/// Use `Button` to trigger an action when tapped or clicked.
+///
+/// ```swift
+/// Button(role: .button) {
+/// "Lorem ipsum"
+/// }
+/// ```
public struct Button: View, Modifiable, Actionable {
+ /// The identifier of the button.
internal var id: String?
- /// The role of the button
+ /// The role of the button.
internal var role: HTMLKit.Values.Button
/// The content of the button.
@@ -20,9 +29,14 @@ public struct Button: View, Modifiable, Actionable {
/// The classes of the button.
internal var classes: [String]
+ /// The events of the button.
internal var events: [String]?
- /// Creates a action button.
+ /// Create a button.
+ ///
+ /// - Parameters:
+ /// - role: The role of the button.
+ /// - content: The button's content.
public init(role: HTMLKit.Values.Button, @ContentBuilder content: () -> [Content]) {
self.role = role
@@ -30,6 +44,18 @@ public struct Button: View, Modifiable, Actionable {
self.classes = ["button"]
}
+ /// Create a button.
+ ///
+ /// - Parameters:
+ /// - localizedStringKey: The key of the localized string used as a label.
+ /// - role: The role of the button.
+ public init(_ localizedStringKey: LocalizedStringKey, role: HTMLKit.Values.Button) {
+
+ self.role = role
+ self.content = [LocalizedString(key: localizedStringKey)]
+ self.classes = ["button"]
+ }
+
public var body: Content {
HTMLKit.Button {
self.content
@@ -146,11 +172,21 @@ extension Button: ViewModifier {
}
}
-/// A component that initiates an action.
+/// A view that represents a link button.
+///
+/// Use `LinkButton`to navigate to a target.
+///
+/// ```swift
+/// LinkButton(destination: "https://..") {
+/// "Lorem ipsum"
+/// }
+/// ```
public struct LinkButton: View, Modifiable, Identifiable {
+ /// The unique identifier of the button.
internal var id: String?
+ /// The target behaviour for the destination
internal let target: HTMLKit.Values.Target
/// The url path of the target.
@@ -165,7 +201,12 @@ public struct LinkButton: View, Modifiable, Identifiable {
/// The events of the button.
internal var events: [String]?
- /// Creates a action button.
+ /// Create a link button.
+ ///
+ /// - Parameters:
+ /// - destination: The url of the target to navigate to.
+ /// - target: The behaviour that determines how to open the target.
+ /// - content: The content displayed as the label.
public init(destination: String, target: HTMLKit.Values.Target = .current, @ContentBuilder content: () -> [Content]) {
self.destination = destination
@@ -174,7 +215,26 @@ public struct LinkButton: View, Modifiable, Identifiable {
self.classes = ["button"]
}
- /// Creates a action button.
+ /// Create a link button.
+ ///
+ /// - Parameters:
+ /// - localizedStringKey: The key of the localized string used as the label.
+ /// - destination: The url of the target to navigate to.
+ /// - target: The behaviour that determines how to open the target.
+ public init(_ localizedStringKey: LocalizedStringKey, destination: String, target: HTMLKit.Values.Target = .current) {
+
+ self.destination = destination
+ self.target = target
+ self.content = [LocalizedString(key: localizedStringKey)]
+ self.classes = ["button"]
+ }
+
+ /// Create a link button.
+ ///
+ /// - Parameters:
+ /// - destination: The url of the target to navigate to.
+ /// - target: The behaviour that determines how to open the target.
+ /// - content: The content displayed as the label.
public init(destination: URL, target: HTMLKit.Values.Target = .current, @ContentBuilder content: () -> [Content]) {
self.destination = destination.absoluteString
@@ -183,6 +243,20 @@ public struct LinkButton: View, Modifiable, Identifiable {
self.classes = ["button"]
}
+ /// Create a link button.
+ ///
+ /// - Parameters:
+ /// - localizedStringKey: The key of the localized string used as the label.
+ /// - destination: The url of the target to navigate to.
+ /// - target: The behaviour that determines how to open the target.
+ public init(_ localizedStringKey: LocalizedStringKey, destination: URL, target: HTMLKit.Values.Target = .current) {
+
+ self.destination = destination.absoluteString
+ self.target = target
+ self.content = [LocalizedString(key: localizedStringKey)]
+ self.classes = ["button"]
+ }
+
public var body: Content {
Anchor {
self.content
diff --git a/Sources/HTMLKitComponents/Components/Disclosure.swift b/Sources/HTMLKitComponents/Components/Disclosure.swift
index 24d8d81d..9c819896 100644
--- a/Sources/HTMLKitComponents/Components/Disclosure.swift
+++ b/Sources/HTMLKitComponents/Components/Disclosure.swift
@@ -5,17 +5,34 @@
import HTMLKit
-/// A component that distinguish content.
+/// A view that represents a disclosure.
+///
+/// Use `Disclosure` to reveal or hide content when interacted with.
+///
+/// ```swift
+/// Disclosure("Lorem ipsum") {
+/// Text {
+/// "Lorem ipsum..."
+/// }
+/// }
+/// ```
public struct Disclosure: View, Modifiable {
- internal let label: String
+ /// The label of the disclosure.
+ internal let label: Content
+ /// The disclosure's content.
internal let content: [Content]
/// The classes of the content.
internal var classes: [String]
-
- /// Creates a card.
+
+ /// Create a disclosure.
+ ///
+ /// - Parameters:
+ /// - label: The label to describe the content.
+ /// - content: The disclosure's content.
+ @_disfavoredOverload
public init(_ label: String, @ContentBuilder content: () -> [Content]) {
self.label = label
@@ -23,6 +40,18 @@ public struct Disclosure: View, Modifiable {
self.classes = ["disclosure"]
}
+ /// Create a disclosure.
+ ///
+ /// - Parameters:
+ /// - label: The key of the localized string to describe the content.
+ /// - content: The disclosure's content.
+ public init(_ label: LocalizedStringKey, @ContentBuilder content: () -> [Content]) {
+
+ self.label = LocalizedString(key: label)
+ self.content = content()
+ self.classes = ["disclosure"]
+ }
+
public var body: Content {
Division {
Division {
diff --git a/Sources/HTMLKitComponents/Components/Form.swift b/Sources/HTMLKitComponents/Components/Form.swift
index d59ffeb7..60c19497 100644
--- a/Sources/HTMLKitComponents/Components/Form.swift
+++ b/Sources/HTMLKitComponents/Components/Form.swift
@@ -62,7 +62,15 @@ extension Form: FormEvent {
}
}
-/// A component that displays the name of the form control.
+/// A view that represents a field label.
+///
+/// Use `FieldLabel` to display the name for the form control.
+///
+/// ```swift
+/// FieldLabel(for: "lorem") {
+/// "Lorem ipsum"
+/// }
+/// ```
public struct FieldLabel: View {
/// The identifier of the element the label is related to.
@@ -77,7 +85,11 @@ public struct FieldLabel: View {
/// The events of the label.
internal var events: [String]?
- /// Creates a field label.
+ /// Create a field label.
+ ///
+ /// - Parameters:
+ /// - id: The identifier of the field to associate the label with.
+ /// - content: The text content to display in the label.
public init(for id: String, @ContentBuilder content: () -> [Content]) {
self.id = id
@@ -85,6 +97,18 @@ public struct FieldLabel: View {
self.classes = ["label"]
}
+ /// Create a field label.
+ ///
+ /// - Parameters:
+ /// - localizedStringKey: The key of the localized string to look for.
+ /// - id: The identifier of the field to associate the label with.
+ public init(_ localizedStringKey: LocalizedStringKey, for id: String) {
+
+ self.id = id
+ self.content = [LocalizedString(key: localizedStringKey)]
+ self.classes = ["label"]
+ }
+
public var body: Content {
Label {
content
@@ -94,16 +118,23 @@ public struct FieldLabel: View {
}
}
-/// A component that displays an editable form control.
+/// A view that represents a text field.
+///
+/// Use `TextField` to display an editable form control.
+///
+/// ```swift
+/// TextField(name: "lorem", prompt: "Lorem ipsum", value: "Lorem ipsum")
+/// ```
public struct TextField: View, Modifiable, Identifiable {
+ /// The identifier of the field.
internal var id: String?
- /// The identifier of the field.
+ /// The name of the field.
internal let name: String
/// The placeholder for the field value.
- internal let prompt: String?
+ internal let prompt: PromptType?
/// The content of the field.
internal let value: String?
@@ -114,11 +145,31 @@ public struct TextField: View, Modifiable, Identifiable {
/// The events of the field.
internal var events: [String]?
- /// Creates a text field.
+ /// Create a text field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The prompt to guide the user.
+ /// - value: The value to edit within the field.
+ @_disfavoredOverload
public init(name: String, prompt: String? = nil, value: String? = nil) {
self.name = name
- self.prompt = prompt
+ self.prompt = prompt.map(PromptType.string(_:))
+ self.value = value
+ self.classes = ["textfield"]
+ }
+
+ /// Create a text field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The key of the localized string to guide the user.
+ /// - value: The value to edit within the field.
+ public init(name: String, prompt: LocalizedStringKey? = nil, value: String? = nil) {
+
+ self.name = name
+ self.prompt = prompt.map(PromptType.value(_:))
self.value = value
self.classes = ["textfield"]
}
@@ -216,7 +267,14 @@ extension TextField: ViewModifier {
}
}
-/// A component that displays a editable and expandable form control.
+/// A view that represents a text editor.
+///
+/// Use `TextEditor` to display a editable and expandable form control.
+///
+/// ```swift
+/// TextEditor(name: "Lorem", prompt: "Lorem ipsum") {
+/// }
+/// ```
public struct TextEditor: View, Modifiable, Identifiable {
internal var id: String?
@@ -225,7 +283,7 @@ public struct TextEditor: View, Modifiable, Identifiable {
internal let name: String
/// The placeholder for the field value.
- internal let prompt: String?
+ internal let prompt: PromptType?
/// The number of lines.
internal var rows: Int = 3
@@ -239,11 +297,31 @@ public struct TextEditor: View, Modifiable, Identifiable {
/// The events of the editor.
internal var events: [String]?
- /// Creates a text editor.
+ /// Create a text editor.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The prompt to guide the user.
+ /// - value: The value to edit within the field.
+ @_disfavoredOverload
public init(name: String, prompt: String? = nil, @ContentBuilder content: () -> [String]) {
self.name = name
- self.prompt = prompt
+ self.prompt = prompt.map(PromptType.string(_:))
+ self.content = content()
+ self.classes = ["texteditor"]
+ }
+
+ /// Create a text editor.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The key of the localized string to guide the user.
+ /// - value: The value to edit within the field.
+ public init(name: String, prompt: LocalizedStringKey? = nil, @ContentBuilder content: () -> [String]) {
+
+ self.name = name
+ self.prompt = prompt.map(PromptType.value(_:))
self.content = content()
self.classes = ["texteditor"]
}
@@ -391,13 +469,24 @@ public struct Picker: View, Modifiable, Identifiable {
}
}
-/// A component that displays a form control
+/// A view that represents a check field.
+///
+/// Use `CheckField` to present a list of options, where multiple options can be selected.
+///
+/// ```swift
+/// Picker(name: "lorem", selection: "ipsum") {
+/// CheckField(value: "ipsum") {
+/// "Lorem ipsum"
+/// }
+/// .tag("ipsum")
+/// }
+/// ```
public struct CheckField: View, Modifiable, Selectable, Identifiable {
- /// The identifer for the label.
+ /// The identifer of the field.
internal var id: String?
- /// The identifier for the field.
+ /// The name of the field.
internal var name: String?
/// The content of the field.
@@ -407,20 +496,37 @@ public struct CheckField: View, Modifiable, Selectable, Identifiable {
internal var isSelected: Bool
/// The content of the field.
- internal var content: String
+ internal var content: Content
/// The classes of the field.
internal var classes: [String]
- /// Creates a check field.
+ /// Create a check field.
+ ///
+ /// - Parameters:
+ /// - value: The current value of the field.
+ /// - content: The label content for the field.
public init(value: String, content: () -> String) {
-
+
self.value = value
self.isSelected = false
self.content = content()
self.classes = ["checkfield"]
}
+ /// Create a check field.
+ ///
+ /// - Parameters:
+ /// - localizedStringKey: The key of the localized string used as the label.
+ /// - value: The current value of the field.
+ public init(_ localizedStringKey: LocalizedStringKey, value: String) {
+
+ self.value = value
+ self.isSelected = false
+ self.content = [LocalizedString(key: localizedStringKey)]
+ self.classes = ["checkfield"]
+ }
+
public var body: Content {
Division {
Input()
@@ -517,13 +623,24 @@ extension CheckField: ViewModifier {
}
}
-/// A component that displays
+/// A view that represents a radio select.
+///
+/// Use `RadioSelect` to present a list of options, where only one option can be selected.
+///
+/// ```swift
+/// Picker(name: "lorem", selection: "ipsum") {
+/// RadioSelect(value: "ipsum") {
+/// "Lorem ipsum"
+/// }
+/// .tag("ipsum")
+/// }
+/// ```
public struct RadioSelect: View, Modifiable, Selectable, Identifiable {
- /// The identifier for the label.
+ /// The identifier of the select.
internal var id: String?
- /// The identifier of the select.
+ /// The name of the select.
internal var name: String?
/// The content of the select.
@@ -533,12 +650,16 @@ public struct RadioSelect: View, Modifiable, Selectable, Identifiable {
internal var isSelected: Bool
/// The content of the select.
- internal var content: String
+ internal var content: Content
/// The classes of the select.
internal var classes: [String]
- /// Creates a radio select.
+ /// Create a radio select.
+ ///
+ /// - Parameters:
+ /// - value: The current value of the select.
+ /// - content: The label content for the select.
public init(value: String, content: () -> String) {
self.value = value
@@ -547,6 +668,19 @@ public struct RadioSelect: View, Modifiable, Selectable, Identifiable {
self.classes = ["radioselect"]
}
+ /// Create a radio select.
+ ///
+ /// - Parameters:
+ /// - localizedStringKey: The key of the localized string used as the label.
+ /// - value: The current value of the select.
+ public init(_ localizedStringKey: LocalizedStringKey, value: String) {
+
+ self.value = value
+ self.isSelected = false
+ self.content = [LocalizedString(key: localizedStringKey)]
+ self.classes = ["radioselect"]
+ }
+
public var body: Content {
Division {
Input()
@@ -643,17 +777,30 @@ extension RadioSelect: ViewModifier {
}
}
-/// A component that displays
+/// A view that represents a selectfield.
+///
+/// Use `SelectField` to present a list of options.
+///
+/// ```swift
+/// SelectField(name: "lorem", selection: "ipsum") {
+/// RadioSelect(value: "ipsum") {
+/// "Lorem ipsum"
+/// }
+/// .tag("ipsum")
+/// }
+/// ```
public struct SelectField: View, Modifiable, Identifiable {
+ /// The identifier of the field.
internal var id: String?
- /// The identifier of the field.
+ /// The name of the field.
internal let name: String
/// The placeholder for the field value.
- internal let prompt: String?
+ internal let prompt: PromptType?
+ /// The selected value of the available options.
internal let selection: String?
/// The content of the field.
@@ -665,21 +812,67 @@ public struct SelectField: View, Modifiable, Identifiable {
/// The events of the field.
internal var events: [String]?
- /// Creates a select field.
+ /// Create a select field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The prompt to guide the user.
+ /// - selection: The option to preselect.
+ /// - content: The options to choose from.
+ @_disfavoredOverload
public init(name: String, prompt: String? = nil, selection: String? = nil, @ContentBuilder content: () -> [RadioSelect]) {
self.name = name
- self.prompt = prompt
+ self.prompt = prompt.map(PromptType.string(_:))
self.selection = selection
self.content = content()
self.classes = ["selectfield"]
}
- /// Creates a select field.
+ /// Create a select field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The key of the localized string to guide the user.
+ /// - selection: The option to preselect.
+ /// - content: The options to choose from.
+ public init(name: String, prompt: LocalizedStringKey? = nil, selection: String? = nil, @ContentBuilder content: () -> [RadioSelect]) {
+
+ self.name = name
+ self.prompt = prompt.map(PromptType.value(_:))
+ self.selection = selection
+ self.content = content()
+ self.classes = ["selectfield"]
+ }
+
+ /// Create a select field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The prompt to guide the user.
+ /// - selection: The option to preselect.
+ /// - content: The options to choose from.
+ @_disfavoredOverload
public init(name: String, prompt: String? = nil, selection: String? = nil, @ContentBuilder content: () -> [CheckField]) {
self.name = name
- self.prompt = prompt
+ self.prompt = prompt.map(PromptType.string(_:))
+ self.selection = selection
+ self.content = content()
+ self.classes = ["selectfield"]
+ }
+
+ /// Create a select field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The prompt to guide the user.
+ /// - selection: The option to preselect.
+ /// - content: The options to choose from.
+ public init(name: String, prompt: LocalizedStringKey? = nil, selection: String? = nil, @ContentBuilder content: () -> [CheckField]) {
+
+ self.name = name
+ self.prompt = prompt.map(PromptType.value(_:))
self.selection = selection
self.content = content()
self.classes = ["selectfield"]
@@ -780,16 +973,23 @@ extension SelectField: ViewModifier {
}
}
-/// A component that displays
+/// A view that represents a secure field.
+///
+/// Use `SecureField` to enter sensitive data in a secure way.
+///
+/// ```swift
+/// SecureField(name: "lorem", prompt: "Lorem ipsum")
+/// ```
public struct SecureField: View, Modifiable, Identifiable {
+ /// The identifer of the field.
internal var id: String?
- /// The identifier of the field.
+ /// The name of the field.
internal let name: String
/// The placeholder for the field value.
- internal let prompt: String?
+ internal let prompt: PromptType?
/// The content of the field.
internal let value: String?
@@ -800,11 +1000,31 @@ public struct SecureField: View, Modifiable, Identifiable {
/// The events of the field.
internal var events: [String]?
- /// Creates a password field.
+ /// Create a secure field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The prompt to guide the user.
+ /// - content: The text content to edit within the field.
+ @_disfavoredOverload
public init(name: String, prompt: String? = nil, value: String? = nil) {
self.name = name
- self.prompt = prompt
+ self.prompt = prompt.map(PromptType.string(_:))
+ self.value = value
+ self.classes = ["securefield"]
+ }
+
+ /// Create a secure field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The key of the localized string to guide the user.
+ /// - content: The text content to edit within the field.
+ public init(name: String, prompt: LocalizedStringKey? = nil, value: String? = nil) {
+
+ self.name = name
+ self.prompt = prompt.map(PromptType.value(_:))
self.value = value
self.classes = ["securefield"]
}
@@ -1188,16 +1408,23 @@ extension DatePicker: ViewModifier {
}
}
-/// A component that displays
+/// A view that represents a search field.
+///
+/// Use `SearchField` to find information in content.
+///
+/// ```swift
+/// SearchField(name: "lorem", prompt: "Lorem ipsum")
+/// ```
public struct SearchField: View, Modifiable, Identifiable {
+ /// The identifier of the field.
internal var id: String?
- /// The identifier of the search field.
+ /// The name of the field.
internal let name: String
/// The placeholder for the field value.
- internal let prompt: String?
+ internal let prompt: PromptType?
/// The content of the field.
internal let value: String?
@@ -1208,12 +1435,32 @@ public struct SearchField: View, Modifiable, Identifiable {
/// The events of the field.
internal var events: [String]?
- /// Creates a search field.
+ /// Create a search field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The prompt to guide the user.
+ /// - value: The value to edit within the field.
+ @_disfavoredOverload
public init(name: String, prompt: String? = nil, value: String? = nil) {
self.name = name
- self.prompt = prompt
self.value = value
+ self.prompt = prompt.map(PromptType.string(_:))
+ self.classes = ["searchfield"]
+ }
+
+ /// Create a search field.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The key of the localized string to guide the user.
+ /// - value: The value to edit within the field.
+ public init(name: String, prompt: LocalizedStringKey? = nil, value: String? = nil) {
+
+ self.name = name
+ self.value = value
+ self.prompt = prompt.map(PromptType.value(_:))
self.classes = ["searchfield"]
}
@@ -1366,16 +1613,25 @@ public struct Progress: View, Modifiable, Identifiable {
}
}
-/// A component to edit and format text content.
+/// A view that represents a text pad.
+///
+/// Use `TextPad` to edit and format text content.
+///
+/// ```swift
+/// TextPad(name: "lorem", prompt: "Lorem ipsum") {
+/// "Lorem ipsum..."
+/// }
+/// ```
public struct TextPad: View, Modifiable, Identifiable {
+ /// The identifier of the textpad.
internal var id: String?
- /// The identifier of the textpad.
+ /// The name of the textpad.
internal let name: String
/// The placeholder for the field value.
- internal let prompt: String?
+ internal let prompt: PromptType?
/// The number of lines.
internal var rows: Int = 3
@@ -1386,11 +1642,31 @@ public struct TextPad: View, Modifiable, Identifiable {
/// The classes of the textpad.
internal var classes: [String]
- /// Creates a textpad
+ /// Create a textpad.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The prompt to guide the user.
+ /// - content: The text content to edit within the field.
+ @_disfavoredOverload
public init(name: String, prompt: String? = nil, @ContentBuilder content: () -> [String]) {
self.name = name
- self.prompt = prompt
+ self.prompt = prompt.map(PromptType.string(_:))
+ self.content = content()
+ self.classes = ["textpad"]
+ }
+
+ /// Create a textpad.
+ ///
+ /// - Parameters:
+ /// - name: The name to assign to the field.
+ /// - prompt: The key of the localized string to guide the user.
+ /// - content: The text content to edit within the field.
+ public init(name: String, prompt: LocalizedStringKey? = nil, @ContentBuilder content: () -> [String]) {
+
+ self.name = name
+ self.prompt = prompt.map(PromptType.value(_:))
self.content = content()
self.classes = ["textpad"]
}
diff --git a/Sources/HTMLKitComponents/Components/Link.swift b/Sources/HTMLKitComponents/Components/Link.swift
index ce1cab00..86d67bbd 100644
--- a/Sources/HTMLKitComponents/Components/Link.swift
+++ b/Sources/HTMLKitComponents/Components/Link.swift
@@ -6,12 +6,21 @@
import HTMLKit
import Foundation
-/// A component that navigates to an target.
+/// A view that represents a text link.
+///
+/// Use `Link` to navigate to a target.
+///
+/// ```swift
+/// Link(destination: "https://..") {
+/// "Lorem ipsum"
+/// }
+/// ```
public struct Link: View, Modifiable, Identifiable {
+ /// The unique identifier of the link.
internal var id: String?
- /// The target for the destination
+ /// The target behaviour for the destination
internal let target: HTMLKit.Values.Target
/// The url path of the target.
@@ -26,7 +35,12 @@ public struct Link: View, Modifiable, Identifiable {
/// The events of the link.
internal var events: [String]?
- /// Creates a link.
+ /// Create a link.
+ ///
+ /// - Parameters:
+ /// - destination: The url of the target to navigate to.
+ /// - target: The behaviour that determines how to open the target.
+ /// - content: The content displayed as the label.
public init(destination: String, target: HTMLKit.Values.Target = .current, @ContentBuilder content: () -> [Content]) {
self.destination = destination
@@ -35,7 +49,12 @@ public struct Link: View, Modifiable, Identifiable {
self.classes = ["link"]
}
- /// Creates a link.
+ /// Create a link.
+ ///
+ /// - Parameters:
+ /// - destination: The url of the target to navigate to.
+ /// - target: The behaviour that determines how to open the target.
+ /// - content: The content displayed as the label.
public init(destination: URL, target: HTMLKit.Values.Target = .current, @ContentBuilder content: () -> [Content]) {
self.destination = destination.absoluteString
diff --git a/Sources/HTMLKitComponents/Extensions/Components+Input.swift b/Sources/HTMLKitComponents/Extensions/Components+Input.swift
new file mode 100644
index 00000000..ef432931
--- /dev/null
+++ b/Sources/HTMLKitComponents/Extensions/Components+Input.swift
@@ -0,0 +1,29 @@
+import HTMLKit
+
+extension HTMLKit.Input {
+
+ internal func placeholder(_ value: PromptType) -> HTMLKit.Input {
+
+ switch value {
+ case .string(let string):
+ return self.placeholder(string)
+
+ case .value(let value):
+ return self.placeholder(value)
+ }
+ }
+}
+
+extension HTMLKit.TextArea {
+
+ internal func placeholder(_ value: PromptType) -> HTMLKit.TextArea {
+
+ switch value {
+ case .string(let string):
+ return self.placeholder(string)
+
+ case .value(let value):
+ return self.placeholder(value)
+ }
+ }
+}
diff --git a/Sources/HTMLKitComponents/Primitives/DynamicType.swift b/Sources/HTMLKitComponents/Primitives/DynamicType.swift
index dadd7cd2..c08cf60e 100644
--- a/Sources/HTMLKitComponents/Primitives/DynamicType.swift
+++ b/Sources/HTMLKitComponents/Primitives/DynamicType.swift
@@ -5,3 +5,13 @@ public enum DynamicType {
case value(EnvironmentValue)
case string(String)
}
+
+/// An enum that represents a dynamic prompt type.
+internal enum PromptType {
+
+ /// Holds a key for the localized string.
+ case value(LocalizedStringKey)
+
+ /// Holds a string.
+ case string(String)
+}
diff --git a/Tests/HTMLKitComponentsTests/Localization/fr/web.strings b/Tests/HTMLKitComponentsTests/Localization/fr/web.strings
index 82199495..ef2368b3 100644
--- a/Tests/HTMLKitComponentsTests/Localization/fr/web.strings
+++ b/Tests/HTMLKitComponentsTests/Localization/fr/web.strings
@@ -1,2 +1,8 @@
/* A button label. */
"button.submit" = "Envoyer le formulaire";
+
+"Password" = "Mot de passe";
+
+"Forgot password?" = "Mot de passe oublié?";
+
+"Create" = "Créer";
diff --git a/Tests/HTMLKitComponentsTests/LocalizationTests.swift b/Tests/HTMLKitComponentsTests/LocalizationTests.swift
index d7209f9b..629fb6d1 100644
--- a/Tests/HTMLKitComponentsTests/LocalizationTests.swift
+++ b/Tests/HTMLKitComponentsTests/LocalizationTests.swift
@@ -31,6 +31,116 @@ final class LocalizationTests: XCTestCase {
"""
)
}
+
+ func testFieldLabelLocalization() throws {
+
+ let view = TestView {
+ FieldLabel("Password", for: "password")
+ }
+
+ XCTAssertEqual(try renderer!.render(view: view),
+ """
+
+ """
+ )
+ }
+
+ func testDisclosureLocalization() throws {
+
+ let view = TestView {
+ Disclosure("Forgot password?") {
+ }
+ }
+
+ XCTAssertEqual(try renderer!.render(view: view),
+ """
+