@f-ewald/components 1.16.0 → 1.17.0

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.
@@ -0,0 +1,59 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * A thin, generic wrapper around a `mapboxgl.Map` — construction, access
4
+ * token, style loading/switching, and container resizing only. It carries no
5
+ * domain logic: no layer registry, no click-handler system, no markers or
6
+ * popups. A consumer registers its own sources/layers/handlers against the
7
+ * `mapboxgl.Map` instance handed back on `map-ready`, the same instance
8
+ * `mapbox-map` continues to own (this component never calls `map.remove()`
9
+ * except on disconnect, so a consumer's own registrations survive style
10
+ * reloads exactly as they would using `mapboxgl.Map` directly).
11
+ *
12
+ * Deliberately does not construct the map until `styleUrl` is a non-empty
13
+ * string — if a consumer knows the desired style only after an async
14
+ * lookup (e.g. a saved user preference), delay setting `styleUrl` rather
15
+ * than setting a default and swapping it later, which would visibly flash
16
+ * the wrong basemap before the real one loads.
17
+ *
18
+ * @element mapbox-map
19
+ * @fires map-ready - The map (and, if `styleUrl` changed before the initial
20
+ * load finished, its final requested style) has finished loading;
21
+ * detail: `{ map: mapboxgl.Map }`.
22
+ * @fires map-style-reloaded - A subsequent `styleUrl` change finished
23
+ * loading its new style (sources/layers registered by a consumer via the
24
+ * `map-ready` instance do not survive a style change and must be
25
+ * re-registered — same behavior as calling `map.setStyle()` directly);
26
+ * detail: `{ map: mapboxgl.Map }`.
27
+ */
28
+ export declare class MapboxMap extends LitElement {
29
+ #private;
30
+ static styles: import("lit").CSSResult[];
31
+ /** Mapbox access token. Required before the map can be constructed. */
32
+ accessToken: string;
33
+ /**
34
+ * Style URL (e.g. `mapbox://styles/mapbox/light-v11`). The map is not
35
+ * constructed until this is a non-empty string — see the class doc.
36
+ */
37
+ styleUrl: string;
38
+ /** Initial center as `[lng, lat]`. Only read at construction time. */
39
+ center: [number, number];
40
+ /** Initial zoom level. Only read at construction time. */
41
+ zoom: number;
42
+ private mapContainer;
43
+ private map?;
44
+ private mapLoaded;
45
+ private currentStyleUrl?;
46
+ private resizeObserver?;
47
+ /** The live `mapboxgl.Map` instance, once constructed (also available via `map-ready`'s event detail). */
48
+ getMap(): mapboxgl.Map | undefined;
49
+ protected firstUpdated(): void;
50
+ protected updated(changed: Map<PropertyKey, unknown>): void;
51
+ disconnectedCallback(): void;
52
+ render(): import("lit-html").TemplateResult<1>;
53
+ }
54
+ declare global {
55
+ interface HTMLElementTagNameMap {
56
+ "mapbox-map": MapboxMap;
57
+ }
58
+ }
59
+ //# sourceMappingURL=mapbox-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapbox-map.d.ts","sourceRoot":"","sources":["../src/mapbox-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAO5C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBACa,SAAU,SAAQ,UAAU;;IACvC,OAAgB,MAAM,4BAcpB;IAEF,uEAAuE;IAC9B,WAAW,SAAM;IAC1D;;;OAGG;IACmC,QAAQ,SAAM;IACpD,sEAAsE;IACtC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAU;IAClE,0DAA0D;IAC9B,IAAI,SAAK;IAEtB,OAAO,CAAC,YAAY,CAAkB;IAErD,OAAO,CAAC,GAAG,CAAC,CAAe;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,cAAc,CAAC,CAAiB;IAExC,0GAA0G;IAC1G,MAAM,IAAI,QAAQ,CAAC,GAAG,GAAG,SAAS,CAEjC;IAED,UAAmB,YAAY,IAAI,IAAI,CAItC;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,GAAG,IAAI,CAYnE;IA4BQ,oBAAoB,IAAI,IAAI,CAIpC;IAEQ,MAAM,yCAKd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,SAAS,CAAC;KACzB;CACF"}
@@ -0,0 +1,144 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement, css, html } from "lit";
8
+ import { customElement, property, query } from "lit/decorators.js";
9
+ import mapboxgl from "mapbox-gl";
10
+ import { tokens } from "./tokens.js";
11
+ const MAPBOX_GL_VERSION = "3.9.0";
12
+ /**
13
+ * A thin, generic wrapper around a `mapboxgl.Map` — construction, access
14
+ * token, style loading/switching, and container resizing only. It carries no
15
+ * domain logic: no layer registry, no click-handler system, no markers or
16
+ * popups. A consumer registers its own sources/layers/handlers against the
17
+ * `mapboxgl.Map` instance handed back on `map-ready`, the same instance
18
+ * `mapbox-map` continues to own (this component never calls `map.remove()`
19
+ * except on disconnect, so a consumer's own registrations survive style
20
+ * reloads exactly as they would using `mapboxgl.Map` directly).
21
+ *
22
+ * Deliberately does not construct the map until `styleUrl` is a non-empty
23
+ * string — if a consumer knows the desired style only after an async
24
+ * lookup (e.g. a saved user preference), delay setting `styleUrl` rather
25
+ * than setting a default and swapping it later, which would visibly flash
26
+ * the wrong basemap before the real one loads.
27
+ *
28
+ * @element mapbox-map
29
+ * @fires map-ready - The map (and, if `styleUrl` changed before the initial
30
+ * load finished, its final requested style) has finished loading;
31
+ * detail: `{ map: mapboxgl.Map }`.
32
+ * @fires map-style-reloaded - A subsequent `styleUrl` change finished
33
+ * loading its new style (sources/layers registered by a consumer via the
34
+ * `map-ready` instance do not survive a style change and must be
35
+ * re-registered — same behavior as calling `map.setStyle()` directly);
36
+ * detail: `{ map: mapboxgl.Map }`.
37
+ */
38
+ let MapboxMap = class MapboxMap extends LitElement {
39
+ constructor() {
40
+ super(...arguments);
41
+ /** Mapbox access token. Required before the map can be constructed. */
42
+ this.accessToken = "";
43
+ /**
44
+ * Style URL (e.g. `mapbox://styles/mapbox/light-v11`). The map is not
45
+ * constructed until this is a non-empty string — see the class doc.
46
+ */
47
+ this.styleUrl = "";
48
+ /** Initial center as `[lng, lat]`. Only read at construction time. */
49
+ this.center = [0, 0];
50
+ /** Initial zoom level. Only read at construction time. */
51
+ this.zoom = 0;
52
+ this.mapLoaded = false;
53
+ }
54
+ static { this.styles = [
55
+ tokens,
56
+ css `
57
+ :host {
58
+ display: block;
59
+ position: relative;
60
+ width: 100%;
61
+ height: 100%;
62
+ }
63
+ #map {
64
+ width: 100%;
65
+ height: 100%;
66
+ }
67
+ `,
68
+ ]; }
69
+ /** The live `mapboxgl.Map` instance, once constructed (also available via `map-ready`'s event detail). */
70
+ getMap() {
71
+ return this.map;
72
+ }
73
+ firstUpdated() {
74
+ this.resizeObserver = new ResizeObserver(() => this.map?.resize());
75
+ this.resizeObserver.observe(this);
76
+ if (this.accessToken && this.styleUrl)
77
+ this.#initializeMap();
78
+ }
79
+ updated(changed) {
80
+ if ((changed.has("accessToken") || changed.has("styleUrl")) && !this.map && this.accessToken && this.styleUrl) {
81
+ this.#initializeMap();
82
+ return;
83
+ }
84
+ if (changed.has("styleUrl") && this.map && this.mapLoaded && this.styleUrl !== this.currentStyleUrl) {
85
+ this.currentStyleUrl = this.styleUrl;
86
+ this.map.setStyle(this.styleUrl);
87
+ this.map.once("style.load", () => this.dispatchEvent(new CustomEvent("map-style-reloaded", { detail: { map: this.map }, bubbles: true, composed: true })));
88
+ }
89
+ }
90
+ #initializeMap() {
91
+ mapboxgl.accessToken = this.accessToken;
92
+ this.currentStyleUrl = this.styleUrl;
93
+ this.map = new mapboxgl.Map({
94
+ container: this.mapContainer,
95
+ style: this.currentStyleUrl,
96
+ center: this.center,
97
+ zoom: this.zoom,
98
+ });
99
+ this.map.once("load", () => {
100
+ this.mapLoaded = true;
101
+ // `updated()`'s style-swap branch requires `mapLoaded` to already be
102
+ // true, so a `styleUrl` change that arrives between construction and
103
+ // this "load" event is not caught there — reconcile it here instead.
104
+ if (this.styleUrl !== this.currentStyleUrl) {
105
+ this.currentStyleUrl = this.styleUrl;
106
+ this.map?.setStyle(this.styleUrl);
107
+ this.map?.once("style.load", () => this.dispatchEvent(new CustomEvent("map-ready", { detail: { map: this.map }, bubbles: true, composed: true })));
108
+ return;
109
+ }
110
+ this.dispatchEvent(new CustomEvent("map-ready", { detail: { map: this.map }, bubbles: true, composed: true }));
111
+ });
112
+ }
113
+ disconnectedCallback() {
114
+ super.disconnectedCallback();
115
+ this.resizeObserver?.disconnect();
116
+ this.map?.remove();
117
+ }
118
+ render() {
119
+ return html `
120
+ <link href="https://api.mapbox.com/mapbox-gl-js/v${MAPBOX_GL_VERSION}/mapbox-gl.css" rel="stylesheet" />
121
+ <div id="map"></div>
122
+ `;
123
+ }
124
+ };
125
+ __decorate([
126
+ property({ attribute: "access-token" })
127
+ ], MapboxMap.prototype, "accessToken", void 0);
128
+ __decorate([
129
+ property({ attribute: "style-url" })
130
+ ], MapboxMap.prototype, "styleUrl", void 0);
131
+ __decorate([
132
+ property({ attribute: false })
133
+ ], MapboxMap.prototype, "center", void 0);
134
+ __decorate([
135
+ property({ type: Number })
136
+ ], MapboxMap.prototype, "zoom", void 0);
137
+ __decorate([
138
+ query("#map")
139
+ ], MapboxMap.prototype, "mapContainer", void 0);
140
+ MapboxMap = __decorate([
141
+ customElement("mapbox-map")
142
+ ], MapboxMap);
143
+ export { MapboxMap };
144
+ //# sourceMappingURL=mapbox-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapbox-map.js","sourceRoot":"","sources":["../src/mapbox-map.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property, query } from \"lit/decorators.js\";\nimport mapboxgl from \"mapbox-gl\";\nimport { tokens } from \"./tokens.js\";\n\nconst MAPBOX_GL_VERSION = \"3.9.0\";\n\n/**\n * A thin, generic wrapper around a `mapboxgl.Map` — construction, access\n * token, style loading/switching, and container resizing only. It carries no\n * domain logic: no layer registry, no click-handler system, no markers or\n * popups. A consumer registers its own sources/layers/handlers against the\n * `mapboxgl.Map` instance handed back on `map-ready`, the same instance\n * `mapbox-map` continues to own (this component never calls `map.remove()`\n * except on disconnect, so a consumer's own registrations survive style\n * reloads exactly as they would using `mapboxgl.Map` directly).\n *\n * Deliberately does not construct the map until `styleUrl` is a non-empty\n * string — if a consumer knows the desired style only after an async\n * lookup (e.g. a saved user preference), delay setting `styleUrl` rather\n * than setting a default and swapping it later, which would visibly flash\n * the wrong basemap before the real one loads.\n *\n * @element mapbox-map\n * @fires map-ready - The map (and, if `styleUrl` changed before the initial\n * load finished, its final requested style) has finished loading;\n * detail: `{ map: mapboxgl.Map }`.\n * @fires map-style-reloaded - A subsequent `styleUrl` change finished\n * loading its new style (sources/layers registered by a consumer via the\n * `map-ready` instance do not survive a style change and must be\n * re-registered — same behavior as calling `map.setStyle()` directly);\n * detail: `{ map: mapboxgl.Map }`.\n */\n@customElement(\"mapbox-map\")\nexport class MapboxMap extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n position: relative;\n width: 100%;\n height: 100%;\n }\n #map {\n width: 100%;\n height: 100%;\n }\n `,\n ];\n\n /** Mapbox access token. Required before the map can be constructed. */\n @property({ attribute: \"access-token\" }) accessToken = \"\";\n /**\n * Style URL (e.g. `mapbox://styles/mapbox/light-v11`). The map is not\n * constructed until this is a non-empty string — see the class doc.\n */\n @property({ attribute: \"style-url\" }) styleUrl = \"\";\n /** Initial center as `[lng, lat]`. Only read at construction time. */\n @property({ attribute: false }) center: [number, number] = [0, 0];\n /** Initial zoom level. Only read at construction time. */\n @property({ type: Number }) zoom = 0;\n\n @query(\"#map\") private mapContainer!: HTMLDivElement;\n\n private map?: mapboxgl.Map;\n private mapLoaded = false;\n private currentStyleUrl?: string;\n private resizeObserver?: ResizeObserver;\n\n /** The live `mapboxgl.Map` instance, once constructed (also available via `map-ready`'s event detail). */\n getMap(): mapboxgl.Map | undefined {\n return this.map;\n }\n\n protected override firstUpdated(): void {\n this.resizeObserver = new ResizeObserver(() => this.map?.resize());\n this.resizeObserver.observe(this);\n if (this.accessToken && this.styleUrl) this.#initializeMap();\n }\n\n protected override updated(changed: Map<PropertyKey, unknown>): void {\n if ((changed.has(\"accessToken\") || changed.has(\"styleUrl\")) && !this.map && this.accessToken && this.styleUrl) {\n this.#initializeMap();\n return;\n }\n if (changed.has(\"styleUrl\") && this.map && this.mapLoaded && this.styleUrl !== this.currentStyleUrl) {\n this.currentStyleUrl = this.styleUrl;\n this.map.setStyle(this.styleUrl);\n this.map.once(\"style.load\", () =>\n this.dispatchEvent(new CustomEvent(\"map-style-reloaded\", { detail: { map: this.map }, bubbles: true, composed: true })),\n );\n }\n }\n\n #initializeMap(): void {\n mapboxgl.accessToken = this.accessToken;\n this.currentStyleUrl = this.styleUrl;\n this.map = new mapboxgl.Map({\n container: this.mapContainer,\n style: this.currentStyleUrl,\n center: this.center,\n zoom: this.zoom,\n });\n this.map.once(\"load\", () => {\n this.mapLoaded = true;\n // `updated()`'s style-swap branch requires `mapLoaded` to already be\n // true, so a `styleUrl` change that arrives between construction and\n // this \"load\" event is not caught there — reconcile it here instead.\n if (this.styleUrl !== this.currentStyleUrl) {\n this.currentStyleUrl = this.styleUrl;\n this.map?.setStyle(this.styleUrl);\n this.map?.once(\"style.load\", () =>\n this.dispatchEvent(new CustomEvent(\"map-ready\", { detail: { map: this.map }, bubbles: true, composed: true })),\n );\n return;\n }\n this.dispatchEvent(new CustomEvent(\"map-ready\", { detail: { map: this.map }, bubbles: true, composed: true }));\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.resizeObserver?.disconnect();\n this.map?.remove();\n }\n\n override render() {\n return html`\n <link href=\"https://api.mapbox.com/mapbox-gl-js/v${MAPBOX_GL_VERSION}/mapbox-gl.css\" rel=\"stylesheet\" />\n <div id=\"map\"></div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"mapbox-map\": MapboxMap;\n }\n}\n"]}
@@ -0,0 +1,48 @@
1
+ import { LitElement, type PropertyValues } from "lit";
2
+ /**
3
+ * A form-associated numeric range slider, usable standalone or inside a
4
+ * native `<form>`. Wraps a native `<input type="range">` (kept for its free
5
+ * keyboard, drag, and screen-reader support) restyled to match this
6
+ * package's track/fill visual language (`stat-meter`, `percent-bar-chart`)
7
+ * instead of the browser-default appearance. Purely a value control — no
8
+ * built-in label; wrap in `form-field` for a labeled field, or render a
9
+ * value readout next to it (see the playground example), matching
10
+ * `autocomplete-input`/`form-select`.
11
+ *
12
+ * @element range-slider
13
+ * @fires input - Fires continuously while dragging/typing; detail: `{ value }`.
14
+ * @fires change - Fires once the value is committed (drag released, arrow
15
+ * key released); detail: `{ value }`.
16
+ */
17
+ export declare class RangeSlider extends LitElement {
18
+ #private;
19
+ static formAssociated: boolean;
20
+ static styles: import("lit").CSSResult[];
21
+ /** Minimum value. */
22
+ min: number;
23
+ /** Maximum value. */
24
+ max: number;
25
+ /** Step increment. */
26
+ step: number;
27
+ /** Current value. */
28
+ value: number;
29
+ /** Disables interaction; merged with an ancestor `<fieldset disabled>`. */
30
+ disabled: boolean;
31
+ /** Form field name. */
32
+ name: string;
33
+ private _formDisabled;
34
+ protected willUpdate(changed: PropertyValues): void;
35
+ /** Resets to the value present at first render, per the form contract. */
36
+ formResetCallback(): void;
37
+ /** Mirrors an ancestor fieldset's disabled state. */
38
+ formDisabledCallback(disabled: boolean): void;
39
+ /** Restores the value from saved form state (bfcache/autofill). */
40
+ formStateRestoreCallback(state: string | File | FormData | null): void;
41
+ render(): import("lit-html").TemplateResult<1>;
42
+ }
43
+ declare global {
44
+ interface HTMLElementTagNameMap {
45
+ "range-slider": RangeSlider;
46
+ }
47
+ }
48
+ //# sourceMappingURL=range-slider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"range-slider.d.ts","sourceRoot":"","sources":["../src/range-slider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAIjE;;;;;;;;;;;;;;GAcG;AACH,qBACa,WAAY,SAAQ,UAAU;;IACzC,MAAM,CAAC,cAAc,UAAQ;IAE7B,OAAgB,MAAM,4BAuGpB;IAEF,qBAAqB;IACO,GAAG,SAAK;IACpC,qBAAqB;IACO,GAAG,SAAO;IACtC,sBAAsB;IACM,IAAI,SAAK;IACrC,qBAAqB;IACO,KAAK,SAAK;IACtC,2EAA2E;IAC9C,QAAQ,UAAS;IAC9C,uBAAuB;IACX,IAAI,SAAM;IAEb,OAAO,CAAC,aAAa,CAAS;IAevC,UAAmB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAG3D;IAED,0EAA0E;IAC1E,iBAAiB,IAAI,IAAI,CAExB;IAED,qDAAqD;IACrD,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAE5C;IAED,mEAAmE;IACnE,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,CAIrE;IAsBQ,MAAM,yCAcd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,WAAW,CAAC;KAC7B;CACF"}
@@ -0,0 +1,240 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement, css, html } from "lit";
8
+ import { customElement, property, state } from "lit/decorators.js";
9
+ import { tokens } from "./tokens.js";
10
+ /**
11
+ * A form-associated numeric range slider, usable standalone or inside a
12
+ * native `<form>`. Wraps a native `<input type="range">` (kept for its free
13
+ * keyboard, drag, and screen-reader support) restyled to match this
14
+ * package's track/fill visual language (`stat-meter`, `percent-bar-chart`)
15
+ * instead of the browser-default appearance. Purely a value control — no
16
+ * built-in label; wrap in `form-field` for a labeled field, or render a
17
+ * value readout next to it (see the playground example), matching
18
+ * `autocomplete-input`/`form-select`.
19
+ *
20
+ * @element range-slider
21
+ * @fires input - Fires continuously while dragging/typing; detail: `{ value }`.
22
+ * @fires change - Fires once the value is committed (drag released, arrow
23
+ * key released); detail: `{ value }`.
24
+ */
25
+ let RangeSlider = class RangeSlider extends LitElement {
26
+ constructor() {
27
+ super(...arguments);
28
+ /** Minimum value. */
29
+ this.min = 0;
30
+ /** Maximum value. */
31
+ this.max = 100;
32
+ /** Step increment. */
33
+ this.step = 1;
34
+ /** Current value. */
35
+ this.value = 0;
36
+ /** Disables interaction; merged with an ancestor `<fieldset disabled>`. */
37
+ this.disabled = false;
38
+ /** Form field name. */
39
+ this.name = "";
40
+ this._formDisabled = false;
41
+ this.#internals = this.attachInternals();
42
+ this.#defaultValue = 0;
43
+ }
44
+ static { this.formAssociated = true; }
45
+ static { this.styles = [
46
+ tokens,
47
+ css `
48
+ :host {
49
+ display: block;
50
+ }
51
+ input[type="range"] {
52
+ -webkit-appearance: none;
53
+ appearance: none;
54
+ width: 100%;
55
+ height: 2rem;
56
+ margin: 0;
57
+ background: transparent;
58
+ cursor: pointer;
59
+ }
60
+ input[type="range"]:disabled {
61
+ cursor: not-allowed;
62
+ opacity: 0.6;
63
+ }
64
+ /* Track */
65
+ input[type="range"]::-webkit-slider-runnable-track {
66
+ height: 0.375rem;
67
+ border-radius: 9999px;
68
+ background: linear-gradient(
69
+ to right,
70
+ var(--ui-primary, #4f46e5) 0%,
71
+ var(--ui-primary, #4f46e5) var(--range-percent, 0%),
72
+ var(--ui-surface-muted, #f8fafc) var(--range-percent, 0%),
73
+ var(--ui-surface-muted, #f8fafc) 100%
74
+ );
75
+ }
76
+ input[type="range"]::-moz-range-track {
77
+ height: 0.375rem;
78
+ border-radius: 9999px;
79
+ background: var(--ui-surface-muted, #f8fafc);
80
+ }
81
+ input[type="range"]::-moz-range-progress {
82
+ height: 0.375rem;
83
+ border-radius: 9999px;
84
+ background: var(--ui-primary, #4f46e5);
85
+ }
86
+ /* Thumb */
87
+ input[type="range"]::-webkit-slider-thumb {
88
+ -webkit-appearance: none;
89
+ appearance: none;
90
+ width: 1rem;
91
+ height: 1rem;
92
+ /* WebKit centers the thumb on the input's full 2rem box, not the
93
+ thinner custom track — nudge it up to align with the track.
94
+ A transform offset (not margin) so it isn't a spacing-grid value. */
95
+ transform: translateY(-0.3125rem);
96
+ border-radius: 50%;
97
+ background: var(--ui-primary, #4f46e5);
98
+ border: 2px solid var(--ui-surface, #ffffff);
99
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.2);
100
+ }
101
+ input[type="range"]::-moz-range-thumb {
102
+ width: 1rem;
103
+ height: 1rem;
104
+ border-radius: 50%;
105
+ background: var(--ui-primary, #4f46e5);
106
+ border: 2px solid var(--ui-surface, #ffffff);
107
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.2);
108
+ }
109
+ input[type="range"]:disabled::-webkit-slider-thumb {
110
+ background: var(--ui-text-muted, #64748b);
111
+ }
112
+ input[type="range"]:disabled::-moz-range-thumb {
113
+ background: var(--ui-text-muted, #64748b);
114
+ }
115
+ input[type="range"]:focus-visible {
116
+ outline: none;
117
+ }
118
+ input[type="range"]:focus-visible::-webkit-slider-thumb {
119
+ box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
120
+ }
121
+ input[type="range"]:focus-visible::-moz-range-thumb {
122
+ box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
123
+ }
124
+ @media (prefers-reduced-motion: no-preference) {
125
+ input[type="range"]::-webkit-slider-thumb {
126
+ transition: box-shadow 120ms ease;
127
+ }
128
+ input[type="range"]::-moz-range-thumb {
129
+ transition: box-shadow 120ms ease;
130
+ }
131
+ }
132
+ @media (forced-colors: active) {
133
+ input[type="range"]::-webkit-slider-runnable-track {
134
+ background: Canvas;
135
+ border: 1px solid CanvasText;
136
+ }
137
+ input[type="range"]::-webkit-slider-thumb {
138
+ background: Highlight;
139
+ border-color: Canvas;
140
+ }
141
+ input[type="range"]:focus-visible::-webkit-slider-thumb {
142
+ outline: 2px solid CanvasText;
143
+ outline-offset: 2px;
144
+ box-shadow: none;
145
+ }
146
+ }
147
+ `,
148
+ ]; }
149
+ #internals;
150
+ #defaultValue;
151
+ /** Whether the host or an ancestor fieldset currently disables the control. */
152
+ get #isDisabled() {
153
+ return this.disabled || this._formDisabled;
154
+ }
155
+ get #percent() {
156
+ const range = this.max - this.min || 1;
157
+ return ((this.value - this.min) / range) * 100;
158
+ }
159
+ willUpdate(changed) {
160
+ if (!this.hasUpdated)
161
+ this.#defaultValue = this.value;
162
+ if (changed.has("value"))
163
+ this.#internals.setFormValue(String(this.value));
164
+ }
165
+ /** Resets to the value present at first render, per the form contract. */
166
+ formResetCallback() {
167
+ this.value = this.#defaultValue;
168
+ }
169
+ /** Mirrors an ancestor fieldset's disabled state. */
170
+ formDisabledCallback(disabled) {
171
+ this._formDisabled = disabled;
172
+ }
173
+ /** Restores the value from saved form state (bfcache/autofill). */
174
+ formStateRestoreCallback(state) {
175
+ if (typeof state !== "string")
176
+ return;
177
+ const parsed = Number(state);
178
+ if (!Number.isNaN(parsed))
179
+ this.value = parsed;
180
+ }
181
+ // The native input's own "input"/"change" events are composed (cross the
182
+ // shadow boundary) — stop them so only our re-dispatched CustomEvent
183
+ // (carrying `detail.value`) reaches consumers, matching text-area.ts's fix
184
+ // for the same issue. Otherwise the native event bubbles out afterwards
185
+ // too, re-invoking the same listener with a plain Event whose `detail` is
186
+ // undefined, crashing consumer code that reads `e.detail.value`.
187
+ #onInput(e) {
188
+ e.stopPropagation();
189
+ const input = e.target;
190
+ this.value = Number(input.value);
191
+ this.dispatchEvent(new CustomEvent("input", { detail: { value: this.value }, bubbles: true, composed: true }));
192
+ }
193
+ #onChange(e) {
194
+ e.stopPropagation();
195
+ const input = e.target;
196
+ this.value = Number(input.value);
197
+ this.dispatchEvent(new CustomEvent("change", { detail: { value: this.value }, bubbles: true, composed: true }));
198
+ }
199
+ render() {
200
+ return html `
201
+ <input
202
+ type="range"
203
+ style=${`--range-percent: ${this.#percent}%`}
204
+ min=${this.min}
205
+ max=${this.max}
206
+ step=${this.step}
207
+ .value=${String(this.value)}
208
+ ?disabled=${this.#isDisabled}
209
+ @input=${(e) => this.#onInput(e)}
210
+ @change=${(e) => this.#onChange(e)}
211
+ />
212
+ `;
213
+ }
214
+ };
215
+ __decorate([
216
+ property({ type: Number })
217
+ ], RangeSlider.prototype, "min", void 0);
218
+ __decorate([
219
+ property({ type: Number })
220
+ ], RangeSlider.prototype, "max", void 0);
221
+ __decorate([
222
+ property({ type: Number })
223
+ ], RangeSlider.prototype, "step", void 0);
224
+ __decorate([
225
+ property({ type: Number })
226
+ ], RangeSlider.prototype, "value", void 0);
227
+ __decorate([
228
+ property({ type: Boolean })
229
+ ], RangeSlider.prototype, "disabled", void 0);
230
+ __decorate([
231
+ property()
232
+ ], RangeSlider.prototype, "name", void 0);
233
+ __decorate([
234
+ state()
235
+ ], RangeSlider.prototype, "_formDisabled", void 0);
236
+ RangeSlider = __decorate([
237
+ customElement("range-slider")
238
+ ], RangeSlider);
239
+ export { RangeSlider };
240
+ //# sourceMappingURL=range-slider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"range-slider.js","sourceRoot":"","sources":["../src/range-slider.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAuB,MAAM,KAAK,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;;;;GAcG;AAEI,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,UAAU;IAApC;;QA4GL,qBAAqB;QACO,QAAG,GAAG,CAAC,CAAC;QACpC,qBAAqB;QACO,QAAG,GAAG,GAAG,CAAC;QACtC,sBAAsB;QACM,SAAI,GAAG,CAAC,CAAC;QACrC,qBAAqB;QACO,UAAK,GAAG,CAAC,CAAC;QACtC,2EAA2E;QAC9C,aAAQ,GAAG,KAAK,CAAC;QAC9C,uBAAuB;QACX,SAAI,GAAG,EAAE,CAAC;QAEL,kBAAa,GAAG,KAAK,CAAC;QAEvC,eAAU,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACpC,kBAAa,GAAG,CAAC,CAAC;IAqEpB,CAAC;aAhMQ,mBAAc,GAAG,IAAI,AAAP,CAAQ;aAEb,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoGF;KACF,AAvGqB,CAuGpB;IAiBF,UAAU,CAA0B;IACpC,aAAa,CAAK;IAElB,+EAA+E;IAC/E,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,aAAa,CAAC;IAC7C,CAAC;IAED,IAAI,QAAQ;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACvC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;IACjD,CAAC;IAEkB,UAAU,CAAC,OAAuB;QACnD,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC;QACtD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,0EAA0E;IAC1E,iBAAiB;QACf,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC;IAClC,CAAC;IAED,qDAAqD;IACrD,oBAAoB,CAAC,QAAiB;QACpC,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;IAChC,CAAC;IAED,mEAAmE;IACnE,wBAAwB,CAAC,KAAsC;QAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO;QACtC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;IACjD,CAAC;IAED,yEAAyE;IACzE,qEAAqE;IACrE,2EAA2E;IAC3E,wEAAwE;IACxE,0EAA0E;IAC1E,iEAAiE;IACjE,QAAQ,CAAC,CAAQ;QACf,CAAC,CAAC,eAAe,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,CAAC,CAAC,MAA0B,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACjH,CAAC;IAED,SAAS,CAAC,CAAQ;QAChB,CAAC,CAAC,eAAe,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,CAAC,CAAC,MAA0B,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAClH,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;;gBAGC,oBAAoB,IAAI,CAAC,QAAQ,GAAG;cACtC,IAAI,CAAC,GAAG;cACR,IAAI,CAAC,GAAG;eACP,IAAI,CAAC,IAAI;iBACP,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;oBACf,IAAI,CAAC,WAAW;iBACnB,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;kBAC7B,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;;KAE5C,CAAC;IACJ,CAAC;CACF,CAAA;AApF6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCAAS;AAER;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCAAW;AAEV;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yCAAU;AAET;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CAAW;AAET;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;6CAAkB;AAElC;IAAX,QAAQ,EAAE;yCAAW;AAEL;IAAhB,KAAK,EAAE;kDAA+B;AAzH5B,WAAW;IADvB,aAAa,CAAC,cAAc,CAAC;GACjB,WAAW,CAiMvB","sourcesContent":["import { LitElement, css, html, type PropertyValues } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A form-associated numeric range slider, usable standalone or inside a\n * native `<form>`. Wraps a native `<input type=\"range\">` (kept for its free\n * keyboard, drag, and screen-reader support) restyled to match this\n * package's track/fill visual language (`stat-meter`, `percent-bar-chart`)\n * instead of the browser-default appearance. Purely a value control — no\n * built-in label; wrap in `form-field` for a labeled field, or render a\n * value readout next to it (see the playground example), matching\n * `autocomplete-input`/`form-select`.\n *\n * @element range-slider\n * @fires input - Fires continuously while dragging/typing; detail: `{ value }`.\n * @fires change - Fires once the value is committed (drag released, arrow\n * key released); detail: `{ value }`.\n */\n@customElement(\"range-slider\")\nexport class RangeSlider extends LitElement {\n static formAssociated = true;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n }\n input[type=\"range\"] {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 2rem;\n margin: 0;\n background: transparent;\n cursor: pointer;\n }\n input[type=\"range\"]:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n /* Track */\n input[type=\"range\"]::-webkit-slider-runnable-track {\n height: 0.375rem;\n border-radius: 9999px;\n background: linear-gradient(\n to right,\n var(--ui-primary, #4f46e5) 0%,\n var(--ui-primary, #4f46e5) var(--range-percent, 0%),\n var(--ui-surface-muted, #f8fafc) var(--range-percent, 0%),\n var(--ui-surface-muted, #f8fafc) 100%\n );\n }\n input[type=\"range\"]::-moz-range-track {\n height: 0.375rem;\n border-radius: 9999px;\n background: var(--ui-surface-muted, #f8fafc);\n }\n input[type=\"range\"]::-moz-range-progress {\n height: 0.375rem;\n border-radius: 9999px;\n background: var(--ui-primary, #4f46e5);\n }\n /* Thumb */\n input[type=\"range\"]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 1rem;\n height: 1rem;\n /* WebKit centers the thumb on the input's full 2rem box, not the\n thinner custom track — nudge it up to align with the track.\n A transform offset (not margin) so it isn't a spacing-grid value. */\n transform: translateY(-0.3125rem);\n border-radius: 50%;\n background: var(--ui-primary, #4f46e5);\n border: 2px solid var(--ui-surface, #ffffff);\n box-shadow: 0 1px 2px rgb(0 0 0 / 0.2);\n }\n input[type=\"range\"]::-moz-range-thumb {\n width: 1rem;\n height: 1rem;\n border-radius: 50%;\n background: var(--ui-primary, #4f46e5);\n border: 2px solid var(--ui-surface, #ffffff);\n box-shadow: 0 1px 2px rgb(0 0 0 / 0.2);\n }\n input[type=\"range\"]:disabled::-webkit-slider-thumb {\n background: var(--ui-text-muted, #64748b);\n }\n input[type=\"range\"]:disabled::-moz-range-thumb {\n background: var(--ui-text-muted, #64748b);\n }\n input[type=\"range\"]:focus-visible {\n outline: none;\n }\n input[type=\"range\"]:focus-visible::-webkit-slider-thumb {\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n input[type=\"range\"]:focus-visible::-moz-range-thumb {\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n @media (prefers-reduced-motion: no-preference) {\n input[type=\"range\"]::-webkit-slider-thumb {\n transition: box-shadow 120ms ease;\n }\n input[type=\"range\"]::-moz-range-thumb {\n transition: box-shadow 120ms ease;\n }\n }\n @media (forced-colors: active) {\n input[type=\"range\"]::-webkit-slider-runnable-track {\n background: Canvas;\n border: 1px solid CanvasText;\n }\n input[type=\"range\"]::-webkit-slider-thumb {\n background: Highlight;\n border-color: Canvas;\n }\n input[type=\"range\"]:focus-visible::-webkit-slider-thumb {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n }\n `,\n ];\n\n /** Minimum value. */\n @property({ type: Number }) min = 0;\n /** Maximum value. */\n @property({ type: Number }) max = 100;\n /** Step increment. */\n @property({ type: Number }) step = 1;\n /** Current value. */\n @property({ type: Number }) value = 0;\n /** Disables interaction; merged with an ancestor `<fieldset disabled>`. */\n @property({ type: Boolean }) disabled = false;\n /** Form field name. */\n @property() name = \"\";\n\n @state() private _formDisabled = false;\n\n #internals = this.attachInternals();\n #defaultValue = 0;\n\n /** Whether the host or an ancestor fieldset currently disables the control. */\n get #isDisabled(): boolean {\n return this.disabled || this._formDisabled;\n }\n\n get #percent(): number {\n const range = this.max - this.min || 1;\n return ((this.value - this.min) / range) * 100;\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n if (!this.hasUpdated) this.#defaultValue = this.value;\n if (changed.has(\"value\")) this.#internals.setFormValue(String(this.value));\n }\n\n /** Resets to the value present at first render, per the form contract. */\n formResetCallback(): void {\n this.value = this.#defaultValue;\n }\n\n /** Mirrors an ancestor fieldset's disabled state. */\n formDisabledCallback(disabled: boolean): void {\n this._formDisabled = disabled;\n }\n\n /** Restores the value from saved form state (bfcache/autofill). */\n formStateRestoreCallback(state: string | File | FormData | null): void {\n if (typeof state !== \"string\") return;\n const parsed = Number(state);\n if (!Number.isNaN(parsed)) this.value = parsed;\n }\n\n // The native input's own \"input\"/\"change\" events are composed (cross the\n // shadow boundary) — stop them so only our re-dispatched CustomEvent\n // (carrying `detail.value`) reaches consumers, matching text-area.ts's fix\n // for the same issue. Otherwise the native event bubbles out afterwards\n // too, re-invoking the same listener with a plain Event whose `detail` is\n // undefined, crashing consumer code that reads `e.detail.value`.\n #onInput(e: Event): void {\n e.stopPropagation();\n const input = e.target as HTMLInputElement;\n this.value = Number(input.value);\n this.dispatchEvent(new CustomEvent(\"input\", { detail: { value: this.value }, bubbles: true, composed: true }));\n }\n\n #onChange(e: Event): void {\n e.stopPropagation();\n const input = e.target as HTMLInputElement;\n this.value = Number(input.value);\n this.dispatchEvent(new CustomEvent(\"change\", { detail: { value: this.value }, bubbles: true, composed: true }));\n }\n\n override render() {\n return html`\n <input\n type=\"range\"\n style=${`--range-percent: ${this.#percent}%`}\n min=${this.min}\n max=${this.max}\n step=${this.step}\n .value=${String(this.value)}\n ?disabled=${this.#isDisabled}\n @input=${(e: Event) => this.#onInput(e)}\n @change=${(e: Event) => this.#onChange(e)}\n />\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"range-slider\": RangeSlider;\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { LitElement, type PropertyValues } from "lit";
1
+ import { LitElement, type PropertyValues, type TemplateResult } from "lit";
2
2
  /**
3
3
  * A form-associated boolean checkbox, usable standalone or inside a native
4
4
  * `<form>`. Submits `name=on` when checked (matching native
@@ -8,7 +8,11 @@ import { LitElement, type PropertyValues } from "lit";
8
8
  * Renders a native `<input type="checkbox">` wrapped in a `<label>`, styled
9
9
  * via `:has()` on the wrapping label (matching `radio-pills`/`radio-cards`)
10
10
  * rather than styling the native input directly; the checkbox itself renders
11
- * at `1rem`, matching the existing radio-input convention.
11
+ * at `1rem`, matching the existing radio-input convention. An optional
12
+ * pre-rendered `icon` (matching `form-select`'s per-option icon convention)
13
+ * renders between the box and the label, inside the same clickable `<label>`
14
+ * — for a row that pairs a checkbox with an icon/swatch and needs the whole
15
+ * row, icon included, to stay one click target.
12
16
  *
13
17
  * @element ui-checkbox
14
18
  * @fires change - The checkbox was toggled by the user, in either direction;
@@ -30,6 +34,10 @@ export declare class UiCheckbox extends LitElement {
30
34
  name: string;
31
35
  /** Visible label text rendered next to the box. */
32
36
  label: string;
37
+ /** Pre-rendered icon template displayed between the box and the label, e.g. `iconPencil(14)` from this package's icon set. */
38
+ icon: TemplateResult | null;
39
+ /** Square icon size in pixels — 14 (inline icon size) by default. */
40
+ iconSize: number;
33
41
  private _formDisabled;
34
42
  protected willUpdate(_changed: PropertyValues): void;
35
43
  protected updated(changed: PropertyValues): void;
@@ -39,7 +47,7 @@ export declare class UiCheckbox extends LitElement {
39
47
  formDisabledCallback(disabled: boolean): void;
40
48
  /** Restores the checked state from saved form state (bfcache/autofill). */
41
49
  formStateRestoreCallback(state: string | File | FormData | null): void;
42
- render(): import("lit-html").TemplateResult<1>;
50
+ render(): TemplateResult<1>;
43
51
  }
44
52
  declare global {
45
53
  interface HTMLElementTagNameMap {
@@ -1 +1 @@
1
- {"version":3,"file":"ui-checkbox.d.ts","sourceRoot":"","sources":["../src/ui-checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAKjE;;;;;;;;;;;;;;GAcG;AACH,qBACa,UAAW,SAAQ,UAAU;;IACxC,MAAM,CAAC,cAAc,UAAQ;IAE7B,OAAgB,MAAM,4BAkEpB;IAEF,kCAAkC;IACL,OAAO,UAAS;IAC7C,8EAA8E;IACjD,aAAa,UAAS;IACnD,2EAA2E;IAC9C,QAAQ,UAAS;IAC9C,wEAAwE;IAC3C,QAAQ,UAAS;IAC9C,kEAAkE;IACtD,IAAI,SAAM;IACtB,mDAAmD;IACvC,KAAK,SAAM;IAEd,OAAO,CAAC,aAAa,CAAS;IAWvC,UAAmB,UAAU,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAE5D;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAQxD;IAED,kFAAkF;IAClF,iBAAiB,IAAI,IAAI,CAGxB;IAED,qDAAqD;IACrD,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAE5C;IAED,2EAA2E;IAC3E,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,CAGrE;IAwCQ,MAAM,yCAoBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
1
+ {"version":3,"file":"ui-checkbox.d.ts","sourceRoot":"","sources":["../src/ui-checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAK/F;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,UAAW,SAAQ,UAAU;;IACxC,MAAM,CAAC,cAAc,UAAQ;IAE7B,OAAgB,MAAM,4BA4EpB;IAEF,kCAAkC;IACL,OAAO,UAAS;IAC7C,8EAA8E;IACjD,aAAa,UAAS;IACnD,2EAA2E;IAC9C,QAAQ,UAAS;IAC9C,wEAAwE;IAC3C,QAAQ,UAAS;IAC9C,kEAAkE;IACtD,IAAI,SAAM;IACtB,mDAAmD;IACvC,KAAK,SAAM;IACvB,8HAA8H;IAC9F,IAAI,EAAE,cAAc,GAAG,IAAI,CAAQ;IACnE,qEAAqE;IACzC,QAAQ,SAAM;IAEjC,OAAO,CAAC,aAAa,CAAS;IAWvC,UAAmB,UAAU,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAE5D;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAQxD;IAED,kFAAkF;IAClF,iBAAiB,IAAI,IAAI,CAGxB;IAED,qDAAqD;IACrD,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAE5C;IAED,2EAA2E;IAC3E,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,CAGrE;IAwCQ,MAAM,sBAyBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}