-
Notifications
You must be signed in to change notification settings - Fork 34
/
text.js
134 lines (126 loc) · 3.36 KB
/
text.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import {html} from "htl";
import {maybeWidth} from "./css.js";
import {maybeDatalist} from "./datalist.js";
import {checkValidity, dispatchInput, preventDefault} from "./event.js";
import {stringify} from "./format.js";
import {maybeLabel} from "./label.js";
export function createText(form, input, value, {
validate = checkValidity,
submit
} = {}, {
get = (input) => input.value,
set = (input, value) => input.value = stringify(value),
same = (input, value) => input.value === value,
after = (button) => input.after(button)
} = {}) {
submit = submit === true ? "Submit" : submit || null;
const button = submit ? html`<button type=submit disabled>${submit}` : null;
if (submit) after(button);
set(input, value);
value = validate(input) ? get(input) : undefined;
form.addEventListener("submit", onsubmit);
input.oninput = oninput;
function update() {
if (validate(input)) {
value = get(input);
return true;
}
}
function onsubmit(event) {
preventDefault(event);
if (submit) {
if (update()) {
button.disabled = true;
dispatchInput(event);
} else {
input.reportValidity();
}
}
}
function oninput(event) {
if (submit) {
button.disabled = same(input, value);
event.stopPropagation();
} else if (!update()) {
event.stopPropagation();
}
}
return Object.defineProperty(form, "value", {
get() {
return value;
},
set(v) {
set(input, v);
update();
}
});
}
export function text({
label,
value = "",
type = "text",
placeholder,
pattern,
spellcheck,
autocomplete,
autocapitalize,
min,
max,
minlength,
maxlength,
required = minlength > 0,
datalist,
readonly,
disabled,
width,
...options
} = {}) {
const [list, listId] = maybeDatalist(datalist);
const input = html`<input
type=${type}
name=text
list=${listId}
readonly=${readonly}
disabled=${disabled}
required=${required}
min=${min}
max=${max}
minlength=${minlength}
maxlength=${maxlength}
pattern=${pattern}
spellcheck=${truefalse(spellcheck)}
autocomplete=${onoff(autocomplete)}
autocapitalize=${onoff(autocapitalize)}
placeholder=${placeholder}
>`;
const form = html`<form class=__ns__ style=${maybeWidth(width)}>
${maybeLabel(label, input)}<div class=__ns__-input>
${input}
</div>${list}
</form>`;
return createText(form, input, value, options);
}
export function email(options) {
return text({...options, type: "email"});
}
export function tel(options) {
return text({...options, type: "tel"});
}
export function url(options) {
return text({...options, type: "url"});
}
export function password(options) {
return text({...options, type: "password"});
}
// Hypertext Literal will normally drop an attribute if its value is exactly
// false, but for these attributes (e.g., spellcheck), we actually want the
// false to be stringified as the attribute value.
export function truefalse(value) {
return value == null ? null : `${value}`;
}
// For boolean attributes that support “on” and “off”, this maps true to “on”
// and false to “off”. Any other value (if not nullish) is assumed to be a
// string, such as autocapitalize=sentences.
export function onoff(value) {
return value == null ? null : `${value === false ? "off" : value === true ? "on" : value}`;
}