@targoninc/jess-components 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1006 -0
- package/dist/src/Components.d.ts +17 -0
- package/dist/src/Types.d.ts +86 -0
- package/package.json +29 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,1006 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// node_modules/@targoninc/jess/dist/index.js
|
|
3
|
+
class Signal {
|
|
4
|
+
_callbacks = [];
|
|
5
|
+
_value;
|
|
6
|
+
_values = {};
|
|
7
|
+
constructor(initialValue, updateCallback = () => {}) {
|
|
8
|
+
this._value = initialValue;
|
|
9
|
+
this._values = {};
|
|
10
|
+
this._callbacks.push(updateCallback);
|
|
11
|
+
}
|
|
12
|
+
boolValues(assignments = {}) {
|
|
13
|
+
for (let key in assignments) {
|
|
14
|
+
if (assignments[key]) {
|
|
15
|
+
this._values[key] = signal(this._value ? assignments[key].onTrue : assignments[key].onFalse);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
this.subscribe((newValue) => {
|
|
19
|
+
for (let key in assignments) {
|
|
20
|
+
if (assignments[key] && this._values[key]) {
|
|
21
|
+
this._values[key].value = newValue ? assignments[key].onTrue : assignments[key].onFalse;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return this._values;
|
|
26
|
+
}
|
|
27
|
+
unsubscribeAll() {
|
|
28
|
+
this._callbacks = [];
|
|
29
|
+
}
|
|
30
|
+
subscribe(callback) {
|
|
31
|
+
this._callbacks.push(callback);
|
|
32
|
+
}
|
|
33
|
+
unsubscribe(callback) {
|
|
34
|
+
const index = this._callbacks.indexOf(callback);
|
|
35
|
+
if (index >= 0) {
|
|
36
|
+
this._callbacks.splice(index, 1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
get onUpdate() {
|
|
40
|
+
return this._callbacks;
|
|
41
|
+
}
|
|
42
|
+
set onUpdate(callback) {
|
|
43
|
+
this._callbacks.push(callback);
|
|
44
|
+
}
|
|
45
|
+
get value() {
|
|
46
|
+
return this._value;
|
|
47
|
+
}
|
|
48
|
+
set value(value) {
|
|
49
|
+
const changed = this._value !== value;
|
|
50
|
+
this._value = value;
|
|
51
|
+
this._callbacks.forEach((callback) => callback(value, changed));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function signal(initialValue) {
|
|
55
|
+
return new Signal(initialValue);
|
|
56
|
+
}
|
|
57
|
+
function compute(valueFunction, ...signals) {
|
|
58
|
+
const getValues = () => signals.map((s) => s.value);
|
|
59
|
+
let out = signal(valueFunction(...getValues()));
|
|
60
|
+
for (const sig of signals) {
|
|
61
|
+
sig.subscribe((_, changed) => {
|
|
62
|
+
if (!changed) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
out.value = valueFunction(...getValues());
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
function isSignal(obj) {
|
|
71
|
+
return obj?.constructor === Signal;
|
|
72
|
+
}
|
|
73
|
+
function asSignal(obj) {
|
|
74
|
+
return obj;
|
|
75
|
+
}
|
|
76
|
+
function create(tag) {
|
|
77
|
+
return new DomNode(tag);
|
|
78
|
+
}
|
|
79
|
+
function nullElement() {
|
|
80
|
+
return create("div").styles("display", "none").build();
|
|
81
|
+
}
|
|
82
|
+
function when(condition, element, inverted = false) {
|
|
83
|
+
function getElement() {
|
|
84
|
+
if (element.constructor === Function) {
|
|
85
|
+
return element();
|
|
86
|
+
}
|
|
87
|
+
return element;
|
|
88
|
+
}
|
|
89
|
+
if (condition && condition.constructor === Signal) {
|
|
90
|
+
const state = signal(condition.value ? inverted ? nullElement() : getElement() : inverted ? getElement() : nullElement());
|
|
91
|
+
condition.subscribe((newValue) => {
|
|
92
|
+
if (newValue) {
|
|
93
|
+
state.value = inverted ? nullElement() : getElement();
|
|
94
|
+
} else {
|
|
95
|
+
state.value = inverted ? getElement() : nullElement();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return state;
|
|
99
|
+
} else {
|
|
100
|
+
return condition ? inverted ? nullElement() : getElement() : inverted ? getElement() : nullElement();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function signalMap(arrayState, wrapper, callback, renderSequentially = false) {
|
|
104
|
+
if (!arrayState.subscribe) {
|
|
105
|
+
throw new Error("arrayState argument for signalMap is not a signal");
|
|
106
|
+
}
|
|
107
|
+
const update = (newValue) => {
|
|
108
|
+
if (!newValue) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const tmp = [...newValue].filter((t) => !!t);
|
|
112
|
+
const children = [];
|
|
113
|
+
if (renderSequentially) {
|
|
114
|
+
wrapper.overwriteChildren();
|
|
115
|
+
for (let i = 0;i < tmp.length; i++) {
|
|
116
|
+
wrapper.children(callback(tmp[i], i));
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
for (let i = 0;i < tmp.length; i++) {
|
|
120
|
+
children.push(callback(tmp[i], i));
|
|
121
|
+
}
|
|
122
|
+
wrapper.overwriteChildren(...children);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
arrayState.subscribe(update);
|
|
126
|
+
update(arrayState.value);
|
|
127
|
+
return wrapper.build();
|
|
128
|
+
}
|
|
129
|
+
function stack(message, debugInfo = {}) {
|
|
130
|
+
console.warn(message, { debugInfo }, new Error().stack);
|
|
131
|
+
}
|
|
132
|
+
function isValidElement(element) {
|
|
133
|
+
const validTypes = [HTMLElement, SVGElement];
|
|
134
|
+
return validTypes.some((type) => element instanceof type);
|
|
135
|
+
}
|
|
136
|
+
class DomNode {
|
|
137
|
+
_node;
|
|
138
|
+
svgTags = ["svg", "g", "circle", "ellipse", "line", "path", "polygon", "polyline", "rect", "text", "textPath", "tspan"];
|
|
139
|
+
constructor(tag) {
|
|
140
|
+
if (this.svgTags.includes(tag)) {
|
|
141
|
+
this._node = document.createElementNS("http://www.w3.org/2000/svg", tag);
|
|
142
|
+
} else {
|
|
143
|
+
this._node = document.createElement(tag);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
applyGenericConfig(config) {
|
|
147
|
+
return this.classes("jess", ...config.classes ?? []).attributes(...config.attributes ?? []).styles(...config.styles ?? []).id(config.id).css(config.css).title(config.title).role(config.role);
|
|
148
|
+
}
|
|
149
|
+
build() {
|
|
150
|
+
if (!isValidElement(this._node)) {
|
|
151
|
+
throw new Error("Invalid node type. Must be an HTMLElement or a subclass.");
|
|
152
|
+
}
|
|
153
|
+
return this._node;
|
|
154
|
+
}
|
|
155
|
+
wrapProperty(property, value) {
|
|
156
|
+
if (value && value.constructor === Signal) {
|
|
157
|
+
const sig = value;
|
|
158
|
+
this._node[property] = sig.value;
|
|
159
|
+
sig.subscribe((newValue) => {
|
|
160
|
+
this._node[property] = newValue;
|
|
161
|
+
});
|
|
162
|
+
} else {
|
|
163
|
+
if (value !== undefined && value !== null) {
|
|
164
|
+
this._node[property] = value;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
class(className) {
|
|
169
|
+
return this.classes(className);
|
|
170
|
+
}
|
|
171
|
+
classes(...classes) {
|
|
172
|
+
for (let cls of classes) {
|
|
173
|
+
if (cls && cls.constructor === Signal) {
|
|
174
|
+
const sig = cls;
|
|
175
|
+
let previousValue = sig.value;
|
|
176
|
+
this._node.classList.add(previousValue);
|
|
177
|
+
sig.subscribe((newValue) => {
|
|
178
|
+
this._node.classList.remove(previousValue);
|
|
179
|
+
this._node.classList.add(newValue);
|
|
180
|
+
previousValue = newValue;
|
|
181
|
+
});
|
|
182
|
+
} else {
|
|
183
|
+
this._node.classList.add(cls);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
188
|
+
attribute(key, value) {
|
|
189
|
+
return this.attributes(key, value);
|
|
190
|
+
}
|
|
191
|
+
attributes(...attributes) {
|
|
192
|
+
if (arguments.length % 2 === 0) {
|
|
193
|
+
for (let i = 0;i < arguments.length; i += 2) {
|
|
194
|
+
const key = arguments[i];
|
|
195
|
+
const value = arguments[i + 1];
|
|
196
|
+
if (value && value.constructor === Signal) {
|
|
197
|
+
this._node.setAttribute(key, value.value);
|
|
198
|
+
value.onUpdate = (newValue) => {
|
|
199
|
+
this._node.setAttribute(key, newValue);
|
|
200
|
+
};
|
|
201
|
+
} else {
|
|
202
|
+
this._node.setAttribute(key, value);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
throw new Error("Invalid number of arguments for attributes. Must be even. (key, value, key, value, ...)");
|
|
207
|
+
}
|
|
208
|
+
return this;
|
|
209
|
+
}
|
|
210
|
+
id(id) {
|
|
211
|
+
this.wrapProperty("id", id);
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
text(text) {
|
|
215
|
+
this.wrapProperty("innerText", text);
|
|
216
|
+
return this;
|
|
217
|
+
}
|
|
218
|
+
title(title) {
|
|
219
|
+
this.wrapProperty("title", title);
|
|
220
|
+
return this;
|
|
221
|
+
}
|
|
222
|
+
html(html) {
|
|
223
|
+
this.wrapProperty("innerHTML", html);
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
children(...children) {
|
|
227
|
+
for (let node of arguments) {
|
|
228
|
+
if (isValidElement(node)) {
|
|
229
|
+
this._node.appendChild(node);
|
|
230
|
+
} else if (node instanceof DomNode) {
|
|
231
|
+
this._node.appendChild(node.build());
|
|
232
|
+
} else if (node && node.constructor === Signal) {
|
|
233
|
+
node.subscribe((newValue) => {
|
|
234
|
+
if (isValidElement(newValue)) {
|
|
235
|
+
this._node.replaceChild(newValue, childNode);
|
|
236
|
+
childNode = newValue;
|
|
237
|
+
} else if (newValue.constructor === DomNode) {
|
|
238
|
+
this._node.replaceChild(newValue.build(), childNode);
|
|
239
|
+
childNode = newValue.build();
|
|
240
|
+
} else {
|
|
241
|
+
stack("Unexpected value for child. Must be an HTMLElement or a subclass.", newValue);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
let childNode = node.value;
|
|
245
|
+
if (!isValidElement(childNode)) {
|
|
246
|
+
childNode = nullElement();
|
|
247
|
+
}
|
|
248
|
+
this._node.appendChild(childNode);
|
|
249
|
+
} else if (node && node.constructor === Array) {
|
|
250
|
+
for (let childNode of node) {
|
|
251
|
+
this.children(childNode);
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
if (node) {
|
|
255
|
+
stack("Invalid node type. Must be an HTMLElement or a subclass.", node);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
overwriteChildren() {
|
|
262
|
+
this._node.innerHTML = "";
|
|
263
|
+
return this.children(...arguments);
|
|
264
|
+
}
|
|
265
|
+
child() {
|
|
266
|
+
return this.children(...arguments);
|
|
267
|
+
}
|
|
268
|
+
role(role) {
|
|
269
|
+
this.wrapProperty("role", role);
|
|
270
|
+
return this;
|
|
271
|
+
}
|
|
272
|
+
prefixedAttribute(prefix, key, value) {
|
|
273
|
+
return this.attributes(`${prefix}-${key}`, value);
|
|
274
|
+
}
|
|
275
|
+
aria(key, value) {
|
|
276
|
+
return this.prefixedAttribute("aria", key, value);
|
|
277
|
+
}
|
|
278
|
+
data(key, value) {
|
|
279
|
+
return this.prefixedAttribute("data", key, value);
|
|
280
|
+
}
|
|
281
|
+
onclick(callback) {
|
|
282
|
+
this._node.onclick = callback;
|
|
283
|
+
return this;
|
|
284
|
+
}
|
|
285
|
+
onauxclick(callback) {
|
|
286
|
+
this._node.onauxclick = callback;
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
ondblclick(callback) {
|
|
290
|
+
this._node.ondblclick = callback;
|
|
291
|
+
return this;
|
|
292
|
+
}
|
|
293
|
+
onchange(callback) {
|
|
294
|
+
this._node.onchange = callback;
|
|
295
|
+
return this;
|
|
296
|
+
}
|
|
297
|
+
oninput(callback) {
|
|
298
|
+
this._node.oninput = callback;
|
|
299
|
+
return this;
|
|
300
|
+
}
|
|
301
|
+
onkeydown(callback) {
|
|
302
|
+
this._node.onkeydown = callback;
|
|
303
|
+
return this;
|
|
304
|
+
}
|
|
305
|
+
onkeyup(callback) {
|
|
306
|
+
this._node.onkeyup = callback;
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
onmousedown(callback) {
|
|
310
|
+
this._node.onmousedown = callback;
|
|
311
|
+
return this;
|
|
312
|
+
}
|
|
313
|
+
onmouseup(callback) {
|
|
314
|
+
this._node.onmouseup = callback;
|
|
315
|
+
return this;
|
|
316
|
+
}
|
|
317
|
+
onmouseover(callback) {
|
|
318
|
+
this._node.onmouseover = callback;
|
|
319
|
+
return this;
|
|
320
|
+
}
|
|
321
|
+
onmouseout(callback) {
|
|
322
|
+
this._node.onmouseout = callback;
|
|
323
|
+
return this;
|
|
324
|
+
}
|
|
325
|
+
onmousemove(callback) {
|
|
326
|
+
this._node.onmousemove = callback;
|
|
327
|
+
return this;
|
|
328
|
+
}
|
|
329
|
+
onmouseenter(callback) {
|
|
330
|
+
this._node.onmouseenter = callback;
|
|
331
|
+
return this;
|
|
332
|
+
}
|
|
333
|
+
onmouseleave(callback) {
|
|
334
|
+
this._node.onmouseleave = callback;
|
|
335
|
+
return this;
|
|
336
|
+
}
|
|
337
|
+
oncontextmenu(callback) {
|
|
338
|
+
this._node.oncontextmenu = callback;
|
|
339
|
+
return this;
|
|
340
|
+
}
|
|
341
|
+
onwheel(callback) {
|
|
342
|
+
this._node.onwheel = callback;
|
|
343
|
+
return this;
|
|
344
|
+
}
|
|
345
|
+
ondrag(callback) {
|
|
346
|
+
this._node.ondrag = callback;
|
|
347
|
+
return this;
|
|
348
|
+
}
|
|
349
|
+
ondragend(callback) {
|
|
350
|
+
this._node.ondragend = callback;
|
|
351
|
+
return this;
|
|
352
|
+
}
|
|
353
|
+
ondragenter(callback) {
|
|
354
|
+
this._node.ondragenter = callback;
|
|
355
|
+
return this;
|
|
356
|
+
}
|
|
357
|
+
ondragstart(callback) {
|
|
358
|
+
this._node.ondragstart = callback;
|
|
359
|
+
return this;
|
|
360
|
+
}
|
|
361
|
+
ondragleave(callback) {
|
|
362
|
+
this._node.ondragleave = callback;
|
|
363
|
+
return this;
|
|
364
|
+
}
|
|
365
|
+
ondragover(callback) {
|
|
366
|
+
this._node.ondragover = callback;
|
|
367
|
+
return this;
|
|
368
|
+
}
|
|
369
|
+
ondrop(callback) {
|
|
370
|
+
this._node.ondrop = callback;
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
onscroll(callback) {
|
|
374
|
+
this._node.onscroll = callback;
|
|
375
|
+
return this;
|
|
376
|
+
}
|
|
377
|
+
onfocus(callback) {
|
|
378
|
+
this._node.onfocus = callback;
|
|
379
|
+
return this;
|
|
380
|
+
}
|
|
381
|
+
onblur(callback) {
|
|
382
|
+
this._node.onblur = callback;
|
|
383
|
+
return this;
|
|
384
|
+
}
|
|
385
|
+
onresize(callback) {
|
|
386
|
+
this._node.onresize = callback;
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
389
|
+
onselect(callback) {
|
|
390
|
+
this._node.onselect = callback;
|
|
391
|
+
return this;
|
|
392
|
+
}
|
|
393
|
+
onsubmit(callback) {
|
|
394
|
+
this._node.onsubmit = callback;
|
|
395
|
+
return this;
|
|
396
|
+
}
|
|
397
|
+
onreset(callback) {
|
|
398
|
+
this._node.onreset = callback;
|
|
399
|
+
return this;
|
|
400
|
+
}
|
|
401
|
+
onabort(callback) {
|
|
402
|
+
this._node.onabort = callback;
|
|
403
|
+
return this;
|
|
404
|
+
}
|
|
405
|
+
onerror(callback) {
|
|
406
|
+
this._node.onerror = callback;
|
|
407
|
+
return this;
|
|
408
|
+
}
|
|
409
|
+
oncanplay(callback) {
|
|
410
|
+
this._node.oncanplay = callback;
|
|
411
|
+
return this;
|
|
412
|
+
}
|
|
413
|
+
oncanplaythrough(callback) {
|
|
414
|
+
this._node.oncanplaythrough = callback;
|
|
415
|
+
return this;
|
|
416
|
+
}
|
|
417
|
+
ondurationchange(callback) {
|
|
418
|
+
this._node.ondurationchange = callback;
|
|
419
|
+
return this;
|
|
420
|
+
}
|
|
421
|
+
onemptied(callback) {
|
|
422
|
+
this._node.onemptied = callback;
|
|
423
|
+
return this;
|
|
424
|
+
}
|
|
425
|
+
onended(callback) {
|
|
426
|
+
this._node.onended = callback;
|
|
427
|
+
return this;
|
|
428
|
+
}
|
|
429
|
+
onloadeddata(callback) {
|
|
430
|
+
this._node.onloadeddata = callback;
|
|
431
|
+
return this;
|
|
432
|
+
}
|
|
433
|
+
onloadedmetadata(callback) {
|
|
434
|
+
this._node.onloadedmetadata = callback;
|
|
435
|
+
return this;
|
|
436
|
+
}
|
|
437
|
+
onloadstart(callback) {
|
|
438
|
+
this._node.onloadstart = callback;
|
|
439
|
+
return this;
|
|
440
|
+
}
|
|
441
|
+
onpause(callback) {
|
|
442
|
+
this._node.onpause = callback;
|
|
443
|
+
return this;
|
|
444
|
+
}
|
|
445
|
+
onplay(callback) {
|
|
446
|
+
this._node.onplay = callback;
|
|
447
|
+
return this;
|
|
448
|
+
}
|
|
449
|
+
onplaying(callback) {
|
|
450
|
+
this._node.onplaying = callback;
|
|
451
|
+
return this;
|
|
452
|
+
}
|
|
453
|
+
onprogress(callback) {
|
|
454
|
+
this._node.onprogress = callback;
|
|
455
|
+
return this;
|
|
456
|
+
}
|
|
457
|
+
onratechange(callback) {
|
|
458
|
+
this._node.onratechange = callback;
|
|
459
|
+
return this;
|
|
460
|
+
}
|
|
461
|
+
onseeked(callback) {
|
|
462
|
+
this._node.onseeked = callback;
|
|
463
|
+
return this;
|
|
464
|
+
}
|
|
465
|
+
onseeking(callback) {
|
|
466
|
+
this._node.onseeking = callback;
|
|
467
|
+
return this;
|
|
468
|
+
}
|
|
469
|
+
onstalled(callback) {
|
|
470
|
+
this._node.onstalled = callback;
|
|
471
|
+
return this;
|
|
472
|
+
}
|
|
473
|
+
onsuspend(callback) {
|
|
474
|
+
this._node.onsuspend = callback;
|
|
475
|
+
return this;
|
|
476
|
+
}
|
|
477
|
+
ontimeupdate(callback) {
|
|
478
|
+
this._node.ontimeupdate = callback;
|
|
479
|
+
return this;
|
|
480
|
+
}
|
|
481
|
+
onvolumechange(callback) {
|
|
482
|
+
this._node.onvolumechange = callback;
|
|
483
|
+
return this;
|
|
484
|
+
}
|
|
485
|
+
onwaiting(callback) {
|
|
486
|
+
this._node.onwaiting = callback;
|
|
487
|
+
return this;
|
|
488
|
+
}
|
|
489
|
+
oncopy(callback) {
|
|
490
|
+
this._node.oncopy = callback;
|
|
491
|
+
return this;
|
|
492
|
+
}
|
|
493
|
+
oncut(callback) {
|
|
494
|
+
this._node.oncut = callback;
|
|
495
|
+
return this;
|
|
496
|
+
}
|
|
497
|
+
onpaste(callback) {
|
|
498
|
+
this._node.onpaste = callback;
|
|
499
|
+
return this;
|
|
500
|
+
}
|
|
501
|
+
onanimationstart(callback) {
|
|
502
|
+
this._node.onanimationstart = callback;
|
|
503
|
+
return this;
|
|
504
|
+
}
|
|
505
|
+
onanimationend(callback) {
|
|
506
|
+
this._node.onanimationend = callback;
|
|
507
|
+
return this;
|
|
508
|
+
}
|
|
509
|
+
onanimationiteration(callback) {
|
|
510
|
+
this._node.onanimationiteration = callback;
|
|
511
|
+
return this;
|
|
512
|
+
}
|
|
513
|
+
ontransitionend(callback) {
|
|
514
|
+
this._node.ontransitionend = callback;
|
|
515
|
+
return this;
|
|
516
|
+
}
|
|
517
|
+
on(eventName, callback) {
|
|
518
|
+
this._node.addEventListener(eventName, callback);
|
|
519
|
+
return this;
|
|
520
|
+
}
|
|
521
|
+
open(open) {
|
|
522
|
+
this.wrapProperty("open", open);
|
|
523
|
+
return this;
|
|
524
|
+
}
|
|
525
|
+
src(src) {
|
|
526
|
+
this.wrapProperty("src", src);
|
|
527
|
+
return this;
|
|
528
|
+
}
|
|
529
|
+
alt(alt) {
|
|
530
|
+
this.wrapProperty("alt", alt);
|
|
531
|
+
return this;
|
|
532
|
+
}
|
|
533
|
+
css(css) {
|
|
534
|
+
if (!css) {
|
|
535
|
+
return this;
|
|
536
|
+
}
|
|
537
|
+
for (const [key, value] of Object.entries(css)) {
|
|
538
|
+
this.styles(key, value);
|
|
539
|
+
}
|
|
540
|
+
return this;
|
|
541
|
+
}
|
|
542
|
+
style(key, value) {
|
|
543
|
+
return this.styles(key, value);
|
|
544
|
+
}
|
|
545
|
+
styles(...styles) {
|
|
546
|
+
if (arguments.length % 2 === 0) {
|
|
547
|
+
for (let i = 0;i < arguments.length; i += 2) {
|
|
548
|
+
const key = arguments[i];
|
|
549
|
+
const value = arguments[i + 1];
|
|
550
|
+
if (key.constructor !== String) {
|
|
551
|
+
throw new Error("Invalid key type for styles. Must be a string.");
|
|
552
|
+
}
|
|
553
|
+
if (value && value.constructor === Signal) {
|
|
554
|
+
this._node.style[key] = value.value;
|
|
555
|
+
value.onUpdate = (newValue) => {
|
|
556
|
+
this._node.style[key] = newValue;
|
|
557
|
+
};
|
|
558
|
+
} else {
|
|
559
|
+
this._node.style[key] = value;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
} else {
|
|
563
|
+
throw new Error("Invalid number of arguments for styles. Must be even. (key, value, key, value, ...)");
|
|
564
|
+
}
|
|
565
|
+
return this;
|
|
566
|
+
}
|
|
567
|
+
width(width) {
|
|
568
|
+
this.wrapProperty("width", width);
|
|
569
|
+
return this;
|
|
570
|
+
}
|
|
571
|
+
height(height) {
|
|
572
|
+
this.wrapProperty("height", height);
|
|
573
|
+
return this;
|
|
574
|
+
}
|
|
575
|
+
type(type) {
|
|
576
|
+
this.wrapProperty("type", type);
|
|
577
|
+
return this;
|
|
578
|
+
}
|
|
579
|
+
name(name) {
|
|
580
|
+
this.wrapProperty("name", name);
|
|
581
|
+
return this;
|
|
582
|
+
}
|
|
583
|
+
value(value) {
|
|
584
|
+
this.wrapProperty("value", value);
|
|
585
|
+
return this;
|
|
586
|
+
}
|
|
587
|
+
placeholder(placeholder) {
|
|
588
|
+
this.wrapProperty("placeholder", placeholder);
|
|
589
|
+
return this;
|
|
590
|
+
}
|
|
591
|
+
for(forId) {
|
|
592
|
+
this.wrapProperty("for", forId);
|
|
593
|
+
return this;
|
|
594
|
+
}
|
|
595
|
+
checked(checked) {
|
|
596
|
+
this.wrapProperty("checked", checked);
|
|
597
|
+
return this;
|
|
598
|
+
}
|
|
599
|
+
disabled(disabled) {
|
|
600
|
+
this.wrapProperty("disabled", disabled);
|
|
601
|
+
return this;
|
|
602
|
+
}
|
|
603
|
+
selected(selected) {
|
|
604
|
+
this.wrapProperty("selected", selected);
|
|
605
|
+
return this;
|
|
606
|
+
}
|
|
607
|
+
href(href) {
|
|
608
|
+
this.wrapProperty("href", href);
|
|
609
|
+
return this;
|
|
610
|
+
}
|
|
611
|
+
target(target) {
|
|
612
|
+
this.wrapProperty("target", target);
|
|
613
|
+
return this;
|
|
614
|
+
}
|
|
615
|
+
rel(rel) {
|
|
616
|
+
this.wrapProperty("rel", rel);
|
|
617
|
+
return this;
|
|
618
|
+
}
|
|
619
|
+
required(required) {
|
|
620
|
+
this.wrapProperty("required", required);
|
|
621
|
+
return this;
|
|
622
|
+
}
|
|
623
|
+
multiple(multiple) {
|
|
624
|
+
this.wrapProperty("multiple", multiple);
|
|
625
|
+
return this;
|
|
626
|
+
}
|
|
627
|
+
accept(accept) {
|
|
628
|
+
this.wrapProperty("accept", accept);
|
|
629
|
+
return this;
|
|
630
|
+
}
|
|
631
|
+
acceptCharset(acceptCharset) {
|
|
632
|
+
this.wrapProperty("acceptCharset", acceptCharset);
|
|
633
|
+
return this;
|
|
634
|
+
}
|
|
635
|
+
action(action) {
|
|
636
|
+
this.wrapProperty("action", action);
|
|
637
|
+
return this;
|
|
638
|
+
}
|
|
639
|
+
autocomplete(autocomplete) {
|
|
640
|
+
this.wrapProperty("autocomplete", autocomplete);
|
|
641
|
+
return this;
|
|
642
|
+
}
|
|
643
|
+
enctype(enctype) {
|
|
644
|
+
this.wrapProperty("enctype", enctype);
|
|
645
|
+
return this;
|
|
646
|
+
}
|
|
647
|
+
method(method) {
|
|
648
|
+
this.wrapProperty("method", method);
|
|
649
|
+
return this;
|
|
650
|
+
}
|
|
651
|
+
novalidate(novalidate) {
|
|
652
|
+
this.wrapProperty("novalidate", novalidate);
|
|
653
|
+
return this;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
var InputType;
|
|
657
|
+
((InputType2) => {
|
|
658
|
+
InputType2["button"] = "button";
|
|
659
|
+
InputType2["checkbox"] = "checkbox";
|
|
660
|
+
InputType2["color"] = "color";
|
|
661
|
+
InputType2["date"] = "date";
|
|
662
|
+
InputType2["datetimelocal"] = "datetime-local";
|
|
663
|
+
InputType2["email"] = "email";
|
|
664
|
+
InputType2["file"] = "file";
|
|
665
|
+
InputType2["hidden"] = "hidden";
|
|
666
|
+
InputType2["image"] = "image";
|
|
667
|
+
InputType2["month"] = "month";
|
|
668
|
+
InputType2["number"] = "number";
|
|
669
|
+
InputType2["password"] = "password";
|
|
670
|
+
InputType2["radio"] = "radio";
|
|
671
|
+
InputType2["range"] = "range";
|
|
672
|
+
InputType2["reset"] = "reset";
|
|
673
|
+
InputType2["search"] = "search";
|
|
674
|
+
InputType2["submit"] = "submit";
|
|
675
|
+
InputType2["tel"] = "tel";
|
|
676
|
+
InputType2["text"] = "text";
|
|
677
|
+
InputType2["time"] = "time";
|
|
678
|
+
InputType2["url"] = "url";
|
|
679
|
+
InputType2["week"] = "week";
|
|
680
|
+
})(InputType ||= {});
|
|
681
|
+
|
|
682
|
+
// src/src/Components.ts
|
|
683
|
+
function getDisabledClass(config) {
|
|
684
|
+
let disabledClass;
|
|
685
|
+
if (isSignal(config.disabled)) {
|
|
686
|
+
disabledClass = compute((newValue) => newValue ? "disabled" : "enabled", config.disabled);
|
|
687
|
+
} else {
|
|
688
|
+
disabledClass = config.disabled ? "disabled" : "enabled";
|
|
689
|
+
}
|
|
690
|
+
return disabledClass;
|
|
691
|
+
}
|
|
692
|
+
function button(config) {
|
|
693
|
+
config.classes ??= [];
|
|
694
|
+
return create("button").applyGenericConfig(config).onclick(config.onclick).classes(getDisabledClass(config)).attributes("tabindex", config.tabindex ?? "0").children(when(config.icon, () => icon(config.icon)), when(config.text, () => text({
|
|
695
|
+
text: config.text
|
|
696
|
+
}))).build();
|
|
697
|
+
}
|
|
698
|
+
function input(config) {
|
|
699
|
+
const errors = signal([]);
|
|
700
|
+
const hasError = compute((e) => [...e].length > 0, errors);
|
|
701
|
+
const invalidClass = compute((has) => has ? "invalid" : "valid", hasError);
|
|
702
|
+
const touched = signal(false);
|
|
703
|
+
const isPassword = config.type === InputType.password;
|
|
704
|
+
const passwordClass = isPassword ? "jessc-password-input" : "_";
|
|
705
|
+
const toggleState = signal(false);
|
|
706
|
+
const configTypeSignal = config.type.constructor === Signal ? config.type : signal(config.type);
|
|
707
|
+
const actualType = compute((t) => t ? InputType.text : configTypeSignal.value, toggleState);
|
|
708
|
+
let lastChange = 0;
|
|
709
|
+
let debounceTimeout;
|
|
710
|
+
function validate(newValue) {
|
|
711
|
+
errors.value = [];
|
|
712
|
+
if (config.debounce) {
|
|
713
|
+
if (Date.now() - lastChange < config.debounce) {
|
|
714
|
+
if (debounceTimeout) {
|
|
715
|
+
clearTimeout(debounceTimeout);
|
|
716
|
+
}
|
|
717
|
+
debounceTimeout = setTimeout(() => {
|
|
718
|
+
debounceTimeout = undefined;
|
|
719
|
+
validate(newValue);
|
|
720
|
+
}, config.debounce);
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
config.validators?.forEach(async (valFunction) => {
|
|
725
|
+
const valErrors = await valFunction(newValue);
|
|
726
|
+
if (valErrors) {
|
|
727
|
+
errors.value = errors.value.concat(valErrors);
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
if (config.required && (newValue === null || newValue === undefined || newValue === "") && touched.value) {
|
|
731
|
+
errors.value = errors.value.concat(["This field is required."]);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
let value = config.value;
|
|
735
|
+
if (isSignal(config.value)) {
|
|
736
|
+
asSignal(config.value).subscribe(validate);
|
|
737
|
+
validate(asSignal(config.value).value);
|
|
738
|
+
} else {
|
|
739
|
+
validate(config.value);
|
|
740
|
+
value = signal(config.value ?? "");
|
|
741
|
+
}
|
|
742
|
+
return create("div").classes("flex-v", "fjsc").children(create("label").classes("flex-v", "fjsc", getDisabledClass(config)).text(config.label ?? "").for(config.title).children(create("input").classes(invalidClass, passwordClass).applyGenericConfig(config).type(actualType).value(value).accept(config.accept ?? "").required(config.required ?? false).placeholder(config.placeholder ?? "").attributes("autofocus", config.autofocus ?? "").oninput((e) => {
|
|
743
|
+
touched.value = true;
|
|
744
|
+
lastChange = Date.now();
|
|
745
|
+
if (!isSignal(config.value)) {
|
|
746
|
+
validate(e.target.value);
|
|
747
|
+
}
|
|
748
|
+
if (config.onchange) {
|
|
749
|
+
config.onchange(e.target.value);
|
|
750
|
+
}
|
|
751
|
+
}).onchange((e) => {
|
|
752
|
+
touched.value = true;
|
|
753
|
+
lastChange = Date.now();
|
|
754
|
+
if (!isSignal(config.value)) {
|
|
755
|
+
validate(e.target.value);
|
|
756
|
+
}
|
|
757
|
+
if (config.onchange) {
|
|
758
|
+
config.onchange(e.target.value);
|
|
759
|
+
}
|
|
760
|
+
}).onkeydown(config.onkeydown ?? (() => {})).name(config.name).build(), when(isPassword, eyeButton(toggleState, () => {
|
|
761
|
+
toggleState.value = !toggleState.value;
|
|
762
|
+
}))).build(), when(hasError, errorList(errors))).build();
|
|
763
|
+
}
|
|
764
|
+
function eyeButton(toggleState, onClick) {
|
|
765
|
+
const icon$ = compute((t) => t ? "visibility" : "visibility_off", toggleState);
|
|
766
|
+
return create("div").classes("jessc-eye-button").onclick(onClick).children(icon({
|
|
767
|
+
icon: icon$,
|
|
768
|
+
adaptive: true,
|
|
769
|
+
isUrl: false
|
|
770
|
+
})).build();
|
|
771
|
+
}
|
|
772
|
+
function textarea(config) {
|
|
773
|
+
const errors = signal([]);
|
|
774
|
+
const hasError = compute((e) => e.length > 0, errors);
|
|
775
|
+
const invalidClass = compute((has) => has ? "invalid" : "valid", hasError);
|
|
776
|
+
function validate(newValue) {
|
|
777
|
+
errors.value = [];
|
|
778
|
+
config.validators?.forEach(async (valFunction) => {
|
|
779
|
+
const valErrors = await valFunction(newValue);
|
|
780
|
+
if (valErrors) {
|
|
781
|
+
errors.value = errors.value.concat(valErrors);
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
if (config.required && (newValue === null || newValue === undefined || newValue === "")) {
|
|
785
|
+
errors.value = errors.value.concat(["This field is required."]);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
if (isSignal(config.value)) {
|
|
789
|
+
asSignal(config.value).subscribe(validate);
|
|
790
|
+
validate(asSignal(config.value).value);
|
|
791
|
+
} else {
|
|
792
|
+
validate(config.value);
|
|
793
|
+
}
|
|
794
|
+
return create("div").classes("flex-v", "fjsc", ...config.classes ?? []).children(create("label").classes("flex-v", "fjsc", getDisabledClass(config)).text(config.label ?? "").for(config.name).children(create("textarea").classes(invalidClass).applyGenericConfig(config).styles("resize", config.resize ?? "vertical").value(config.value).required(config.required ?? false).placeholder(config.placeholder ?? "").attributes("autofocus", config.autofocus ?? "", "rows", config.rows?.toString() ?? "3").oninput((e) => {
|
|
795
|
+
if (!isSignal(config.value)) {
|
|
796
|
+
validate(e.target.value);
|
|
797
|
+
}
|
|
798
|
+
if (config.onchange) {
|
|
799
|
+
config.onchange(e.target.value);
|
|
800
|
+
}
|
|
801
|
+
}).onchange((e) => {
|
|
802
|
+
if (!isSignal(config.value)) {
|
|
803
|
+
validate(e.target.value);
|
|
804
|
+
}
|
|
805
|
+
if (config.onchange) {
|
|
806
|
+
config.onchange(e.target.value);
|
|
807
|
+
}
|
|
808
|
+
}).name(config.name).build()).build(), when(hasError, errorList(errors))).build();
|
|
809
|
+
}
|
|
810
|
+
function errorList(errors) {
|
|
811
|
+
return signalMap(errors, create("div").classes("flex-v", "fjsc", "jessc-error-list"), error);
|
|
812
|
+
}
|
|
813
|
+
function error(error2) {
|
|
814
|
+
return create("span").classes("jessc-error").text(error2).build();
|
|
815
|
+
}
|
|
816
|
+
function area(config) {
|
|
817
|
+
config.classes ??= [];
|
|
818
|
+
config.children ??= [];
|
|
819
|
+
return create(config.tag ?? "div").applyGenericConfig(config).classes("jessc-area").children(...config.children).build();
|
|
820
|
+
}
|
|
821
|
+
function container(config) {
|
|
822
|
+
config.classes ??= [];
|
|
823
|
+
config.children ??= [];
|
|
824
|
+
return create(config.tag ?? "div").applyGenericConfig(config).classes("jessc-container").children(...config.children).build();
|
|
825
|
+
}
|
|
826
|
+
function text(config) {
|
|
827
|
+
return create(config.tag ?? "span").applyGenericConfig(config).text(config.text).build();
|
|
828
|
+
}
|
|
829
|
+
function heading(config) {
|
|
830
|
+
return create(`h${config.level ?? 1}`).applyGenericConfig(config).text(config.text).build();
|
|
831
|
+
}
|
|
832
|
+
function icon(config) {
|
|
833
|
+
const icon2 = config.icon;
|
|
834
|
+
const isMaterial = !config.isUrl;
|
|
835
|
+
const iconClass = config.adaptive ? "adaptive-icon" : "static-icon";
|
|
836
|
+
const pointerClass = config.title ? "_" : "no-pointer";
|
|
837
|
+
if (isMaterial) {
|
|
838
|
+
return create("i").applyGenericConfig(config).classes(iconClass, "material-symbols-outlined", pointerClass).text(icon2).onclick(config.onclick).build();
|
|
839
|
+
}
|
|
840
|
+
return create("img").applyGenericConfig(config).classes(iconClass, pointerClass).attributes("src", icon2).onclick(config.onclick).build();
|
|
841
|
+
}
|
|
842
|
+
function searchableSelect(config) {
|
|
843
|
+
const options = config.options ?? signal([]);
|
|
844
|
+
const value = config.value ?? signal(null);
|
|
845
|
+
const search = signal(options.value.find((o) => o.id === value.value)?.name ?? "");
|
|
846
|
+
value.subscribe((newVal) => {
|
|
847
|
+
search.value = options.value.find((o) => o.id === newVal)?.name ?? "";
|
|
848
|
+
});
|
|
849
|
+
const optionsVisible = signal(false);
|
|
850
|
+
const filtered = signal(options.value);
|
|
851
|
+
const selectedIndex = signal(0);
|
|
852
|
+
const filter = () => {
|
|
853
|
+
selectedIndex.value = options.value.findIndex((o) => o.name.toLowerCase().includes(search.value.toLowerCase()));
|
|
854
|
+
};
|
|
855
|
+
options.subscribe(filter);
|
|
856
|
+
search.subscribe(filter);
|
|
857
|
+
filter();
|
|
858
|
+
const selectedId = signal(options.value[0]?.id ?? null);
|
|
859
|
+
const updateSelectedId = () => {
|
|
860
|
+
selectedId.value = filtered.value[selectedIndex.value]?.id;
|
|
861
|
+
};
|
|
862
|
+
selectedIndex.subscribe(updateSelectedId);
|
|
863
|
+
filtered.subscribe(updateSelectedId);
|
|
864
|
+
updateSelectedId();
|
|
865
|
+
const currentIcon = compute((vis) => vis ? "arrow_drop_up" : "arrow_drop_down", optionsVisible);
|
|
866
|
+
return create("div").applyGenericConfig(config).classes("jessc-search-select", "flex-v", "relative").children(when(config.label, create("label").classes("fjsc").text(config.label).build()), create("div").classes("flex", "jessc-search-select-visible", "fjsc").children(create("input").classes("fjsc", "jessc-search-select-input", getDisabledClass(config)).value(search).onfocus(() => {
|
|
867
|
+
optionsVisible.value = true;
|
|
868
|
+
}).onkeydown((e) => {
|
|
869
|
+
switch (e.key) {
|
|
870
|
+
case "Enter":
|
|
871
|
+
e.preventDefault();
|
|
872
|
+
e.stopPropagation();
|
|
873
|
+
const selectedOption = filtered.value[selectedIndex.value];
|
|
874
|
+
value.value = selectedOption?.id ?? value.value;
|
|
875
|
+
search.value = selectedOption?.name ?? search.value;
|
|
876
|
+
optionsVisible.value = false;
|
|
877
|
+
break;
|
|
878
|
+
case "ArrowDown":
|
|
879
|
+
e.preventDefault();
|
|
880
|
+
e.stopPropagation();
|
|
881
|
+
selectedIndex.value = (selectedIndex.value + 1) % filtered.value.length;
|
|
882
|
+
break;
|
|
883
|
+
case "ArrowUp":
|
|
884
|
+
e.preventDefault();
|
|
885
|
+
e.stopPropagation();
|
|
886
|
+
selectedIndex.value = (selectedIndex.value - 1 + filtered.value.length) % filtered.value.length;
|
|
887
|
+
break;
|
|
888
|
+
case "Escape":
|
|
889
|
+
case "Tab":
|
|
890
|
+
optionsVisible.value = false;
|
|
891
|
+
break;
|
|
892
|
+
default:
|
|
893
|
+
if (e.keyCode > 32 && e.keyCode < 126 || e.key === "Backspace") {
|
|
894
|
+
setTimeout(() => {
|
|
895
|
+
search.value = e.target.value;
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
break;
|
|
899
|
+
}
|
|
900
|
+
}).build(), create("div").classes("jessc-search-select-dropdown", getDisabledClass(config)).onclick(() => {
|
|
901
|
+
optionsVisible.value = !optionsVisible.value;
|
|
902
|
+
}).children(icon({
|
|
903
|
+
icon: currentIcon,
|
|
904
|
+
adaptive: true,
|
|
905
|
+
isUrl: false
|
|
906
|
+
})).build()).build(), when(optionsVisible, signalMap(filtered, create("div").classes("jessc-search-select-options", "flex-v"), (option) => searchSelectOption({ option, value, search, optionsVisible, selectedId })))).build();
|
|
907
|
+
}
|
|
908
|
+
function searchSelectOption(config) {
|
|
909
|
+
let element;
|
|
910
|
+
const selectedClass = compute((id) => {
|
|
911
|
+
element?.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
912
|
+
return id === config.option.id ? "selected" : "_";
|
|
913
|
+
}, config.selectedId);
|
|
914
|
+
element = create("div").classes("jessc-search-select-option", "flex", "gap", "padded", selectedClass).onclick(() => {
|
|
915
|
+
config.value.value = config.option.id;
|
|
916
|
+
config.search.value = config.option.name;
|
|
917
|
+
config.optionsVisible.value = false;
|
|
918
|
+
}).children(when(config.option.image, icon({
|
|
919
|
+
icon: config.option.image ?? "",
|
|
920
|
+
isUrl: config.option.imageIsUrl,
|
|
921
|
+
adaptive: true
|
|
922
|
+
})), create("span").text(config.option.name).build()).build();
|
|
923
|
+
return element;
|
|
924
|
+
}
|
|
925
|
+
function checkbox(config) {
|
|
926
|
+
const errors = signal([]);
|
|
927
|
+
const hasError = compute((e) => e.length > 0, errors);
|
|
928
|
+
const invalidClass = compute((has) => has ? "invalid" : "valid", hasError);
|
|
929
|
+
function validate(newValue) {
|
|
930
|
+
errors.value = [];
|
|
931
|
+
config.validators?.forEach(async (valFunction) => {
|
|
932
|
+
const valErrors = await valFunction(newValue);
|
|
933
|
+
if (valErrors) {
|
|
934
|
+
errors.value = errors.value.concat(valErrors);
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
if (config.required && (newValue === null || newValue === undefined || newValue === false)) {
|
|
938
|
+
errors.value = errors.value.concat(["This field is required."]);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
let checked;
|
|
942
|
+
if (isSignal(config.checked)) {
|
|
943
|
+
const sig = config.checked;
|
|
944
|
+
sig.subscribe(validate);
|
|
945
|
+
validate(sig.value);
|
|
946
|
+
checked = compute((c) => c.toString(), sig);
|
|
947
|
+
} else {
|
|
948
|
+
validate(config.checked);
|
|
949
|
+
checked = config.checked.toString();
|
|
950
|
+
}
|
|
951
|
+
return create("div").classes("flex-v", "fjsc").children(create("label").applyGenericConfig(config).classes("jessc-checkbox-container", invalidClass, getDisabledClass(config)).text(config.text).children(create("input").type(InputType.checkbox).name(config.name ?? "").id(config.name ?? "").required(config.required ?? false).checked(checked).onclick((e) => {
|
|
952
|
+
const c = e.target.checked;
|
|
953
|
+
if (!isSignal(config.checked)) {
|
|
954
|
+
validate(c);
|
|
955
|
+
}
|
|
956
|
+
config.onchange && config.onchange(c);
|
|
957
|
+
}).build(), create("span").classes("jessc-checkmark").children(when(config.checked, create("span").classes("jessc-checkmark-icon").text("\u2713").build())).build()).build(), when(hasError, errorList(errors))).build();
|
|
958
|
+
}
|
|
959
|
+
function toggle(config) {
|
|
960
|
+
const errors = signal([]);
|
|
961
|
+
const hasError = compute((e) => e.length > 0, errors);
|
|
962
|
+
const invalidClass = compute((has) => has ? "invalid" : "valid", hasError);
|
|
963
|
+
function validate(newValue) {
|
|
964
|
+
errors.value = [];
|
|
965
|
+
config.validators?.forEach(async (valFunction) => {
|
|
966
|
+
const valErrors = await valFunction(newValue);
|
|
967
|
+
if (valErrors) {
|
|
968
|
+
errors.value = errors.value.concat(valErrors);
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
if (config.required && (newValue === null || newValue === undefined || newValue === false)) {
|
|
972
|
+
errors.value = errors.value.concat(["This field is required."]);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
if (isSignal(config.checked)) {
|
|
976
|
+
const sig = config.checked;
|
|
977
|
+
sig.subscribe(validate);
|
|
978
|
+
validate(sig.value);
|
|
979
|
+
} else {
|
|
980
|
+
validate(config.checked);
|
|
981
|
+
}
|
|
982
|
+
return create("div").classes("flex-v", "fjsc").children(create("label").applyGenericConfig(config).classes("flex", "gap", "align-children", invalidClass, getDisabledClass(config)).for(config.name ?? "").children(create("input").type(InputType.checkbox).classes("hidden", "jessc-slider").id(config.name ?? "").required(config.required ?? false).checked(config.checked).onclick((e) => {
|
|
983
|
+
const checked = e.target.checked;
|
|
984
|
+
if (!isSignal(config.checked)) {
|
|
985
|
+
validate(checked);
|
|
986
|
+
}
|
|
987
|
+
config.onchange && config.onchange(checked);
|
|
988
|
+
}).build(), create("div").classes("jessc-toggle-container").children(create("span").classes("jessc-toggle-slider").build()).build(), create("span").classes("jessc-toggle-text").text(config.text ?? "").build()).build(), when(hasError, errorList(errors))).build();
|
|
989
|
+
}
|
|
990
|
+
export {
|
|
991
|
+
toggle,
|
|
992
|
+
textarea,
|
|
993
|
+
text,
|
|
994
|
+
searchableSelect,
|
|
995
|
+
searchSelectOption,
|
|
996
|
+
input,
|
|
997
|
+
icon,
|
|
998
|
+
heading,
|
|
999
|
+
eyeButton,
|
|
1000
|
+
errorList,
|
|
1001
|
+
error,
|
|
1002
|
+
container,
|
|
1003
|
+
checkbox,
|
|
1004
|
+
button,
|
|
1005
|
+
area
|
|
1006
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BooleanConfig, ButtonConfig, ContainerConfig, HeadingConfig, IconConfig, InputConfig, SearchableSelectConfig, SelectOptionConfig, TextareaConfig, TextConfig } from "./Types.ts";
|
|
2
|
+
import { type AnyElement, Signal, type StringOrSignal } from "@targoninc/jess";
|
|
3
|
+
export declare function button(config: ButtonConfig): AnyElement;
|
|
4
|
+
export declare function input<T>(config: InputConfig<T>): AnyElement;
|
|
5
|
+
export declare function eyeButton(toggleState: Signal<boolean>, onClick: Function): AnyElement;
|
|
6
|
+
export declare function textarea(config: TextareaConfig): AnyElement;
|
|
7
|
+
export declare function errorList(errors: Signal<string[]>): any;
|
|
8
|
+
export declare function error(error: StringOrSignal): AnyElement;
|
|
9
|
+
export declare function area(config: ContainerConfig): AnyElement;
|
|
10
|
+
export declare function container(config: ContainerConfig): AnyElement;
|
|
11
|
+
export declare function text(config: TextConfig): AnyElement;
|
|
12
|
+
export declare function heading(config: HeadingConfig): AnyElement;
|
|
13
|
+
export declare function icon(config: IconConfig): AnyElement;
|
|
14
|
+
export declare function searchableSelect(config: SearchableSelectConfig): AnyElement;
|
|
15
|
+
export declare function searchSelectOption(config: SelectOptionConfig): any;
|
|
16
|
+
export declare function checkbox(config: BooleanConfig): AnyElement;
|
|
17
|
+
export declare function toggle(config: BooleanConfig): AnyElement;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type CssClass, DomNode, type EventHandler, type HtmlPropertyValue, InputType, Signal, type StringOrSignal, type TypeOrSignal } from "@targoninc/jess";
|
|
2
|
+
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N ? Acc[number] : Enumerate<N, [...Acc, Acc['length']]>;
|
|
3
|
+
type IntRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;
|
|
4
|
+
export interface BaseComponentConfig {
|
|
5
|
+
classes?: StringOrSignal[];
|
|
6
|
+
attributes?: StringOrSignal[];
|
|
7
|
+
styles?: StringOrSignal[];
|
|
8
|
+
id?: HtmlPropertyValue;
|
|
9
|
+
title?: HtmlPropertyValue;
|
|
10
|
+
tabindex?: HtmlPropertyValue;
|
|
11
|
+
role?: HtmlPropertyValue;
|
|
12
|
+
ariaLabel?: HtmlPropertyValue;
|
|
13
|
+
css?: CssClass;
|
|
14
|
+
}
|
|
15
|
+
export interface ButtonConfig extends BaseComponentConfig {
|
|
16
|
+
text?: StringOrSignal;
|
|
17
|
+
onclick: EventHandler<MouseEvent>;
|
|
18
|
+
icon?: IconConfig;
|
|
19
|
+
disabled?: TypeOrSignal<boolean>;
|
|
20
|
+
}
|
|
21
|
+
export type ValidatorFunction<T> = (value: T) => (string[] | null | undefined) | Promise<string[] | null | undefined>;
|
|
22
|
+
export interface ChangeableConfig<T = any> extends BaseComponentConfig {
|
|
23
|
+
onchange?: (value: T) => void;
|
|
24
|
+
validators?: ValidatorFunction<T>[];
|
|
25
|
+
required?: boolean;
|
|
26
|
+
autofocus?: boolean;
|
|
27
|
+
label?: HtmlPropertyValue;
|
|
28
|
+
disabled?: TypeOrSignal<boolean>;
|
|
29
|
+
}
|
|
30
|
+
export interface InputConfig<T> extends ChangeableConfig<T> {
|
|
31
|
+
name: StringOrSignal;
|
|
32
|
+
type: TypeOrSignal<InputType>;
|
|
33
|
+
value: TypeOrSignal<T>;
|
|
34
|
+
placeholder?: StringOrSignal;
|
|
35
|
+
accept?: StringOrSignal;
|
|
36
|
+
onkeydown?: EventHandler<KeyboardEvent>;
|
|
37
|
+
debounce?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface TextareaConfig extends ChangeableConfig<string> {
|
|
40
|
+
name: StringOrSignal;
|
|
41
|
+
value: StringOrSignal;
|
|
42
|
+
placeholder?: StringOrSignal;
|
|
43
|
+
rows?: TypeOrSignal<number>;
|
|
44
|
+
resize?: "both" | "horizontal" | "vertical" | "none";
|
|
45
|
+
}
|
|
46
|
+
export interface ContainerConfig extends BaseComponentConfig {
|
|
47
|
+
tag: string;
|
|
48
|
+
children: (DomNode)[];
|
|
49
|
+
}
|
|
50
|
+
export interface TextConfig extends BaseComponentConfig {
|
|
51
|
+
text: HtmlPropertyValue;
|
|
52
|
+
tag: string;
|
|
53
|
+
}
|
|
54
|
+
export interface IconConfig extends BaseComponentConfig {
|
|
55
|
+
icon: StringOrSignal;
|
|
56
|
+
adaptive?: boolean;
|
|
57
|
+
isUrl?: boolean;
|
|
58
|
+
onclick?: Function;
|
|
59
|
+
}
|
|
60
|
+
export interface SelectOption extends BaseComponentConfig {
|
|
61
|
+
image?: string;
|
|
62
|
+
imageIsUrl?: boolean;
|
|
63
|
+
name: any;
|
|
64
|
+
id: any;
|
|
65
|
+
}
|
|
66
|
+
export interface SelectOptionConfig extends BaseComponentConfig {
|
|
67
|
+
option: SelectOption;
|
|
68
|
+
value: Signal<any>;
|
|
69
|
+
search: Signal<string>;
|
|
70
|
+
optionsVisible: Signal<boolean>;
|
|
71
|
+
selectedId: Signal<any>;
|
|
72
|
+
}
|
|
73
|
+
export interface SearchableSelectConfig<T = string> extends ChangeableConfig<T> {
|
|
74
|
+
options: Signal<SelectOption[]>;
|
|
75
|
+
value: Signal<T>;
|
|
76
|
+
}
|
|
77
|
+
export interface HeadingConfig extends BaseComponentConfig {
|
|
78
|
+
level?: IntRange<1, 6>;
|
|
79
|
+
text: StringOrSignal;
|
|
80
|
+
}
|
|
81
|
+
export interface BooleanConfig extends ChangeableConfig<boolean> {
|
|
82
|
+
text: HtmlPropertyValue;
|
|
83
|
+
checked: TypeOrSignal<boolean>;
|
|
84
|
+
name?: HtmlPropertyValue;
|
|
85
|
+
}
|
|
86
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@targoninc/jess-components",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/targoninc/jess-components.git"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target bun --format esm && tsc",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"prepublishOnly": "bun run build"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@targoninc/jess": "^0.0.6"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/bun": "latest",
|
|
24
|
+
"bun-plugin-dtsx": "^0.21.9"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"typescript": "^5"
|
|
28
|
+
}
|
|
29
|
+
}
|