kerfjs 4.2.0-beta.2 → 4.2.0-beta.4
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/CHANGELOG.md +3 -3
- package/dist/async.d.ts +39 -3
- package/dist/async.js +60 -13
- package/dist/async.js.map +1 -1
- package/dist/list.d.ts +28 -4
- package/dist/list.js +53 -16
- package/dist/list.js.map +1 -1
- package/dist/overlay.d.ts +197 -6
- package/dist/overlay.js +240 -71
- package/dist/overlay.js.map +1 -1
- package/package.json +1 -1
package/dist/overlay.js
CHANGED
|
@@ -125,9 +125,10 @@ function confirm(message, options = {}) {
|
|
|
125
125
|
title,
|
|
126
126
|
okText = "OK",
|
|
127
127
|
cancelText = "Cancel",
|
|
128
|
-
danger = false
|
|
128
|
+
danger = false,
|
|
129
|
+
render
|
|
129
130
|
} = options;
|
|
130
|
-
const body = jsx("div", {
|
|
131
|
+
const body = render !== void 0 ? render({ message, ok: { "data-confirm": "ok" }, cancel: { "data-confirm": "cancel" } }) : jsx("div", {
|
|
131
132
|
class: "kerf-confirm",
|
|
132
133
|
children: [
|
|
133
134
|
title !== void 0 ? jsx("h2", { class: "kerf-confirm__title", children: title }) : "",
|
|
@@ -150,7 +151,7 @@ function confirm(message, options = {}) {
|
|
|
150
151
|
container,
|
|
151
152
|
className: danger ? `${className} kerf-confirm--danger` : className,
|
|
152
153
|
dismiss: ["escape", "backdrop"],
|
|
153
|
-
initialFocus:
|
|
154
|
+
initialFocus: '[data-confirm="ok"]',
|
|
154
155
|
trap: true
|
|
155
156
|
});
|
|
156
157
|
delegate(handle.el, "click", "[data-confirm]", (_event, el) => {
|
|
@@ -168,20 +169,27 @@ function prompt(message, options = {}) {
|
|
|
168
169
|
inputType = "text",
|
|
169
170
|
okText = "OK",
|
|
170
171
|
cancelText = "Cancel",
|
|
171
|
-
validate
|
|
172
|
+
validate,
|
|
173
|
+
render
|
|
172
174
|
} = options;
|
|
173
|
-
const
|
|
175
|
+
const inputAttrs = {
|
|
176
|
+
"data-prompt-input": "",
|
|
177
|
+
type: inputType,
|
|
178
|
+
value: defaultValue,
|
|
179
|
+
...placeholder !== void 0 ? { placeholder } : {}
|
|
180
|
+
};
|
|
181
|
+
const body = render !== void 0 ? render({
|
|
182
|
+
message,
|
|
183
|
+
input: inputAttrs,
|
|
184
|
+
error: { "data-prompt-error": "" },
|
|
185
|
+
ok: { "data-prompt": "ok" },
|
|
186
|
+
cancel: { "data-prompt": "cancel" }
|
|
187
|
+
}) : jsx("div", {
|
|
174
188
|
class: "kerf-prompt",
|
|
175
189
|
children: [
|
|
176
190
|
title !== void 0 ? jsx("h2", { class: "kerf-prompt__title", children: title }) : "",
|
|
177
191
|
jsx("label", { class: "kerf-prompt__message", children: message }),
|
|
178
|
-
jsx("input", {
|
|
179
|
-
class: "kerf-prompt__input",
|
|
180
|
-
type: inputType,
|
|
181
|
-
value: defaultValue,
|
|
182
|
-
...placeholder !== void 0 ? { placeholder } : {},
|
|
183
|
-
"data-prompt-input": ""
|
|
184
|
-
}),
|
|
192
|
+
jsx("input", { class: "kerf-prompt__input", ...inputAttrs }),
|
|
185
193
|
jsx("p", { class: "kerf-prompt__error", "data-prompt-error": "", children: "" }),
|
|
186
194
|
jsx("div", {
|
|
187
195
|
class: "kerf-prompt__actions",
|
|
@@ -201,18 +209,20 @@ function prompt(message, options = {}) {
|
|
|
201
209
|
container,
|
|
202
210
|
className,
|
|
203
211
|
dismiss: ["escape", "backdrop"],
|
|
204
|
-
initialFocus: "
|
|
212
|
+
initialFocus: "[data-prompt-input]",
|
|
205
213
|
trap: true
|
|
206
214
|
});
|
|
207
215
|
const input = handle.el.querySelector("[data-prompt-input]");
|
|
208
216
|
const errorEl = handle.el.querySelector("[data-prompt-error]");
|
|
209
|
-
errorEl.hidden = true;
|
|
217
|
+
if (errorEl !== null) errorEl.hidden = true;
|
|
210
218
|
function attemptOk() {
|
|
211
219
|
const value = input.value;
|
|
212
220
|
const error = validate?.(value);
|
|
213
221
|
if (typeof error === "string" && error.length > 0) {
|
|
214
|
-
errorEl
|
|
215
|
-
|
|
222
|
+
if (errorEl !== null) {
|
|
223
|
+
errorEl.textContent = error;
|
|
224
|
+
errorEl.hidden = false;
|
|
225
|
+
}
|
|
216
226
|
input.focus();
|
|
217
227
|
return;
|
|
218
228
|
}
|
|
@@ -231,8 +241,24 @@ function prompt(message, options = {}) {
|
|
|
231
241
|
return handle.result.then((value) => typeof value === "string" ? value : null);
|
|
232
242
|
}
|
|
233
243
|
function form(fields, options = {}) {
|
|
234
|
-
const { container, className = "kerf-overlay", title, okText = "OK", cancelText = "Cancel" } = options;
|
|
235
|
-
const
|
|
244
|
+
const { container, className = "kerf-overlay", title, okText = "OK", cancelText = "Cancel", render } = options;
|
|
245
|
+
const fieldAttrs = (field) => ({
|
|
246
|
+
"data-field": field.name,
|
|
247
|
+
name: field.name,
|
|
248
|
+
type: field.type ?? "text",
|
|
249
|
+
value: field.defaultValue ?? "",
|
|
250
|
+
...field.placeholder !== void 0 ? { placeholder: field.placeholder } : {}
|
|
251
|
+
});
|
|
252
|
+
const body = render !== void 0 ? render({
|
|
253
|
+
fields: fields.map((field) => ({
|
|
254
|
+
name: field.name,
|
|
255
|
+
label: field.label ?? field.name,
|
|
256
|
+
input: fieldAttrs(field),
|
|
257
|
+
error: { "data-field-error": field.name }
|
|
258
|
+
})),
|
|
259
|
+
ok: { "data-form": "ok" },
|
|
260
|
+
cancel: { "data-form": "cancel" }
|
|
261
|
+
}) : jsx("div", {
|
|
236
262
|
class: "kerf-form",
|
|
237
263
|
children: [
|
|
238
264
|
title !== void 0 ? jsx("h2", { class: "kerf-form__title", children: title }) : "",
|
|
@@ -241,19 +267,8 @@ function form(fields, options = {}) {
|
|
|
241
267
|
class: "kerf-form__field",
|
|
242
268
|
children: [
|
|
243
269
|
jsx("label", { class: "kerf-form__label", children: field.label ?? field.name }),
|
|
244
|
-
jsx("input", {
|
|
245
|
-
|
|
246
|
-
type: field.type ?? "text",
|
|
247
|
-
name: field.name,
|
|
248
|
-
value: field.defaultValue ?? "",
|
|
249
|
-
...field.placeholder !== void 0 ? { placeholder: field.placeholder } : {},
|
|
250
|
-
"data-field": field.name
|
|
251
|
-
}),
|
|
252
|
-
jsx("p", {
|
|
253
|
-
class: "kerf-form__error",
|
|
254
|
-
"data-field-error": field.name,
|
|
255
|
-
children: ""
|
|
256
|
-
})
|
|
270
|
+
jsx("input", { class: "kerf-form__input", ...fieldAttrs(field) }),
|
|
271
|
+
jsx("p", { class: "kerf-form__error", "data-field-error": field.name, children: "" })
|
|
257
272
|
]
|
|
258
273
|
})
|
|
259
274
|
),
|
|
@@ -275,14 +290,18 @@ function form(fields, options = {}) {
|
|
|
275
290
|
container,
|
|
276
291
|
className,
|
|
277
292
|
dismiss: ["escape", "backdrop"],
|
|
278
|
-
initialFocus: "
|
|
293
|
+
initialFocus: "[data-field]",
|
|
279
294
|
trap: true
|
|
280
295
|
});
|
|
281
296
|
const byAttr = (attr, name) => Array.from(handle.el.querySelectorAll(`[${attr}]`)).find(
|
|
282
297
|
(el) => el.getAttribute(attr) === name
|
|
283
298
|
);
|
|
299
|
+
const errorFor = (name) => Array.from(handle.el.querySelectorAll("[data-field-error]")).find(
|
|
300
|
+
(el) => el.getAttribute("data-field-error") === name
|
|
301
|
+
) ?? null;
|
|
284
302
|
for (const field of fields) {
|
|
285
|
-
|
|
303
|
+
const errorEl = errorFor(field.name);
|
|
304
|
+
if (errorEl !== null) errorEl.hidden = true;
|
|
286
305
|
}
|
|
287
306
|
function attemptOk() {
|
|
288
307
|
const record = {};
|
|
@@ -292,12 +311,14 @@ function form(fields, options = {}) {
|
|
|
292
311
|
const value = el.value;
|
|
293
312
|
record[field.name] = value;
|
|
294
313
|
const error = field.validate?.(value);
|
|
295
|
-
const errorEl =
|
|
314
|
+
const errorEl = errorFor(field.name);
|
|
296
315
|
if (typeof error === "string" && error.length > 0) {
|
|
297
|
-
errorEl
|
|
298
|
-
|
|
316
|
+
if (errorEl !== null) {
|
|
317
|
+
errorEl.textContent = error;
|
|
318
|
+
errorEl.hidden = false;
|
|
319
|
+
}
|
|
299
320
|
if (firstInvalid === null) firstInvalid = el;
|
|
300
|
-
} else {
|
|
321
|
+
} else if (errorEl !== null) {
|
|
301
322
|
errorEl.hidden = true;
|
|
302
323
|
}
|
|
303
324
|
}
|
|
@@ -321,6 +342,83 @@ function form(fields, options = {}) {
|
|
|
321
342
|
(value) => value !== null && typeof value === "object" ? value : null
|
|
322
343
|
);
|
|
323
344
|
}
|
|
345
|
+
function choice(message, actions, options = {}) {
|
|
346
|
+
const { container, className = "kerf-overlay", title, defaultValue, render } = options;
|
|
347
|
+
const hasDefault = "defaultValue" in options;
|
|
348
|
+
const actionAttrs = actions.map((_, i) => ({ "data-choice": String(i) }));
|
|
349
|
+
const body = render !== void 0 ? render({ message, actions: actionAttrs }) : jsx("div", {
|
|
350
|
+
class: "kerf-choice",
|
|
351
|
+
children: [
|
|
352
|
+
title !== void 0 ? jsx("h2", { class: "kerf-choice__title", children: title }) : "",
|
|
353
|
+
jsx("p", { class: "kerf-choice__message", children: message }),
|
|
354
|
+
jsx("div", {
|
|
355
|
+
class: "kerf-choice__actions",
|
|
356
|
+
children: actions.map(
|
|
357
|
+
(action, i) => jsx("button", {
|
|
358
|
+
type: "button",
|
|
359
|
+
class: action.className !== void 0 ? `kerf-choice__action ${action.className}` : "kerf-choice__action",
|
|
360
|
+
...actionAttrs[i],
|
|
361
|
+
children: action.label
|
|
362
|
+
})
|
|
363
|
+
)
|
|
364
|
+
})
|
|
365
|
+
]
|
|
366
|
+
});
|
|
367
|
+
let resolveChoice;
|
|
368
|
+
const result = new Promise((resolve) => {
|
|
369
|
+
resolveChoice = resolve;
|
|
370
|
+
});
|
|
371
|
+
const handle = overlay(body, {
|
|
372
|
+
container,
|
|
373
|
+
className,
|
|
374
|
+
dismiss: ["escape", "backdrop"],
|
|
375
|
+
initialFocus: "[data-choice]",
|
|
376
|
+
trap: true
|
|
377
|
+
});
|
|
378
|
+
delegate(handle.el, "click", "[data-choice]", (_event, el) => {
|
|
379
|
+
resolveChoice(actions[Number(el.getAttribute("data-choice"))].value);
|
|
380
|
+
handle.close();
|
|
381
|
+
});
|
|
382
|
+
if (hasDefault) {
|
|
383
|
+
handle.el.addEventListener("keydown", (event) => {
|
|
384
|
+
if (event.key === "Enter") {
|
|
385
|
+
event.preventDefault();
|
|
386
|
+
resolveChoice(defaultValue);
|
|
387
|
+
handle.close();
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
void handle.result.then(() => resolveChoice(null));
|
|
392
|
+
return result;
|
|
393
|
+
}
|
|
394
|
+
function positionAnchored(el, anchor, options = {}) {
|
|
395
|
+
const { placement = "bottom", align = "start", gap = 4 } = options;
|
|
396
|
+
const a = anchor.getBoundingClientRect();
|
|
397
|
+
const p = el.getBoundingClientRect();
|
|
398
|
+
const vw = window.innerWidth;
|
|
399
|
+
const vh = window.innerHeight;
|
|
400
|
+
const belowTop = a.bottom + gap;
|
|
401
|
+
const aboveTop = a.top - gap - p.height;
|
|
402
|
+
let below = placement !== "top";
|
|
403
|
+
if (below && belowTop + p.height > vh && aboveTop >= 0) below = false;
|
|
404
|
+
else if (!below && aboveTop < 0 && belowTop + p.height <= vh) below = true;
|
|
405
|
+
let left = align === "end" ? a.right - p.width : a.left;
|
|
406
|
+
left = Math.max(0, Math.min(left, vw - p.width));
|
|
407
|
+
el.style.position = "fixed";
|
|
408
|
+
el.style.margin = "0";
|
|
409
|
+
el.style.left = `${left}px`;
|
|
410
|
+
el.style.top = `${below ? belowTop : aboveTop}px`;
|
|
411
|
+
}
|
|
412
|
+
function autoReposition(el, anchor, options = {}) {
|
|
413
|
+
const reposition = () => positionAnchored(el, anchor, options);
|
|
414
|
+
reposition();
|
|
415
|
+
window.addEventListener("scroll", reposition, true);
|
|
416
|
+
window.addEventListener("resize", reposition);
|
|
417
|
+
return () => {
|
|
418
|
+
window.removeEventListener("scroll", reposition, true);
|
|
419
|
+
window.removeEventListener("resize", reposition);
|
|
420
|
+
};
|
|
421
|
+
}
|
|
324
422
|
function popover(anchor, content, options = {}) {
|
|
325
423
|
const {
|
|
326
424
|
container,
|
|
@@ -343,32 +441,62 @@ function popover(anchor, content, options = {}) {
|
|
|
343
441
|
onDismiss,
|
|
344
442
|
outsideIgnore: [anchor, ...extraIgnore]
|
|
345
443
|
});
|
|
346
|
-
handle.el
|
|
347
|
-
handle.
|
|
348
|
-
const reposition = () => {
|
|
349
|
-
const a = anchor.getBoundingClientRect();
|
|
350
|
-
const p = handle.el.getBoundingClientRect();
|
|
351
|
-
const vw = window.innerWidth;
|
|
352
|
-
const vh = window.innerHeight;
|
|
353
|
-
const belowTop = a.bottom + gap;
|
|
354
|
-
const aboveTop = a.top - gap - p.height;
|
|
355
|
-
let below = placement !== "top";
|
|
356
|
-
if (below && belowTop + p.height > vh && aboveTop >= 0) below = false;
|
|
357
|
-
else if (!below && aboveTop < 0 && belowTop + p.height <= vh) below = true;
|
|
358
|
-
let left = align === "end" ? a.right - p.width : a.left;
|
|
359
|
-
left = Math.max(0, Math.min(left, vw - p.width));
|
|
360
|
-
handle.el.style.left = `${left}px`;
|
|
361
|
-
handle.el.style.top = `${below ? belowTop : aboveTop}px`;
|
|
362
|
-
};
|
|
363
|
-
reposition();
|
|
364
|
-
window.addEventListener("scroll", reposition, true);
|
|
365
|
-
window.addEventListener("resize", reposition);
|
|
366
|
-
void handle.result.then(() => {
|
|
367
|
-
window.removeEventListener("scroll", reposition, true);
|
|
368
|
-
window.removeEventListener("resize", reposition);
|
|
369
|
-
});
|
|
444
|
+
const stopReposition = autoReposition(handle.el, anchor, { placement, align, gap });
|
|
445
|
+
void handle.result.then(stopReposition);
|
|
370
446
|
return handle;
|
|
371
447
|
}
|
|
448
|
+
function tooltip(anchor, content, options = {}) {
|
|
449
|
+
const {
|
|
450
|
+
container,
|
|
451
|
+
className = "kerf-tooltip",
|
|
452
|
+
delay = 400,
|
|
453
|
+
hideDelay = 100,
|
|
454
|
+
role = "tooltip",
|
|
455
|
+
placement = "top",
|
|
456
|
+
align = "start",
|
|
457
|
+
gap = 4
|
|
458
|
+
} = options;
|
|
459
|
+
const body = typeof content === "function" ? content : typeof content === "string" ? jsx("span", { class: `${className}__text`, children: content }) : content;
|
|
460
|
+
const timers = {};
|
|
461
|
+
let current;
|
|
462
|
+
function show() {
|
|
463
|
+
const handle = overlay(body, { container, className, dismiss: false, trap: false, initialFocus: false });
|
|
464
|
+
handle.el.setAttribute("role", role);
|
|
465
|
+
const stop = autoReposition(handle.el, anchor, { placement, align, gap });
|
|
466
|
+
current = { handle, stop };
|
|
467
|
+
}
|
|
468
|
+
function hide() {
|
|
469
|
+
if (current === void 0) return;
|
|
470
|
+
current.stop();
|
|
471
|
+
current.handle.close();
|
|
472
|
+
current = void 0;
|
|
473
|
+
}
|
|
474
|
+
const onEnter = () => {
|
|
475
|
+
if (timers.hide !== void 0) clearTimeout(timers.hide);
|
|
476
|
+
if (current !== void 0) return;
|
|
477
|
+
if (timers.show !== void 0) clearTimeout(timers.show);
|
|
478
|
+
timers.show = setTimeout(show, delay);
|
|
479
|
+
};
|
|
480
|
+
const onLeave = () => {
|
|
481
|
+
if (timers.show !== void 0) clearTimeout(timers.show);
|
|
482
|
+
if (current === void 0) return;
|
|
483
|
+
timers.hide = setTimeout(hide, hideDelay);
|
|
484
|
+
};
|
|
485
|
+
anchor.addEventListener("pointerenter", onEnter);
|
|
486
|
+
anchor.addEventListener("pointerleave", onLeave);
|
|
487
|
+
anchor.addEventListener("focus", onEnter);
|
|
488
|
+
anchor.addEventListener("blur", onLeave);
|
|
489
|
+
return () => {
|
|
490
|
+
anchor.removeEventListener("pointerenter", onEnter);
|
|
491
|
+
anchor.removeEventListener("pointerleave", onLeave);
|
|
492
|
+
anchor.removeEventListener("focus", onEnter);
|
|
493
|
+
anchor.removeEventListener("blur", onLeave);
|
|
494
|
+
if (timers.show !== void 0) clearTimeout(timers.show);
|
|
495
|
+
if (timers.hide !== void 0) clearTimeout(timers.hide);
|
|
496
|
+
hide();
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
var TOAST_SET = /* @__PURE__ */ Symbol("kerf.toasts");
|
|
372
500
|
function toastRegion(container) {
|
|
373
501
|
if (container !== void 0) return container;
|
|
374
502
|
const existing = document.querySelector(".kerf-toasts");
|
|
@@ -380,27 +508,68 @@ function toastRegion(container) {
|
|
|
380
508
|
return region;
|
|
381
509
|
}
|
|
382
510
|
function toast(content, options = {}) {
|
|
383
|
-
const {
|
|
511
|
+
const {
|
|
512
|
+
container,
|
|
513
|
+
className = "kerf-toast",
|
|
514
|
+
duration = 4e3,
|
|
515
|
+
role = "status",
|
|
516
|
+
mode = "stack",
|
|
517
|
+
collapse = "fade",
|
|
518
|
+
variant,
|
|
519
|
+
enterClass,
|
|
520
|
+
exitClass,
|
|
521
|
+
exitDuration = 0
|
|
522
|
+
} = options;
|
|
523
|
+
const region = toastRegion(container);
|
|
524
|
+
const active = region[TOAST_SET] ??= /* @__PURE__ */ new Set();
|
|
525
|
+
if (mode === "replace") {
|
|
526
|
+
for (const d of [...active]) {
|
|
527
|
+
if (collapse === "instant") d.removeNow();
|
|
528
|
+
else d();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
384
531
|
const el = document.createElement("div");
|
|
385
532
|
el.className = className;
|
|
533
|
+
if (variant !== void 0) el.classList.add(`${className}--${variant}`);
|
|
386
534
|
el.setAttribute("role", role);
|
|
387
|
-
|
|
535
|
+
region.appendChild(el);
|
|
388
536
|
const disposeMount = mount(el, typeof content === "function" ? content : () => content);
|
|
389
|
-
const state = {
|
|
390
|
-
|
|
391
|
-
|
|
537
|
+
const state = { dismissed: false, timer: void 0 };
|
|
538
|
+
if (enterClass !== void 0) {
|
|
539
|
+
globalThis.requestAnimationFrame(() => {
|
|
540
|
+
if (!state.dismissed) el.classList.add(enterClass);
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
const remove = () => {
|
|
544
|
+
disposeMount();
|
|
545
|
+
el.remove();
|
|
546
|
+
active.delete(dismiss);
|
|
392
547
|
};
|
|
393
|
-
|
|
548
|
+
const finish = (instant) => {
|
|
394
549
|
if (state.dismissed) return;
|
|
395
550
|
state.dismissed = true;
|
|
396
551
|
if (state.timer !== void 0) clearTimeout(state.timer);
|
|
397
|
-
|
|
398
|
-
|
|
552
|
+
if (instant) {
|
|
553
|
+
remove();
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (enterClass !== void 0) el.classList.remove(enterClass);
|
|
557
|
+
if (exitClass !== void 0) el.classList.add(exitClass);
|
|
558
|
+
if (exitClass !== void 0 || exitDuration > 0) {
|
|
559
|
+
setTimeout(remove, exitDuration);
|
|
560
|
+
} else {
|
|
561
|
+
remove();
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
function dismiss() {
|
|
565
|
+
finish(false);
|
|
399
566
|
}
|
|
567
|
+
dismiss.removeNow = () => finish(true);
|
|
568
|
+
active.add(dismiss);
|
|
400
569
|
if (duration > 0) state.timer = setTimeout(dismiss, duration);
|
|
401
|
-
return dismiss;
|
|
570
|
+
return { el, dismiss };
|
|
402
571
|
}
|
|
403
572
|
|
|
404
|
-
export { confirm, form, overlay, popover, prompt, toast };
|
|
573
|
+
export { autoReposition, choice, confirm, form, overlay, popover, positionAnchored, prompt, toast, tooltip };
|
|
405
574
|
//# sourceMappingURL=overlay.js.map
|
|
406
575
|
//# sourceMappingURL=overlay.js.map
|