Skip to content

Commit 7212a56

Browse files
authored
chore: move bindings code (#10772)
* move bindings to separate file * tidy up * errrr this code is confusing as hell but it works and the tests pass. fix it another day --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 468ecda commit 7212a56

File tree

12 files changed

+930
-850
lines changed

12 files changed

+930
-850
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { DEV } from 'esm-env';
2+
import { render_effect } from '../../reactivity/effects.js';
3+
import { stringify } from '../../render.js';
4+
5+
/**
6+
* @param {HTMLInputElement} input
7+
* @param {() => unknown} get_value
8+
* @param {(value: unknown) => void} update
9+
* @returns {void}
10+
*/
11+
export function bind_value(input, get_value, update) {
12+
input.addEventListener('input', () => {
13+
if (DEV && input.type === 'checkbox') {
14+
throw new Error(
15+
'Using bind:value together with a checkbox input is not allowed. Use bind:checked instead'
16+
);
17+
}
18+
19+
update(is_numberlike_input(input) ? to_number(input.value) : input.value);
20+
});
21+
22+
render_effect(() => {
23+
if (DEV && input.type === 'checkbox') {
24+
throw new Error(
25+
'Using bind:value together with a checkbox input is not allowed. Use bind:checked instead'
26+
);
27+
}
28+
29+
var value = get_value();
30+
31+
// @ts-ignore
32+
input.__value = value;
33+
34+
if (is_numberlike_input(input) && value === to_number(input.value)) {
35+
// handles 0 vs 00 case (see https://github.com/sveltejs/svelte/issues/9959)
36+
return;
37+
}
38+
39+
if (input.type === 'date' && !value && !input.value) {
40+
// Handles the case where a temporarily invalid date is set (while typing, for example with a leading 0 for the day)
41+
// and prevents this state from clearing the other parts of the date input (see https://github.com/sveltejs/svelte/issues/7897)
42+
return;
43+
}
44+
45+
input.value = stringify(value);
46+
});
47+
}
48+
49+
/**
50+
* @param {Array<HTMLInputElement>} inputs
51+
* @param {null | [number]} group_index
52+
* @param {HTMLInputElement} input
53+
* @param {() => unknown} get_value
54+
* @param {(value: unknown) => void} update
55+
* @returns {void}
56+
*/
57+
export function bind_group(inputs, group_index, input, get_value, update) {
58+
var is_checkbox = input.getAttribute('type') === 'checkbox';
59+
var binding_group = inputs;
60+
61+
if (group_index !== null) {
62+
for (var index of group_index) {
63+
var group = binding_group;
64+
// @ts-ignore
65+
binding_group = group[index];
66+
if (binding_group === undefined) {
67+
// @ts-ignore
68+
binding_group = group[index] = [];
69+
}
70+
}
71+
}
72+
73+
binding_group.push(input);
74+
75+
input.addEventListener('change', () => {
76+
// @ts-ignore
77+
var value = input.__value;
78+
79+
if (is_checkbox) {
80+
value = get_binding_group_value(binding_group, value, input.checked);
81+
}
82+
83+
update(value);
84+
});
85+
86+
render_effect(() => {
87+
var value = get_value();
88+
89+
if (is_checkbox) {
90+
value = value || [];
91+
// @ts-ignore
92+
input.checked = value.includes(input.__value);
93+
} else {
94+
// @ts-ignore
95+
input.checked = input.__value === value;
96+
}
97+
});
98+
99+
render_effect(() => {
100+
return () => {
101+
var index = binding_group.indexOf(input);
102+
103+
if (index !== -1) {
104+
binding_group.splice(index, 1);
105+
}
106+
};
107+
});
108+
}
109+
110+
/**
111+
* @param {HTMLInputElement} input
112+
* @param {() => unknown} get_value
113+
* @param {(value: unknown) => void} update
114+
* @returns {void}
115+
*/
116+
export function bind_checked(input, get_value, update) {
117+
input.addEventListener('change', () => {
118+
var value = input.checked;
119+
update(value);
120+
});
121+
122+
// eslint-disable-next-line eqeqeq
123+
if (get_value() == undefined) {
124+
update(false);
125+
}
126+
127+
render_effect(() => {
128+
var value = get_value();
129+
input.checked = Boolean(value);
130+
});
131+
}
132+
133+
/**
134+
* @template V
135+
* @param {Array<HTMLInputElement>} group
136+
* @param {V} __value
137+
* @param {boolean} checked
138+
* @returns {V[]}
139+
*/
140+
function get_binding_group_value(group, __value, checked) {
141+
var value = new Set();
142+
143+
for (var i = 0; i < group.length; i += 1) {
144+
if (group[i].checked) {
145+
// @ts-ignore
146+
value.add(group[i].__value);
147+
}
148+
}
149+
150+
if (!checked) {
151+
value.delete(__value);
152+
}
153+
154+
return Array.from(value);
155+
}
156+
157+
/**
158+
* @param {HTMLInputElement} input
159+
*/
160+
function is_numberlike_input(input) {
161+
var type = input.type;
162+
return type === 'number' || type === 'range';
163+
}
164+
165+
/**
166+
* @param {string} value
167+
*/
168+
function to_number(value) {
169+
return value === '' ? null : +value;
170+
}

0 commit comments

Comments
 (0)