Use listen() helper across more components
This commit is contained in:
parent
dec5f8f1d2
commit
929a6585f0
@ -3,43 +3,43 @@
|
|||||||
.petty-stagger-hidden { opacity: 0; }
|
.petty-stagger-hidden { opacity: 0; }
|
||||||
|
|
||||||
.petty-stagger-fade-up {
|
.petty-stagger-fade-up {
|
||||||
animation: pettyFadeUp 0.5s ease both;
|
animation: pettyFadeUp 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-stagger-fade-down {
|
.petty-stagger-fade-down {
|
||||||
animation: pettyFadeDown 0.5s ease both;
|
animation: pettyFadeDown 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-stagger-fade-left {
|
.petty-stagger-fade-left {
|
||||||
animation: pettyFadeLeft 0.5s ease both;
|
animation: pettyFadeLeft 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-stagger-fade-right {
|
.petty-stagger-fade-right {
|
||||||
animation: pettyFadeRight 0.5s ease both;
|
animation: pettyFadeRight 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-stagger-scale {
|
.petty-stagger-scale {
|
||||||
animation: pettyScale 0.5s ease both;
|
animation: pettyScale 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-stagger-blur {
|
.petty-stagger-blur {
|
||||||
animation: pettyBlur 0.6s ease both;
|
animation: pettyBlur 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.petty-reveal-hidden { opacity: 0; }
|
.petty-reveal-hidden { opacity: 0; }
|
||||||
|
|
||||||
.petty-reveal-fade-up {
|
.petty-reveal-fade-up {
|
||||||
animation: pettyFadeUp 0.6s ease both;
|
animation: pettyFadeUp 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-reveal-fade-down {
|
.petty-reveal-fade-down {
|
||||||
animation: pettyFadeDown 0.6s ease both;
|
animation: pettyFadeDown 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-reveal-fade-left {
|
.petty-reveal-fade-left {
|
||||||
animation: pettyFadeLeft 0.6s ease both;
|
animation: pettyFadeLeft 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-reveal-fade-right {
|
.petty-reveal-fade-right {
|
||||||
animation: pettyFadeRight 0.6s ease both;
|
animation: pettyFadeRight 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-reveal-scale {
|
.petty-reveal-scale {
|
||||||
animation: pettyScale 0.6s ease both;
|
animation: pettyScale 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
.petty-reveal-blur {
|
.petty-reveal-blur {
|
||||||
animation: pettyBlur 0.7s ease both;
|
animation: pettyBlur 0.5s cubic-bezier(0.2, 0, 0, 1) both;
|
||||||
}
|
}
|
||||||
|
|
||||||
petty-typewriter.petty-typewriter-cursor::after {
|
petty-typewriter.petty-typewriter-cursor::after {
|
||||||
@ -82,7 +82,7 @@ petty-counter { font-variant-numeric: tabular-nums; }
|
|||||||
}
|
}
|
||||||
|
|
||||||
dialog[open] {
|
dialog[open] {
|
||||||
animation: pettyDialogIn 0.2s ease;
|
animation: pettyDialogIn 0.2s cubic-bezier(0.2, 0, 0, 1);
|
||||||
}
|
}
|
||||||
@keyframes pettyDialogIn {
|
@keyframes pettyDialogIn {
|
||||||
from { opacity: 0; transform: translateY(8px) scale(0.98); }
|
from { opacity: 0; transform: translateY(8px) scale(0.98); }
|
||||||
@ -90,7 +90,7 @@ dialog[open] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[popover]:popover-open {
|
[popover]:popover-open {
|
||||||
animation: pettyPopoverIn 0.15s ease;
|
animation: pettyPopoverIn 0.15s cubic-bezier(0.2, 0, 0, 1);
|
||||||
}
|
}
|
||||||
@keyframes pettyPopoverIn {
|
@keyframes pettyPopoverIn {
|
||||||
from { opacity: 0; transform: translateY(-4px); }
|
from { opacity: 0; transform: translateY(-4px); }
|
||||||
@ -98,7 +98,7 @@ dialog[open] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-part="toast"] {
|
[data-part="toast"] {
|
||||||
animation: pettySlideIn 0.3s ease;
|
animation: pettySlideIn 0.3s cubic-bezier(0.2, 0, 0, 1);
|
||||||
}
|
}
|
||||||
@keyframes pettySlideIn {
|
@keyframes pettySlideIn {
|
||||||
from { opacity: 0; transform: translateX(100%); }
|
from { opacity: 0; transform: translateX(100%); }
|
||||||
@ -113,25 +113,10 @@ petty-loading-indicator [data-part="indicator"] {
|
|||||||
border: 3px solid rgba(54, 192, 241, 0.12);
|
border: 3px solid rgba(54, 192, 241, 0.12);
|
||||||
border-top-color: #36c0f1;
|
border-top-color: #36c0f1;
|
||||||
border-right-color: rgba(54, 192, 241, 0.4);
|
border-right-color: rgba(54, 192, 241, 0.4);
|
||||||
animation: pettyLoadSpin 1.1s linear infinite, pettyLoadPulse 2.2s ease-in-out infinite;
|
animation: pettyLoadSpin 0.9s linear infinite;
|
||||||
}
|
|
||||||
|
|
||||||
petty-loading-indicator [data-part="container"]::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
inset: -2px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
border-bottom-color: rgba(54, 192, 241, 0.2);
|
|
||||||
border-left-color: rgba(54, 192, 241, 0.1);
|
|
||||||
animation: pettyLoadSpin 2.4s linear infinite reverse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pettyLoadSpin {
|
@keyframes pettyLoadSpin {
|
||||||
to { rotate: 360deg; }
|
to { rotate: 360deg; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pettyLoadPulse {
|
|
||||||
0%, 100% { box-shadow: 0 0 8px rgba(54, 192, 241, 0.15); }
|
|
||||||
50% { box-shadow: 0 0 20px rgba(54, 192, 241, 0.35); }
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PettyAccordionItem — wraps a single `<details>` element within a PettyAccordion.
|
* PettyAccordionItem — wraps a single `<details>` element within a PettyAccordion.
|
||||||
*
|
*
|
||||||
@ -34,20 +36,18 @@ export class PettyAccordionItem extends HTMLElement {
|
|||||||
return this.querySelector("summary")?.textContent?.trim() ?? "";
|
return this.querySelector("summary")?.textContent?.trim() ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
this.#syncState();
|
this.#syncState();
|
||||||
this.#applyDisabled();
|
this.#applyDisabled();
|
||||||
const details = this.detailsElement;
|
this.#cleanup = listen(this.detailsElement, [["toggle", this.#handleToggle]]);
|
||||||
if (details) {
|
|
||||||
details.addEventListener("toggle", this.#handleToggle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
const details = this.detailsElement;
|
this.#cleanup();
|
||||||
details?.removeEventListener("toggle", this.#handleToggle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyAvatar — image with automatic fallback on load error. */
|
/** PettyAvatar — image with automatic fallback on load error. */
|
||||||
export class PettyAvatar extends HTMLElement {
|
export class PettyAvatar extends HTMLElement {
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { signal, effect } from "../../signals";
|
import { signal, effect } from "../../signals";
|
||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyCalendar — month grid with day selection and month navigation. */
|
/** PettyCalendar — month grid with day selection and month navigation. */
|
||||||
export class PettyCalendar extends HTMLElement {
|
export class PettyCalendar extends HTMLElement {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { uniqueId } from "../../shared/aria";
|
import { uniqueId } from "../../shared/aria";
|
||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyCombobox — searchable select with popover listbox and keyboard nav. */
|
/** PettyCombobox — searchable select with popover listbox and keyboard nav. */
|
||||||
export class PettyCombobox extends HTMLElement {
|
export class PettyCombobox extends HTMLElement {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyCommandPalette — search-driven command menu using native dialog. */
|
/** PettyCommandPalette — search-driven command menu using native dialog. */
|
||||||
export class PettyCommandPalette extends HTMLElement {
|
export class PettyCommandPalette extends HTMLElement {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyContextMenu — right-click menu using Popover API with keyboard nav. */
|
/** PettyContextMenu — right-click menu using Popover API with keyboard nav. */
|
||||||
export class PettyContextMenu extends HTMLElement {
|
export class PettyContextMenu extends HTMLElement {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyDatePicker — date input with calendar popover integration. */
|
/** PettyDatePicker — date input with calendar popover integration. */
|
||||||
export class PettyDatePicker extends HTMLElement {
|
export class PettyDatePicker extends HTMLElement {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyDropdownMenu — action menu built on the Popover API. */
|
/** PettyDropdownMenu — action menu built on the Popover API. */
|
||||||
export class PettyDropdownMenu extends HTMLElement {
|
export class PettyDropdownMenu extends HTMLElement {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
interface SchemaLike {
|
interface SchemaLike {
|
||||||
safeParse: (data: unknown) => {
|
safeParse: (data: unknown) => {
|
||||||
@ -37,18 +37,19 @@ export class PettyForm extends HTMLElement {
|
|||||||
this.#schema = schema;
|
this.#schema = schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
const form = this.querySelector("form");
|
const form = this.querySelector("form");
|
||||||
if (!form) return;
|
if (!form) return;
|
||||||
form.addEventListener("submit", this.#handleSubmit);
|
|
||||||
form.setAttribute("novalidate", "");
|
form.setAttribute("novalidate", "");
|
||||||
|
this.#cleanup = listen(form, [["submit", this.#handleSubmit]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
const form = this.querySelector("form");
|
this.#cleanup();
|
||||||
form?.removeEventListener("submit", this.#handleSubmit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#handleSubmit = (e: Event): void => {
|
#handleSubmit = (e: Event): void => {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyImage — image element with fallback display on load failure. */
|
/** PettyImage — image element with fallback display on load failure. */
|
||||||
export class PettyImage extends HTMLElement {
|
export class PettyImage extends HTMLElement {
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyLink — headless anchor wrapper with disabled and external support. */
|
/** PettyLink — headless anchor wrapper with disabled and external support. */
|
||||||
export class PettyLink extends HTMLElement {
|
export class PettyLink extends HTMLElement {
|
||||||
static observedAttributes = ["disabled", "external"];
|
static observedAttributes = ["disabled", "external"];
|
||||||
@ -6,13 +8,15 @@ export class PettyLink extends HTMLElement {
|
|||||||
return this.querySelector("a");
|
return this.querySelector("a");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
this.#sync();
|
this.#sync();
|
||||||
this.addEventListener("click", this.#handleClick);
|
this.#cleanup = listen(this, [["click", this.#handleClick]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.removeEventListener("click", this.#handleClick);
|
this.#cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(): void {
|
attributeChangedCallback(): void {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { signal, effect } from "../../signals";
|
import { signal, effect } from "../../signals";
|
||||||
import { emit, initialValue } from "../../shared/helpers";
|
import { emit, initialValue, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyListbox — inline selectable list with single or multiple selection. */
|
/** PettyListbox — inline selectable list with single or multiple selection. */
|
||||||
export class PettyListbox extends HTMLElement {
|
export class PettyListbox extends HTMLElement {
|
||||||
@ -27,18 +27,18 @@ export class PettyListbox extends HTMLElement {
|
|||||||
emit(this, "change", { value: this.#value.get() });
|
emit(this, "change", { value: this.#value.get() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
const init = initialValue(this);
|
const init = initialValue(this);
|
||||||
if (init) this.#value.set(init);
|
if (init) this.#value.set(init);
|
||||||
this.#stopEffect = effect(() => this.#syncChildren());
|
this.#stopEffect = effect(() => this.#syncChildren());
|
||||||
this.addEventListener("keydown", this.#onKeydown);
|
this.#cleanup = listen(this, [["keydown", this.#onKeydown], ["click", this.#onClick]]);
|
||||||
this.addEventListener("click", this.#onClick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.#stopEffect = null;
|
this.#stopEffect = null;
|
||||||
this.removeEventListener("keydown", this.#onKeydown);
|
this.#cleanup();
|
||||||
this.removeEventListener("click", this.#onClick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(name: string, _old: string | null, next: string | null): void {
|
attributeChangedCallback(name: string, _old: string | null, next: string | null): void {
|
||||||
@ -59,18 +59,19 @@ export class PettyListbox extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#onClick = (e: MouseEvent): void => {
|
#onClick = (e: Event): void => {
|
||||||
const opt = (e.target as HTMLElement).closest("petty-listbox-option");
|
const opt = (e.target as HTMLElement).closest("petty-listbox-option");
|
||||||
if (!opt || opt.hasAttribute("disabled")) return;
|
if (!opt || opt.hasAttribute("disabled")) return;
|
||||||
this.selectValue(opt.getAttribute("value") ?? "");
|
this.selectValue(opt.getAttribute("value") ?? "");
|
||||||
};
|
};
|
||||||
|
|
||||||
#onKeydown = (e: KeyboardEvent): void => {
|
#onKeydown = (e: Event): void => {
|
||||||
|
const ke = e as KeyboardEvent;
|
||||||
const items = this.#options();
|
const items = this.#options();
|
||||||
const active = document.activeElement as HTMLElement;
|
const active = document.activeElement as HTMLElement;
|
||||||
const idx = items.indexOf(active);
|
const idx = items.indexOf(active);
|
||||||
if (e.key === "ArrowDown") { e.preventDefault(); items[(idx + 1) % items.length]?.focus(); }
|
if (ke.key === "ArrowDown") { ke.preventDefault(); items[(idx + 1) % items.length]?.focus(); }
|
||||||
else if (e.key === "ArrowUp") { e.preventDefault(); items[(idx - 1 + items.length) % items.length]?.focus(); }
|
else if (ke.key === "ArrowUp") { ke.preventDefault(); items[(idx - 1 + items.length) % items.length]?.focus(); }
|
||||||
else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); if (active) this.selectValue(active.getAttribute("value") ?? ""); }
|
else if (ke.key === "Enter" || ke.key === " ") { ke.preventDefault(); if (active) this.selectValue(active.getAttribute("value") ?? ""); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyNavigationMenuItem — nav item with optional popover content on hover. */
|
/** PettyNavigationMenuItem — nav item with optional popover content on hover. */
|
||||||
export class PettyNavigationMenuItem extends HTMLElement {
|
export class PettyNavigationMenuItem extends HTMLElement {
|
||||||
#showTimer: ReturnType<typeof setTimeout> | null = null;
|
#showTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { signal } from "../../signals";
|
import { signal } from "../../signals";
|
||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen, part } from "../../shared/helpers";
|
||||||
import { uniqueId } from "../../shared/aria";
|
import { uniqueId } from "../../shared/aria";
|
||||||
|
|
||||||
/** PettyNumberField — numeric input with increment/decrement buttons and clamping. */
|
/** PettyNumberField — numeric input with increment/decrement buttons and clamping. */
|
||||||
@ -7,6 +7,7 @@ export class PettyNumberField extends HTMLElement {
|
|||||||
static observedAttributes = ["min", "max", "step", "value", "disabled", "name"];
|
static observedAttributes = ["min", "max", "step", "value", "disabled", "name"];
|
||||||
|
|
||||||
readonly #value = signal(0);
|
readonly #value = signal(0);
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
get value(): number { return this.#value.get(); }
|
get value(): number { return this.#value.get(); }
|
||||||
set value(v: number) { this.#applyValue(v); }
|
set value(v: number) { this.#applyValue(v); }
|
||||||
@ -18,18 +19,14 @@ export class PettyNumberField extends HTMLElement {
|
|||||||
this.#syncInput();
|
this.#syncInput();
|
||||||
this.#wireLabel();
|
this.#wireLabel();
|
||||||
|
|
||||||
input?.addEventListener("input", this.#onInput);
|
const c1 = listen(input, [["input", this.#onInput], ["keydown", this.#onKeydown as EventListener]]);
|
||||||
input?.addEventListener("keydown", this.#onKeydown);
|
const c2 = listen(part(this, "increment"), [["click", this.#onIncrement]]);
|
||||||
this.querySelector("[data-part=increment]")?.addEventListener("click", this.#onIncrement);
|
const c3 = listen(part(this, "decrement"), [["click", this.#onDecrement]]);
|
||||||
this.querySelector("[data-part=decrement]")?.addEventListener("click", this.#onDecrement);
|
this.#cleanup = () => { c1(); c2(); c3(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
const input = this.#input();
|
this.#cleanup();
|
||||||
input?.removeEventListener("input", this.#onInput);
|
|
||||||
input?.removeEventListener("keydown", this.#onKeydown);
|
|
||||||
this.querySelector("[data-part=increment]")?.removeEventListener("click", this.#onIncrement);
|
|
||||||
this.querySelector("[data-part=decrement]")?.removeEventListener("click", this.#onDecrement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(name: string, _old: string | null, next: string | null): void {
|
attributeChangedCallback(name: string, _old: string | null, next: string | null): void {
|
||||||
|
|||||||
@ -1,17 +1,19 @@
|
|||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyPaginationItem — single page button within a pagination component. */
|
/** PettyPaginationItem — single page button within a pagination component. */
|
||||||
export class PettyPaginationItem extends HTMLElement {
|
export class PettyPaginationItem extends HTMLElement {
|
||||||
static observedAttributes = ["value", "type", "disabled"];
|
static observedAttributes = ["value", "type", "disabled"];
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
this.setAttribute("role", "button");
|
this.setAttribute("role", "button");
|
||||||
this.setAttribute("tabindex", "0");
|
this.setAttribute("tabindex", "0");
|
||||||
this.addEventListener("click", this.#handleClick);
|
this.#cleanup = listen(this, [["click", this.#handleClick], ["keydown", this.#handleKeydown]]);
|
||||||
this.addEventListener("keydown", this.#handleKeydown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.removeEventListener("click", this.#handleClick);
|
this.#cleanup();
|
||||||
this.removeEventListener("keydown", this.#handleKeydown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(name: string): void {
|
attributeChangedCallback(name: string): void {
|
||||||
@ -35,7 +37,8 @@ export class PettyPaginationItem extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#handleClick = (): void => { this.#activate(); };
|
#handleClick = (): void => { this.#activate(); };
|
||||||
#handleKeydown = (e: KeyboardEvent): void => {
|
#handleKeydown = (e: Event): void => {
|
||||||
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); this.#activate(); }
|
const ke = e as KeyboardEvent;
|
||||||
|
if (ke.key === "Enter" || ke.key === " ") { ke.preventDefault(); this.#activate(); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { wrapIndex } from "../../shared/keyboard";
|
import { wrapIndex } from "../../shared/keyboard";
|
||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyRadioItem — single radio option within a petty-radio-group. */
|
/** PettyRadioItem — single radio option within a petty-radio-group. */
|
||||||
export class PettyRadioItem extends HTMLElement {
|
export class PettyRadioItem extends HTMLElement {
|
||||||
@ -7,17 +8,17 @@ export class PettyRadioItem extends HTMLElement {
|
|||||||
get value(): string { return this.getAttribute("value") ?? ""; }
|
get value(): string { return this.getAttribute("value") ?? ""; }
|
||||||
get disabled(): boolean { return this.hasAttribute("disabled"); }
|
get disabled(): boolean { return this.hasAttribute("disabled"); }
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
this.setAttribute("role", "radio");
|
this.setAttribute("role", "radio");
|
||||||
this.setAttribute("tabindex", "-1");
|
this.setAttribute("tabindex", "-1");
|
||||||
if (this.disabled) this.setAttribute("aria-disabled", "true");
|
if (this.disabled) this.setAttribute("aria-disabled", "true");
|
||||||
this.addEventListener("click", this.#handleClick);
|
this.#cleanup = listen(this, [["click", this.#handleClick], ["keydown", this.#handleKeydown]]);
|
||||||
this.addEventListener("keydown", this.#handleKeydown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.removeEventListener("click", this.#handleClick);
|
this.#cleanup();
|
||||||
this.removeEventListener("keydown", this.#handleKeydown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(name: string): void {
|
attributeChangedCallback(name: string): void {
|
||||||
@ -42,17 +43,18 @@ export class PettyRadioItem extends HTMLElement {
|
|||||||
this.focus();
|
this.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
#handleKeydown = (e: KeyboardEvent): void => {
|
#handleKeydown = (e: Event): void => {
|
||||||
|
const ke = e as KeyboardEvent;
|
||||||
const isVertical = this.closest("petty-radio-group")?.getAttribute("orientation") !== "horizontal";
|
const isVertical = this.closest("petty-radio-group")?.getAttribute("orientation") !== "horizontal";
|
||||||
const prev = isVertical ? "ArrowUp" : "ArrowLeft";
|
const prev = isVertical ? "ArrowUp" : "ArrowLeft";
|
||||||
const next = isVertical ? "ArrowDown" : "ArrowRight";
|
const next = isVertical ? "ArrowDown" : "ArrowRight";
|
||||||
if (e.key !== prev && e.key !== next && e.key !== " ") return;
|
if (ke.key !== prev && ke.key !== next && ke.key !== " ") return;
|
||||||
e.preventDefault();
|
ke.preventDefault();
|
||||||
if (e.key === " ") { this.#handleClick(); return; }
|
if (ke.key === " ") { this.#handleClick(); return; }
|
||||||
const items = this.#siblings();
|
const items = this.#siblings();
|
||||||
const idx = items.indexOf(this);
|
const idx = items.indexOf(this);
|
||||||
if (idx === -1) return;
|
if (idx === -1) return;
|
||||||
const delta = e.key === next ? 1 : -1;
|
const delta = ke.key === next ? 1 : -1;
|
||||||
const target = items[wrapIndex(idx, delta, items.length)];
|
const target = items[wrapIndex(idx, delta, items.length)];
|
||||||
if (target) {
|
if (target) {
|
||||||
this.#group()?.selectValue(target.value);
|
this.#group()?.selectValue(target.value);
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen, part, wireLabel } from "../../shared/helpers";
|
||||||
import { uniqueId } from "../../shared/aria";
|
|
||||||
|
|
||||||
/** PettySlider — range input wrapper with label, output, and change events. */
|
/** PettySlider — range input wrapper with label, output, and change events. */
|
||||||
export class PettySlider extends HTMLElement {
|
export class PettySlider extends HTMLElement {
|
||||||
static observedAttributes = ["min", "max", "step", "value", "disabled", "name", "orientation"];
|
static observedAttributes = ["min", "max", "step", "value", "disabled", "name", "orientation"];
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
get value(): number {
|
get value(): number {
|
||||||
return Number(this.#input()?.value ?? 0);
|
return Number(this.#input()?.value ?? 0);
|
||||||
}
|
}
|
||||||
@ -18,13 +19,13 @@ export class PettySlider extends HTMLElement {
|
|||||||
const input = this.#input();
|
const input = this.#input();
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
this.#syncAttrs();
|
this.#syncAttrs();
|
||||||
this.#wireLabel();
|
wireLabel(input, part(this, "label"), "petty-slider");
|
||||||
this.#syncOutput();
|
this.#syncOutput();
|
||||||
input.addEventListener("input", this.#handleInput);
|
this.#cleanup = listen(input, [["input", this.#handleInput]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.#input()?.removeEventListener("input", this.#handleInput);
|
this.#cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(): void {
|
attributeChangedCallback(): void {
|
||||||
@ -36,15 +37,6 @@ export class PettySlider extends HTMLElement {
|
|||||||
return this.querySelector("input[data-part=control]");
|
return this.querySelector("input[data-part=control]");
|
||||||
}
|
}
|
||||||
|
|
||||||
#wireLabel(): void {
|
|
||||||
const input = this.#input();
|
|
||||||
const label = this.querySelector("[data-part=label]");
|
|
||||||
if (input && label) {
|
|
||||||
if (!input.id) input.id = uniqueId("petty-slider");
|
|
||||||
(label as HTMLLabelElement).htmlFor = input.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#syncAttrs(): void {
|
#syncAttrs(): void {
|
||||||
const input = this.#input();
|
const input = this.#input();
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PettyTab — individual tab button within a petty-tabs component.
|
* PettyTab — individual tab button within a petty-tabs component.
|
||||||
*
|
*
|
||||||
@ -19,17 +21,17 @@ export class PettyTab extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
this.setAttribute("role", "tab");
|
this.setAttribute("role", "tab");
|
||||||
this.setAttribute("tabindex", "-1");
|
this.setAttribute("tabindex", "-1");
|
||||||
this.addEventListener("click", this.#handleClick);
|
this.#cleanup = listen(this, [["click", this.#handleClick], ["keydown", this.#handleKeydown]]);
|
||||||
this.addEventListener("keydown", this.#handleKeydown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.removeEventListener("click", this.#handleClick);
|
this.#cleanup();
|
||||||
this.removeEventListener("keydown", this.#handleKeydown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@ -48,12 +50,13 @@ export class PettyTab extends HTMLElement {
|
|||||||
active?.focus();
|
active?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
#handleKeydown = (e: KeyboardEvent): void => {
|
#handleKeydown = (e: Event): void => {
|
||||||
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
|
const ke = e as KeyboardEvent;
|
||||||
|
if (ke.key !== "ArrowLeft" && ke.key !== "ArrowRight") return;
|
||||||
const tabs = this.#siblingTabs().filter(t => !t.disabled);
|
const tabs = this.#siblingTabs().filter(t => !t.disabled);
|
||||||
const idx = tabs.indexOf(this);
|
const idx = tabs.indexOf(this);
|
||||||
if (idx === -1) return;
|
if (idx === -1) return;
|
||||||
const nextIdx = e.key === "ArrowRight"
|
const nextIdx = ke.key === "ArrowRight"
|
||||||
? (idx + 1) % tabs.length
|
? (idx + 1) % tabs.length
|
||||||
: (idx - 1 + tabs.length) % tabs.length;
|
: (idx - 1 + tabs.length) % tabs.length;
|
||||||
const next = tabs[nextIdx];
|
const next = tabs[nextIdx];
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { signal, effect } from "../../signals";
|
import { signal, effect } from "../../signals";
|
||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyTagsInput — multi-value text input for tags, emails, or tokens. */
|
/** PettyTagsInput — multi-value text input for tags, emails, or tokens. */
|
||||||
export class PettyTagsInput extends HTMLElement {
|
export class PettyTagsInput extends HTMLElement {
|
||||||
@ -41,18 +41,21 @@ export class PettyTagsInput extends HTMLElement {
|
|||||||
this.#dispatch();
|
this.#dispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cleanupInput = (): void => {};
|
||||||
|
#cleanupSelf = (): void => {};
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
const init = this.getAttribute("value");
|
const init = this.getAttribute("value");
|
||||||
if (init) this.#tags.set(init.split(",").map(s => s.trim()).filter(Boolean));
|
if (init) this.#tags.set(init.split(",").map(s => s.trim()).filter(Boolean));
|
||||||
this.#stopEffect = effect(() => this.#render());
|
this.#stopEffect = effect(() => this.#render());
|
||||||
this.#input()?.addEventListener("keydown", this.#onKeydown);
|
this.#cleanupInput = listen(this.#input(), [["keydown", this.#onKeydown]]);
|
||||||
this.addEventListener("click", this.#onTagRemove);
|
this.#cleanupSelf = listen(this, [["click", this.#onTagRemove]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.#stopEffect = null;
|
this.#stopEffect = null;
|
||||||
this.#input()?.removeEventListener("keydown", this.#onKeydown);
|
this.#cleanupInput();
|
||||||
this.removeEventListener("click", this.#onTagRemove);
|
this.#cleanupSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(name: string, _old: string | null, next: string | null): void {
|
attributeChangedCallback(name: string, _old: string | null, next: string | null): void {
|
||||||
@ -73,14 +76,15 @@ export class PettyTagsInput extends HTMLElement {
|
|||||||
if (hidden instanceof HTMLInputElement) hidden.value = this.#tags.get().join(",");
|
if (hidden instanceof HTMLInputElement) hidden.value = this.#tags.get().join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
#onKeydown = (e: KeyboardEvent): void => {
|
#onKeydown = (e: Event): void => {
|
||||||
|
const ke = e as KeyboardEvent;
|
||||||
if (this.hasAttribute("disabled")) return;
|
if (this.hasAttribute("disabled")) return;
|
||||||
const input = this.#input();
|
const input = this.#input();
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
if (e.key === "Enter" || e.key === ",") {
|
if (ke.key === "Enter" || ke.key === ",") {
|
||||||
e.preventDefault();
|
ke.preventDefault();
|
||||||
if (this.addTag(input.value)) input.value = "";
|
if (this.addTag(input.value)) input.value = "";
|
||||||
} else if (e.key === "Backspace" && input.value === "") {
|
} else if (ke.key === "Backspace" && input.value === "") {
|
||||||
const tags = this.#tags.get();
|
const tags = this.#tags.get();
|
||||||
const last = tags[tags.length - 1];
|
const last = tags[tags.length - 1];
|
||||||
if (last) this.removeTag(last);
|
if (last) this.removeTag(last);
|
||||||
|
|||||||
@ -1,20 +1,22 @@
|
|||||||
import { uniqueId } from "../../shared/aria";
|
import { uniqueId } from "../../shared/aria";
|
||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen, part } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyTextField — labeled text input with description and error wiring. */
|
/** PettyTextField — labeled text input with description and error wiring. */
|
||||||
export class PettyTextField extends HTMLElement {
|
export class PettyTextField extends HTMLElement {
|
||||||
static observedAttributes = ["name", "disabled", "required"];
|
static observedAttributes = ["name", "disabled", "required"];
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
const name = this.getAttribute("name") ?? "";
|
const name = this.getAttribute("name") ?? "";
|
||||||
const controlId = uniqueId(`petty-tf-${name}`);
|
const controlId = uniqueId(`petty-tf-${name}`);
|
||||||
const errorId = `${controlId}-error`;
|
const errorId = `${controlId}-error`;
|
||||||
const descId = `${controlId}-desc`;
|
const descId = `${controlId}-desc`;
|
||||||
|
|
||||||
const label = this.querySelector("[data-part=label]");
|
const label = part<HTMLLabelElement>(this, "label");
|
||||||
const control = this.#control();
|
const control = this.#control();
|
||||||
const desc = this.querySelector("[data-part=description]");
|
const desc = part(this, "description");
|
||||||
const error = this.querySelector("[data-part=error]");
|
const error = part(this, "error");
|
||||||
|
|
||||||
if (control) {
|
if (control) {
|
||||||
control.id = controlId;
|
control.id = controlId;
|
||||||
@ -22,16 +24,16 @@ export class PettyTextField extends HTMLElement {
|
|||||||
const describedBy = [desc ? descId : "", error ? errorId : ""].filter(Boolean).join(" ");
|
const describedBy = [desc ? descId : "", error ? errorId : ""].filter(Boolean).join(" ");
|
||||||
if (describedBy) control.setAttribute("aria-describedby", describedBy);
|
if (describedBy) control.setAttribute("aria-describedby", describedBy);
|
||||||
}
|
}
|
||||||
if (label && control) (label as HTMLLabelElement).htmlFor = controlId;
|
if (label && control) label.htmlFor = controlId;
|
||||||
if (desc) desc.id = descId;
|
if (desc) desc.id = descId;
|
||||||
if (error) error.id = errorId;
|
if (error) error.id = errorId;
|
||||||
|
|
||||||
this.#syncAttrs();
|
this.#syncAttrs();
|
||||||
control?.addEventListener("input", this.#handleInput);
|
this.#cleanup = listen(control, [["input", this.#handleInput]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.#control()?.removeEventListener("input", this.#handleInput);
|
this.#cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(): void {
|
attributeChangedCallback(): void {
|
||||||
@ -40,7 +42,7 @@ export class PettyTextField extends HTMLElement {
|
|||||||
|
|
||||||
/** Display an error message on this field. */
|
/** Display an error message on this field. */
|
||||||
setError(message: string): void {
|
setError(message: string): void {
|
||||||
const error = this.querySelector("[data-part=error]");
|
const error = part(this, "error");
|
||||||
const control = this.#control();
|
const control = this.#control();
|
||||||
if (error) error.textContent = message;
|
if (error) error.textContent = message;
|
||||||
if (control) control.setAttribute("aria-invalid", "true");
|
if (control) control.setAttribute("aria-invalid", "true");
|
||||||
@ -48,7 +50,7 @@ export class PettyTextField extends HTMLElement {
|
|||||||
|
|
||||||
/** Clear the error message on this field. */
|
/** Clear the error message on this field. */
|
||||||
clearError(): void {
|
clearError(): void {
|
||||||
const error = this.querySelector("[data-part=error]");
|
const error = part(this, "error");
|
||||||
const control = this.#control();
|
const control = this.#control();
|
||||||
if (error) error.textContent = "";
|
if (error) error.textContent = "";
|
||||||
if (control) control.removeAttribute("aria-invalid");
|
if (control) control.removeAttribute("aria-invalid");
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { wrapIndex } from "../../shared/keyboard";
|
import { wrapIndex } from "../../shared/keyboard";
|
||||||
|
import { listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyToggleGroupItem — single item within a toggle group. */
|
/** PettyToggleGroupItem — single item within a toggle group. */
|
||||||
export class PettyToggleGroupItem extends HTMLElement {
|
export class PettyToggleGroupItem extends HTMLElement {
|
||||||
@ -7,17 +8,17 @@ export class PettyToggleGroupItem extends HTMLElement {
|
|||||||
get value(): string { return this.getAttribute("value") ?? ""; }
|
get value(): string { return this.getAttribute("value") ?? ""; }
|
||||||
get disabled(): boolean { return this.hasAttribute("disabled"); }
|
get disabled(): boolean { return this.hasAttribute("disabled"); }
|
||||||
|
|
||||||
|
#cleanup = (): void => {};
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
this.setAttribute("role", "button");
|
this.setAttribute("role", "button");
|
||||||
this.setAttribute("tabindex", "0");
|
this.setAttribute("tabindex", "0");
|
||||||
if (this.disabled) this.setAttribute("aria-disabled", "true");
|
if (this.disabled) this.setAttribute("aria-disabled", "true");
|
||||||
this.addEventListener("click", this.#handleClick);
|
this.#cleanup = listen(this, [["click", this.#handleClick], ["keydown", this.#handleKeydown]]);
|
||||||
this.addEventListener("keydown", this.#handleKeydown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.removeEventListener("click", this.#handleClick);
|
this.#cleanup();
|
||||||
this.removeEventListener("keydown", this.#handleKeydown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(name: string): void {
|
attributeChangedCallback(name: string): void {
|
||||||
@ -39,21 +40,22 @@ export class PettyToggleGroupItem extends HTMLElement {
|
|||||||
this.#group()?.toggleValue(this.value);
|
this.#group()?.toggleValue(this.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
#handleKeydown = (e: KeyboardEvent): void => {
|
#handleKeydown = (e: Event): void => {
|
||||||
if (e.key === " " || e.key === "Enter") {
|
const ke = e as KeyboardEvent;
|
||||||
e.preventDefault();
|
if (ke.key === " " || ke.key === "Enter") {
|
||||||
|
ke.preventDefault();
|
||||||
this.#handleClick();
|
this.#handleClick();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const isHorizontal = this.closest("petty-toggle-group")?.getAttribute("orientation") !== "vertical";
|
const isHorizontal = this.closest("petty-toggle-group")?.getAttribute("orientation") !== "vertical";
|
||||||
const prev = isHorizontal ? "ArrowLeft" : "ArrowUp";
|
const prev = isHorizontal ? "ArrowLeft" : "ArrowUp";
|
||||||
const next = isHorizontal ? "ArrowRight" : "ArrowDown";
|
const next = isHorizontal ? "ArrowRight" : "ArrowDown";
|
||||||
if (e.key !== prev && e.key !== next) return;
|
if (ke.key !== prev && ke.key !== next) return;
|
||||||
e.preventDefault();
|
ke.preventDefault();
|
||||||
const items = this.#siblings();
|
const items = this.#siblings();
|
||||||
const idx = items.indexOf(this);
|
const idx = items.indexOf(this);
|
||||||
if (idx === -1) return;
|
if (idx === -1) return;
|
||||||
const delta = e.key === next ? 1 : -1;
|
const delta = ke.key === next ? 1 : -1;
|
||||||
items[wrapIndex(idx, delta, items.length)]?.focus();
|
items[wrapIndex(idx, delta, items.length)]?.focus();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { emit } from "../../shared/helpers";
|
import { emit, listen } from "../../shared/helpers";
|
||||||
|
|
||||||
/** PettyVirtualList — windowed scroll rendering only visible items plus overscan. */
|
/** PettyVirtualList — windowed scroll rendering only visible items plus overscan. */
|
||||||
export class PettyVirtualList extends HTMLElement {
|
export class PettyVirtualList extends HTMLElement {
|
||||||
|
|||||||
@ -46,7 +46,6 @@ dialog {
|
|||||||
|
|
||||||
dialog::backdrop {
|
dialog::backdrop {
|
||||||
background: rgba(0 0 0 / 0.4);
|
background: rgba(0 0 0 / 0.4);
|
||||||
backdrop-filter: blur(2px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Select ─────────────────────────────────────────────────────────────── */
|
/* ── Select ─────────────────────────────────────────────────────────────── */
|
||||||
@ -234,7 +233,13 @@ petty-toast-region {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
padding: 0.125rem 0.25rem;
|
padding: 0.5rem;
|
||||||
|
min-width: 2.75rem;
|
||||||
|
min-height: 2.75rem;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: var(--petty-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-part="toast-close"]:hover { color: var(--petty-text); }
|
[data-part="toast-close"]:hover { color: var(--petty-text); }
|
||||||
@ -265,10 +270,11 @@ petty-form-field {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-part="control"]:focus {
|
[data-part="control"]:focus-visible {
|
||||||
border-color: var(--petty-border-focus);
|
border-color: var(--petty-border-focus);
|
||||||
box-shadow: 0 0 0 3px rgba(37 99 235 / 0.15);
|
box-shadow: 0 0 0 3px rgba(37 99 235 / 0.15);
|
||||||
outline: none;
|
outline: 2px solid var(--petty-border-focus);
|
||||||
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-part="control"][aria-invalid="true"] {
|
[data-part="control"][aria-invalid="true"] {
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<title>PettyUI — Component Showcase</title>
|
<title>PettyUI — Component Showcase</title>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import "pettyui/button"; import "pettyui/link"; import "pettyui/separator";
|
import "pettyui/button"; import "pettyui/link"; import "pettyui/separator";
|
||||||
import "pettyui/badge"; import "pettyui/skeleton"; import "pettyui/avatar";
|
import "pettyui/badge"; import "pettyui/skeleton"; import "pettyui/avatar";
|
||||||
@ -88,7 +88,7 @@
|
|||||||
<h3>Text Field</h3>
|
<h3>Text Field</h3>
|
||||||
<petty-text-field name="email">
|
<petty-text-field name="email">
|
||||||
<label data-part="label">Email address</label>
|
<label data-part="label">Email address</label>
|
||||||
<input data-part="control" type="email" placeholder="you@example.com" />
|
<input data-part="control" type="email" placeholder="you@example.com" aria-label="Email address" />
|
||||||
<span data-part="description">We will never share your email.</span>
|
<span data-part="description">We will never share your email.</span>
|
||||||
<span data-part="error"></span>
|
<span data-part="error"></span>
|
||||||
</petty-text-field>
|
</petty-text-field>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user