@peektravel/app-utilities 0.2.4 → 0.2.5
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/ui/index.cjs +103 -6
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +21 -0
- package/dist/ui/index.d.ts +21 -0
- package/dist/ui/index.js +103 -6
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/index.cjs
CHANGED
|
@@ -159,6 +159,9 @@ function escapeHtml(value) {
|
|
|
159
159
|
function classes(...parts) {
|
|
160
160
|
return parts.filter(Boolean).join(" ");
|
|
161
161
|
}
|
|
162
|
+
function reflectControlValue(control, value) {
|
|
163
|
+
if (control && control.value !== value) control.value = value;
|
|
164
|
+
}
|
|
162
165
|
function define(tag, ctor) {
|
|
163
166
|
if (typeof customElements === "undefined") return;
|
|
164
167
|
if (!customElements.get(tag)) customElements.define(tag, ctor);
|
|
@@ -1352,6 +1355,28 @@ var OdyInput = class extends OdyElement {
|
|
|
1352
1355
|
this.#value = next;
|
|
1353
1356
|
this.setAttribute("value", next);
|
|
1354
1357
|
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Reflect `value` into the live control in place — the native field already
|
|
1360
|
+
* shows what the user typed, so rebuilding it (as a full re-render would)
|
|
1361
|
+
* needlessly drops focus and caret. Every other observed attribute changes
|
|
1362
|
+
* the chrome and still re-renders via the base implementation.
|
|
1363
|
+
*/
|
|
1364
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
1365
|
+
if (name === "value") {
|
|
1366
|
+
if (oldValue === newValue) return;
|
|
1367
|
+
const value = newValue ?? "";
|
|
1368
|
+
reflectControlValue(
|
|
1369
|
+
this.querySelector(
|
|
1370
|
+
".ody-input__field, .ody-input__textarea"
|
|
1371
|
+
),
|
|
1372
|
+
value
|
|
1373
|
+
);
|
|
1374
|
+
this.#syncCounter(value);
|
|
1375
|
+
this.#syncClearButton(value);
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
super.attributeChangedCallback();
|
|
1379
|
+
}
|
|
1355
1380
|
render() {
|
|
1356
1381
|
const size = this.attr("size", "base");
|
|
1357
1382
|
const isTextarea = this.flag("textarea");
|
|
@@ -1381,8 +1406,7 @@ var OdyInput = class extends OdyElement {
|
|
|
1381
1406
|
`ody-input__container--${size}`
|
|
1382
1407
|
);
|
|
1383
1408
|
const field = isTextarea ? `<textarea class="ody-input__textarea" rows="3"${maxlengthAttr}${isReadonly ? " readonly" : ""}${isDisabled ? " disabled" : ""}>${this.esc(value)}</textarea>` : `<input class="ody-input__field" type="text" value="${this.esc(value)}" placeholder="${this.esc(this.attr("placeholder"))}"${maxlengthAttr}${isReadonly ? " readonly" : ""}${isDisabled ? " disabled" : ""} />`;
|
|
1384
|
-
const
|
|
1385
|
-
const clearEl = clearEnabled ? `<button type="button" class="btn ody-input__clear-button" aria-label="${this.localized("clear-label", "clear")}">${iconSvg("close", "icon__svg clear-icon")}</button>` : "";
|
|
1409
|
+
const clearEl = this.#clearEnabled(value) ? this.#clearButtonHtml() : "";
|
|
1386
1410
|
const showCounter = !isReadonly && !isDisabled && maxlength !== "";
|
|
1387
1411
|
const messages = classes(
|
|
1388
1412
|
caption && "has-caption",
|
|
@@ -1404,7 +1428,6 @@ var OdyInput = class extends OdyElement {
|
|
|
1404
1428
|
#onInput = (event) => {
|
|
1405
1429
|
event.stopPropagation();
|
|
1406
1430
|
const value = event.target.value;
|
|
1407
|
-
this.#syncCounter(value);
|
|
1408
1431
|
this.value = value;
|
|
1409
1432
|
this.dispatchEvent(new CustomEvent("input", { detail: { value }, bubbles: true }));
|
|
1410
1433
|
};
|
|
@@ -1424,6 +1447,26 @@ var OdyInput = class extends OdyElement {
|
|
|
1424
1447
|
const max = this.attr("maxlength");
|
|
1425
1448
|
if (counter && max) counter.textContent = `${value.length} / ${max}`;
|
|
1426
1449
|
}
|
|
1450
|
+
/** Whether the clear button should be shown for the given value. */
|
|
1451
|
+
#clearEnabled(value) {
|
|
1452
|
+
return !this.flag("no-clear") && !this.flag("disabled") && !this.flag("readonly") && value !== "";
|
|
1453
|
+
}
|
|
1454
|
+
/** Markup for the clear button (shared by render and the in-place sync). */
|
|
1455
|
+
#clearButtonHtml() {
|
|
1456
|
+
return `<button type="button" class="btn ody-input__clear-button" aria-label="${this.localized("clear-label", "clear")}">${iconSvg("close", "icon__svg clear-icon")}</button>`;
|
|
1457
|
+
}
|
|
1458
|
+
/** Add or remove the clear button in place as the value gains/loses content. */
|
|
1459
|
+
#syncClearButton(value) {
|
|
1460
|
+
const existing = this.querySelector(".ody-input__clear-button");
|
|
1461
|
+
if (this.#clearEnabled(value)) {
|
|
1462
|
+
if (existing) return;
|
|
1463
|
+
const control = this.querySelector(".ody-input__field, .ody-input__textarea");
|
|
1464
|
+
control?.insertAdjacentHTML("afterend", this.#clearButtonHtml());
|
|
1465
|
+
this.querySelector(".ody-input__clear-button")?.addEventListener("click", this.#onClear);
|
|
1466
|
+
} else {
|
|
1467
|
+
existing?.remove();
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1427
1470
|
};
|
|
1428
1471
|
define("ody-input", OdyInput);
|
|
1429
1472
|
|
|
@@ -1455,6 +1498,28 @@ var OdyInlineInput = class extends OdyElement {
|
|
|
1455
1498
|
this.#value = next;
|
|
1456
1499
|
this.setAttribute("value", next);
|
|
1457
1500
|
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Reflect `value` into the live control in place — the native field already
|
|
1503
|
+
* shows what the user typed, so rebuilding it (as a full re-render would)
|
|
1504
|
+
* needlessly drops focus and caret. Every other observed attribute changes
|
|
1505
|
+
* the chrome and still re-renders via the base implementation.
|
|
1506
|
+
*/
|
|
1507
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
1508
|
+
if (name === "value") {
|
|
1509
|
+
if (oldValue === newValue) return;
|
|
1510
|
+
const value = newValue ?? "";
|
|
1511
|
+
reflectControlValue(
|
|
1512
|
+
this.querySelector(
|
|
1513
|
+
".ody-inline-input__field, .ody-inline-input__textarea"
|
|
1514
|
+
),
|
|
1515
|
+
value
|
|
1516
|
+
);
|
|
1517
|
+
this.#syncCounter(value);
|
|
1518
|
+
this.#syncClearButton(value);
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1521
|
+
super.attributeChangedCallback();
|
|
1522
|
+
}
|
|
1458
1523
|
render() {
|
|
1459
1524
|
const size = this.attr("size", "base");
|
|
1460
1525
|
const isTextarea = this.flag("textarea");
|
|
@@ -1484,8 +1549,7 @@ var OdyInlineInput = class extends OdyElement {
|
|
|
1484
1549
|
`ody-inline-input__group--${size}`
|
|
1485
1550
|
);
|
|
1486
1551
|
const field = isTextarea ? `<textarea class="ody-inline-input__textarea" rows="3"${maxlengthAttr}${isReadonly ? " readonly" : ""}${isDisabled ? " disabled" : ""}>${this.esc(value)}</textarea>` : `<input class="ody-inline-input__field" type="text" value="${this.esc(value)}" placeholder="${this.esc(this.attr("placeholder"))}"${maxlengthAttr}${isReadonly ? " readonly" : ""}${isDisabled ? " disabled" : ""} />`;
|
|
1487
|
-
const
|
|
1488
|
-
const clearEl = clearEnabled ? `<button type="button" class="btn ody-inline-input__clear-button" aria-label="${this.localized("clear-label", "clear")}">${iconSvg("close", "icon__svg clear-icon")}</button>` : "";
|
|
1552
|
+
const clearEl = this.#clearEnabled(value) ? this.#clearButtonHtml() : "";
|
|
1489
1553
|
const showCounter = !isReadonly && !isDisabled && maxlength !== "";
|
|
1490
1554
|
const footerNeeded = showCounter || caption !== "" || warning !== "" || info !== "";
|
|
1491
1555
|
const footer = footerNeeded ? `<div class="ody-inline-input-footer"><div class="ody-inline-input-footer__message">` + (caption ? `<span class="ody-inline-input-footer__message__caption">${this.esc(caption)}</span>` : "") + (warning ? `<span class="ody-inline-input-footer__message__warning">${this.esc(warning)}</span>` : "") + (info ? `<span class="ody-inline-input-footer__message__info">${this.esc(info)}</span>` : "") + `</div>` + (showCounter ? `<div class="ody-inline-input-footer__length-message">${value.length} / ${this.esc(maxlength)}</div>` : "") + `</div>` : "";
|
|
@@ -1502,7 +1566,6 @@ var OdyInlineInput = class extends OdyElement {
|
|
|
1502
1566
|
#onInput = (event) => {
|
|
1503
1567
|
event.stopPropagation();
|
|
1504
1568
|
const value = event.target.value;
|
|
1505
|
-
this.#syncCounter(value);
|
|
1506
1569
|
this.value = value;
|
|
1507
1570
|
this.dispatchEvent(new CustomEvent("input", { detail: { value }, bubbles: true }));
|
|
1508
1571
|
};
|
|
@@ -1521,6 +1584,26 @@ var OdyInlineInput = class extends OdyElement {
|
|
|
1521
1584
|
const max = this.attr("maxlength");
|
|
1522
1585
|
if (counter && max) counter.textContent = `${value.length} / ${max}`;
|
|
1523
1586
|
}
|
|
1587
|
+
/** Whether the clear button should be shown for the given value. */
|
|
1588
|
+
#clearEnabled(value) {
|
|
1589
|
+
return !this.flag("no-clear") && !this.flag("disabled") && !this.flag("readonly") && value !== "";
|
|
1590
|
+
}
|
|
1591
|
+
/** Markup for the clear button (shared by render and the in-place sync). */
|
|
1592
|
+
#clearButtonHtml() {
|
|
1593
|
+
return `<button type="button" class="btn ody-inline-input__clear-button" aria-label="${this.localized("clear-label", "clear")}">${iconSvg("close", "icon__svg clear-icon")}</button>`;
|
|
1594
|
+
}
|
|
1595
|
+
/** Add or remove the clear button in place as the value gains/loses content. */
|
|
1596
|
+
#syncClearButton(value) {
|
|
1597
|
+
const existing = this.querySelector(".ody-inline-input__clear-button");
|
|
1598
|
+
if (this.#clearEnabled(value)) {
|
|
1599
|
+
if (existing) return;
|
|
1600
|
+
const control = this.querySelector(".ody-inline-input__field, .ody-inline-input__textarea");
|
|
1601
|
+
control?.insertAdjacentHTML("afterend", this.#clearButtonHtml());
|
|
1602
|
+
this.querySelector(".ody-inline-input__clear-button")?.addEventListener("click", this.#onClear);
|
|
1603
|
+
} else {
|
|
1604
|
+
existing?.remove();
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1524
1607
|
};
|
|
1525
1608
|
define("ody-inline-input", OdyInlineInput);
|
|
1526
1609
|
|
|
@@ -1544,6 +1627,20 @@ var OdySearchInput = class extends OdyElement {
|
|
|
1544
1627
|
this.#value = next;
|
|
1545
1628
|
this.setAttribute("value", next);
|
|
1546
1629
|
}
|
|
1630
|
+
/**
|
|
1631
|
+
* Reflect `value` into the live control in place — the native field already
|
|
1632
|
+
* shows what the user typed, so rebuilding it (as a full re-render would)
|
|
1633
|
+
* needlessly drops focus, caret and the `--focused` state. Every other
|
|
1634
|
+
* observed attribute changes the chrome and still re-renders via the base.
|
|
1635
|
+
*/
|
|
1636
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
1637
|
+
if (name === "value") {
|
|
1638
|
+
if (oldValue === newValue) return;
|
|
1639
|
+
reflectControlValue(this.querySelector(".ody-input__field"), newValue ?? "");
|
|
1640
|
+
return;
|
|
1641
|
+
}
|
|
1642
|
+
super.attributeChangedCallback();
|
|
1643
|
+
}
|
|
1547
1644
|
render() {
|
|
1548
1645
|
const size = this.attr("size", "base");
|
|
1549
1646
|
const isDisabled = this.flag("disabled");
|