113 lines
2.7 KiB
Swift
113 lines
2.7 KiB
Swift
import Elementary
|
|
|
|
/// A labelled text field, with its hint or — tied to it for assistive technology — what is wrong with it.
|
|
struct TextField: HTML {
|
|
|
|
// MARK: Properties
|
|
|
|
let name: String
|
|
let title: String
|
|
var value: String = ""
|
|
var placeholder: String = ""
|
|
var hint: String?
|
|
var problem: String?
|
|
var isWide = false
|
|
var maxLength: Int?
|
|
|
|
// MARK: Computed
|
|
|
|
var body: some HTML {
|
|
div(.class(isWide ? "field field--wide" : "field")) {
|
|
label(
|
|
.class("field__label"),
|
|
.for(name)
|
|
) {
|
|
title
|
|
}
|
|
input(
|
|
.class("input"),
|
|
.id(name),
|
|
.type(.text),
|
|
.name(name),
|
|
.value(value),
|
|
.placeholder(placeholder)
|
|
)
|
|
.attributes(.custom(name: "maxlength", value: "\(maxLength ?? 0)"), when: maxLength != nil)
|
|
.attributes(
|
|
.custom(name: "aria-invalid", value: "true"),
|
|
.custom(name: "aria-describedby", value: "\(name)-error"),
|
|
when: problem != nil
|
|
)
|
|
FieldNote(name: name, hint: hint, problem: problem)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/// A labelled select, showing the chosen option.
|
|
struct SelectField: HTML {
|
|
|
|
// MARK: Properties
|
|
|
|
let name: String
|
|
let title: String
|
|
let options: [(value: String, label: String)]
|
|
var selected: String?
|
|
var problem: String?
|
|
|
|
// MARK: Computed
|
|
|
|
var body: some HTML {
|
|
div(.class("field")) {
|
|
label(
|
|
.class("field__label"),
|
|
.for(name)
|
|
) {
|
|
title
|
|
}
|
|
select(
|
|
.class("select select--block"),
|
|
.id(name),
|
|
.name(name)
|
|
) {
|
|
ForEach(options) { option in
|
|
Elementary.option(.value(option.value)) {
|
|
option.label
|
|
}
|
|
.attributes(.selected, when: option.value == selected)
|
|
}
|
|
}
|
|
FieldNote(name: name, hint: nil, problem: problem)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/// What is wrong with a field, under it; or, when nothing is, its hint.
|
|
struct FieldNote: HTML {
|
|
|
|
// MARK: Properties
|
|
|
|
let name: String
|
|
let hint: String?
|
|
let problem: String?
|
|
|
|
// MARK: Computed
|
|
|
|
var body: some HTML {
|
|
if let problem {
|
|
p(
|
|
.class("field__error"),
|
|
.id("\(name)-error")
|
|
) {
|
|
problem
|
|
}
|
|
} else if let hint {
|
|
p(.class("field__hint")) {
|
|
hint
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|