@vverchonov/web-components 0.1.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.
- package/dist/button-DYrT530y.js +39 -0
- package/dist/button.js +2 -0
- package/dist/components/button/button-types.d.ts +2 -0
- package/dist/components/button/button.d.ts +14 -0
- package/dist/components/button/index.d.ts +2 -0
- package/dist/components/dropdown-button/dropdown-button-types.d.ts +13 -0
- package/dist/components/dropdown-button/dropdown-button.d.ts +34 -0
- package/dist/components/dropdown-button/index.d.ts +2 -0
- package/dist/components/input/index.d.ts +2 -0
- package/dist/components/input/input-types.d.ts +2 -0
- package/dist/components/input/input.d.ts +22 -0
- package/dist/components/layouts/form/form-layout-types.d.ts +3 -0
- package/dist/components/layouts/form/form-layout.d.ts +53 -0
- package/dist/components/layouts/form/index.d.ts +2 -0
- package/dist/components/layouts/index.d.ts +3 -0
- package/dist/components/layouts/page/index.d.ts +1 -0
- package/dist/components/layouts/page/layout.d.ts +20 -0
- package/dist/components/menu/index.d.ts +2 -0
- package/dist/components/menu/menu-types.d.ts +16 -0
- package/dist/components/menu/menu.d.ts +36 -0
- package/dist/components/modal/index.d.ts +2 -0
- package/dist/components/modal/modal-types.d.ts +2 -0
- package/dist/components/modal/modal.d.ts +103 -0
- package/dist/components/selector/index.d.ts +2 -0
- package/dist/components/selector/selector-types.d.ts +19 -0
- package/dist/components/selector/selector.d.ts +56 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/table-types.d.ts +35 -0
- package/dist/components/table/table.d.ts +47 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/tabs/tabs.d.ts +19 -0
- package/dist/components/toggle/index.d.ts +2 -0
- package/dist/components/toggle/toggle-types.d.ts +4 -0
- package/dist/components/toggle/toggle.d.ts +15 -0
- package/dist/dropdown-button-B6XNoy4L.js +172 -0
- package/dist/dropdown-button.js +2 -0
- package/dist/form-layout-DCX8X-8-.js +140 -0
- package/dist/index.d.ts +22 -0
- package/dist/input-BVlPYqTe.js +70 -0
- package/dist/input.js +2 -0
- package/dist/layout-CYvgu_WE.js +23 -0
- package/dist/layouts.js +3 -0
- package/dist/menu-DmAFaVi5.js +248 -0
- package/dist/menu.js +2 -0
- package/dist/mock/table-data.d.ts +16 -0
- package/dist/modal-v1GlqMF_.js +174 -0
- package/dist/modal.js +2 -0
- package/dist/react/button.d.ts +2 -0
- package/dist/react/button.js +9 -0
- package/dist/react/dropdown-button.d.ts +6 -0
- package/dist/react/dropdown-button.js +10 -0
- package/dist/react/form-layout.d.ts +8 -0
- package/dist/react/form-layout.js +14 -0
- package/dist/react/index.d.ts +21 -0
- package/dist/react/input.d.ts +2 -0
- package/dist/react/input.js +9 -0
- package/dist/react/layout.d.ts +2 -0
- package/dist/react/layout.js +9 -0
- package/dist/react/menu.d.ts +7 -0
- package/dist/react/menu.js +13 -0
- package/dist/react/modal.d.ts +7 -0
- package/dist/react/modal.js +14 -0
- package/dist/react/selector.d.ts +6 -0
- package/dist/react/selector.js +10 -0
- package/dist/react/table.d.ts +8 -0
- package/dist/react/table.js +14 -0
- package/dist/react/tabs.d.ts +5 -0
- package/dist/react/tabs.js +10 -0
- package/dist/react/toggle.d.ts +6 -0
- package/dist/react/toggle.js +10 -0
- package/dist/react.js +12 -0
- package/dist/selector-Bl7Nbkqo.js +300 -0
- package/dist/selector.js +2 -0
- package/dist/styles/tailwind-base.d.ts +1 -0
- package/dist/table--O5km0Wv.js +279 -0
- package/dist/table.js +2 -0
- package/dist/tabs-C2lP0uxY.js +94 -0
- package/dist/tabs.js +2 -0
- package/dist/toggle-D6UMZ8UZ.js +59 -0
- package/dist/toggle.js +2 -0
- package/dist/vite.svg +1 -0
- package/dist/web-components.js +24 -0
- package/package.json +153 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { t as e } from "../table--O5km0Wv.js";
|
|
2
|
+
import * as t from "react";
|
|
3
|
+
import { createComponent as n } from "@lit/react";
|
|
4
|
+
const r = n({
|
|
5
|
+
tagName: "app-table",
|
|
6
|
+
elementClass: e,
|
|
7
|
+
react: t,
|
|
8
|
+
events: {
|
|
9
|
+
onTableSort: "table-sort",
|
|
10
|
+
onTablePage: "table-page",
|
|
11
|
+
onTableColumnToggle: "table-column-toggle"
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
export { r as Table };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { EventName } from '@lit/react';
|
|
2
|
+
import { Tabs as TabsElement, TabChangeEventDetail } from '../components/tabs/tabs.ts';
|
|
3
|
+
export declare const Tabs: import('@lit/react').ReactWebComponent<TabsElement, {
|
|
4
|
+
onTabChange: EventName<CustomEvent<TabChangeEventDetail>>;
|
|
5
|
+
}>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { t as e } from "../tabs-C2lP0uxY.js";
|
|
2
|
+
import * as t from "react";
|
|
3
|
+
import { createComponent as n } from "@lit/react";
|
|
4
|
+
const r = n({
|
|
5
|
+
tagName: "app-tabs",
|
|
6
|
+
elementClass: e,
|
|
7
|
+
react: t,
|
|
8
|
+
events: { onTabChange: "tab-change" }
|
|
9
|
+
});
|
|
10
|
+
export { r as Tabs };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EventName } from '@lit/react';
|
|
2
|
+
import { Toggle as ToggleElement } from '../components/toggle/toggle.ts';
|
|
3
|
+
import { ToggleChangeEventDetail } from '../components/toggle/toggle-types.ts';
|
|
4
|
+
export declare const Toggle: import('@lit/react').ReactWebComponent<ToggleElement, {
|
|
5
|
+
onToggleChange: EventName<CustomEvent<ToggleChangeEventDetail>>;
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { t as e } from "../toggle-D6UMZ8UZ.js";
|
|
2
|
+
import * as t from "react";
|
|
3
|
+
import { createComponent as n } from "@lit/react";
|
|
4
|
+
const r = n({
|
|
5
|
+
tagName: "app-toggle",
|
|
6
|
+
elementClass: e,
|
|
7
|
+
react: t,
|
|
8
|
+
events: { onToggleChange: "toggle-change" }
|
|
9
|
+
});
|
|
10
|
+
export { r as Toggle };
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Button as e } from "./react/button.js";
|
|
2
|
+
import { DropdownButton as t } from "./react/dropdown-button.js";
|
|
3
|
+
import { Input as n } from "./react/input.js";
|
|
4
|
+
import { Menu as r } from "./react/menu.js";
|
|
5
|
+
import { Modal as i } from "./react/modal.js";
|
|
6
|
+
import { Selector as a } from "./react/selector.js";
|
|
7
|
+
import { Table as o } from "./react/table.js";
|
|
8
|
+
import { Tabs as s } from "./react/tabs.js";
|
|
9
|
+
import { Toggle as c } from "./react/toggle.js";
|
|
10
|
+
import { FormLayout as l } from "./react/form-layout.js";
|
|
11
|
+
import { Layout as u } from "./react/layout.js";
|
|
12
|
+
export { e as Button, t as DropdownButton, l as FormLayout, n as Input, u as Layout, r as Menu, i as Modal, a as Selector, o as Table, s as Tabs, c as Toggle };
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { LitElement as e, html as t, nothing as n, unsafeCSS as r } from "lit";
|
|
2
|
+
import { customElement as i, property as a, state as o } from "lit/decorators.js";
|
|
3
|
+
import { repeat as s } from "lit/directives/repeat.js";
|
|
4
|
+
var c = ":host{display:block}.wrapper{flex-direction:column;gap:.375rem;display:flex}.label{color:var(--color-text);font-size:.875rem;font-weight:500;line-height:1.25}.trigger{align-items:center;gap:var(--selector-chip-gap);min-height:var(--selector-min-height);padding:.3125rem 2rem .3125rem var(--input-padding-inline);background:var(--color-surface);border:1px solid var(--color-border-strong);border-radius:var(--radius-input);cursor:pointer;transition:border-color var(--selector-transition-duration) var(--ease-emphasized), box-shadow var(--selector-transition-duration) var(--ease-emphasized);box-sizing:border-box;width:100%;font-size:var(--input-font-size);color:var(--color-text);text-align:left;outline:none;flex-wrap:wrap;display:flex;position:relative}.trigger:hover:not(.is-disabled){border-color:var(--color-border-strong);box-shadow:0 0 0 1px var(--color-border-strong)}.trigger:focus-visible:not(.is-disabled),.trigger.is-open:not(.is-disabled){border-color:var(--color-primary);box-shadow:0 0 0 2px var(--color-primary)}.trigger.is-disabled{opacity:.5;cursor:not-allowed;background:var(--color-surface-elevated)}.chevron{right:var(--input-padding-inline);color:var(--color-text-muted);pointer-events:none;transition:transform var(--selector-transition-duration) var(--ease-emphasized);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.trigger.is-open .chevron{transform:translateY(-50%)rotate(180deg)}.placeholder{color:var(--color-text-muted);user-select:none}.single-value{text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:.375rem;display:flex;overflow:hidden}.chip{padding:var(--selector-chip-padding-block) var(--selector-chip-padding-inline);font-size:var(--selector-chip-font-size);background:var(--color-primary-muted);color:var(--color-text);border-radius:var(--radius-full);white-space:nowrap;align-items:center;gap:.25rem;max-width:10rem;line-height:1.25;display:inline-flex}.chip-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.chip-icon{width:1em;height:1em;color:var(--color-text-muted);flex-shrink:0;align-items:center;display:inline-flex}.chip-remove{border-radius:var(--radius-full);width:1rem;height:1rem;color:var(--color-text-muted);cursor:pointer;transition:color .15s var(--ease-emphasized), background .15s var(--ease-emphasized);background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;margin:0;padding:0;display:inline-flex}.chip-remove:hover{color:var(--color-invalid);background:var(--color-invalid-muted)}.chip-remove:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.panel{z-index:9999;min-width:180px;max-height:var(--selector-panel-max-height);padding:var(--dropdown-padding);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-card);display:none;position:fixed;overflow-y:auto;box-shadow:0 4px 12px oklch(0% 0 0/.12)}.panel.is-open{flex-direction:column;display:flex}.search-wrapper{flex-shrink:0;padding:.25rem .25rem .375rem}.search-input{box-sizing:border-box;width:100%;font-size:var(--selector-chip-font-size);color:var(--color-text);background:var(--color-surface-elevated);border:1px solid var(--color-border);border-radius:calc(var(--radius-card) - 2px);transition:border-color var(--selector-transition-duration) var(--ease-emphasized);outline:none;padding:.375rem .5rem}.search-input::placeholder{color:var(--color-text-muted)}.search-input:focus-visible{border-color:var(--color-primary);box-shadow:0 0 0 1px var(--color-primary)}.option-list{flex-direction:column;flex:1;gap:2px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.group-header{text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-muted);user-select:none;padding:.5rem .5rem .25rem;font-size:.75rem;font-weight:600}.option{width:100%;padding:var(--dropdown-item-padding-block) var(--dropdown-item-padding-inline);font-size:var(--dropdown-item-font-size);text-align:left;color:var(--color-text);border-radius:calc(var(--radius-card) - 2px);cursor:pointer;transition:background-color .15s var(--ease-emphasized);background:0 0;border:none;outline:none;align-items:center;gap:.5rem;font-weight:400;display:flex}.option:hover:not(.is-disabled){background:var(--color-primary-muted)}.option:focus-visible:not(.is-disabled){background:var(--color-primary-muted);outline:none}.option.is-focused:not(.is-disabled){background:var(--color-primary-muted)}.option.is-selected{color:var(--color-primary);font-weight:500}.option.is-disabled{opacity:.45;cursor:not-allowed}.option-check{width:1.125em;height:1.125em;color:var(--color-primary);opacity:0;flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.option.is-selected .option-check{opacity:1}.option-icon{width:1.25em;height:1.25em;color:var(--color-text-muted);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.option-icon:empty{display:none}.option-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.empty-message{font-size:var(--dropdown-item-font-size);color:var(--color-text-muted);text-align:center;padding:.75rem .5rem}:host([state=valid]) .trigger{border-color:var(--color-valid)}:host([state=valid]) .trigger:focus-visible,:host([state=valid]) .trigger.is-open{box-shadow:0 0 0 2px var(--color-valid)}:host([state=invalid]) .trigger{border-color:var(--color-invalid);background:var(--color-invalid-muted)}:host([state=invalid]) .trigger:focus-visible,:host([state=invalid]) .trigger.is-open{box-shadow:0 0 0 2px var(--color-invalid)}.error-text{color:var(--color-invalid);font-size:.8125rem;line-height:1.4}.sr-only{clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}";
|
|
5
|
+
function l(e, t, n, r) {
|
|
6
|
+
var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
|
|
7
|
+
if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
|
|
8
|
+
else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
|
|
9
|
+
return i > 3 && a && Object.defineProperty(t, n, a), a;
|
|
10
|
+
}
|
|
11
|
+
var u = t`
|
|
12
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
|
|
13
|
+
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
14
|
+
stroke-linejoin="round" aria-hidden="true">
|
|
15
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
16
|
+
</svg>
|
|
17
|
+
`, d = t`
|
|
18
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
|
|
19
|
+
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
20
|
+
stroke-linejoin="round" aria-hidden="true">
|
|
21
|
+
<polyline points="20 6 9 17 4 12"></polyline>
|
|
22
|
+
</svg>
|
|
23
|
+
`, f = t`
|
|
24
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24"
|
|
25
|
+
fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"
|
|
26
|
+
stroke-linejoin="round" aria-hidden="true">
|
|
27
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
28
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
29
|
+
</svg>
|
|
30
|
+
`, p = 0, m = class extends e {
|
|
31
|
+
static {
|
|
32
|
+
this.styles = [r(c)];
|
|
33
|
+
}
|
|
34
|
+
connectedCallback() {
|
|
35
|
+
super.connectedCallback(), document.addEventListener("click", this._onDocumentClick), document.addEventListener("keydown", this._onDocumentKeydown);
|
|
36
|
+
}
|
|
37
|
+
disconnectedCallback() {
|
|
38
|
+
super.disconnectedCallback(), document.removeEventListener("click", this._onDocumentClick), document.removeEventListener("keydown", this._onDocumentKeydown);
|
|
39
|
+
}
|
|
40
|
+
get _filteredItems() {
|
|
41
|
+
if (!this._search) return this.items;
|
|
42
|
+
let e = this._search.toLowerCase();
|
|
43
|
+
return this.items.filter((t) => t.label.toLowerCase().includes(e));
|
|
44
|
+
}
|
|
45
|
+
_isSelected(e) {
|
|
46
|
+
return this.value.includes(e);
|
|
47
|
+
}
|
|
48
|
+
_getOptionById(e) {
|
|
49
|
+
return this.items.find((t) => t.value === e);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns filtered items organized by group.
|
|
53
|
+
* Ungrouped items come first, then each group in the order defined by `this.groups`.
|
|
54
|
+
*/ _getGroupedItems() {
|
|
55
|
+
let e = this._filteredItems;
|
|
56
|
+
if (this.groups.length === 0) return [{
|
|
57
|
+
group: null,
|
|
58
|
+
items: e
|
|
59
|
+
}];
|
|
60
|
+
let t = [], n = /* @__PURE__ */ new Map();
|
|
61
|
+
for (let e of this.groups) n.set(e.key, []);
|
|
62
|
+
for (let r of e) r.group && n.has(r.group) ? n.get(r.group).push(r) : t.push(r);
|
|
63
|
+
let r = [];
|
|
64
|
+
t.length && r.push({
|
|
65
|
+
group: null,
|
|
66
|
+
items: t
|
|
67
|
+
});
|
|
68
|
+
for (let e of this.groups) {
|
|
69
|
+
let t = n.get(e.key);
|
|
70
|
+
t.length && r.push({
|
|
71
|
+
group: e,
|
|
72
|
+
items: t
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return r;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Flat list of visible option values (for keyboard index tracking).
|
|
79
|
+
* Skips disabled items.
|
|
80
|
+
*/ get _navigableValues() {
|
|
81
|
+
return this._filteredItems.filter((e) => !e.disabled).map((e) => e.value);
|
|
82
|
+
}
|
|
83
|
+
_select(e) {
|
|
84
|
+
let t = this._getOptionById(e);
|
|
85
|
+
if (!t || t.disabled) return;
|
|
86
|
+
let n;
|
|
87
|
+
this.multiple ? n = this._isSelected(e) ? this.value.filter((t) => t !== e) : [...this.value, e] : (n = this._isSelected(e) ? [] : [e], this._close()), this.value = n, this._dispatchChange(n), this._announceLive(t, n.includes(e));
|
|
88
|
+
}
|
|
89
|
+
_deselect(e) {
|
|
90
|
+
let t = this.value.filter((t) => t !== e);
|
|
91
|
+
this.value = t, this._dispatchChange(t);
|
|
92
|
+
let n = this._getOptionById(e);
|
|
93
|
+
n && this._announceLive(n, !1);
|
|
94
|
+
}
|
|
95
|
+
_dispatchChange(e) {
|
|
96
|
+
this.dispatchEvent(new CustomEvent("selector-change", {
|
|
97
|
+
detail: { value: e },
|
|
98
|
+
bubbles: !0,
|
|
99
|
+
composed: !0
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
_announceLive(e, t) {
|
|
103
|
+
this._liveMessage = t ? `${e.label} selected` : `${e.label} removed`;
|
|
104
|
+
}
|
|
105
|
+
_toggle() {
|
|
106
|
+
this.disabled || (this._open ? this._close() : this._openPanel());
|
|
107
|
+
}
|
|
108
|
+
_openPanel() {
|
|
109
|
+
this._open = !0, this._search = "", this._focusedIndex = -1, this.updateComplete.then(() => {
|
|
110
|
+
this._positionPanel(), this.searchable && this.shadowRoot?.querySelector(".search-input")?.focus();
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
_close() {
|
|
114
|
+
this._open = !1, this._search = "", this._focusedIndex = -1;
|
|
115
|
+
}
|
|
116
|
+
_positionPanel() {
|
|
117
|
+
let e = this.shadowRoot?.querySelector(".trigger"), t = this.shadowRoot?.querySelector(".panel");
|
|
118
|
+
if (!e || !t) return;
|
|
119
|
+
let n = e.getBoundingClientRect();
|
|
120
|
+
t.style.width = `${n.width}px`, t.style.left = `${n.left}px`;
|
|
121
|
+
let r = window.innerHeight - n.bottom - 8;
|
|
122
|
+
r < t.scrollHeight && n.top > r ? (t.style.bottom = `${window.innerHeight - n.top + 4}px`, t.style.top = "auto") : (t.style.top = `${n.bottom + 4}px`, t.style.bottom = "auto");
|
|
123
|
+
}
|
|
124
|
+
_onTriggerKeydown(e) {
|
|
125
|
+
switch (e.key) {
|
|
126
|
+
case "ArrowDown":
|
|
127
|
+
case "Enter":
|
|
128
|
+
case " ":
|
|
129
|
+
e.preventDefault(), this._open || (this._openPanel(), this.updateComplete.then(() => {
|
|
130
|
+
this._focusedIndex = 0, this._scrollToFocused();
|
|
131
|
+
}));
|
|
132
|
+
break;
|
|
133
|
+
case "ArrowUp":
|
|
134
|
+
e.preventDefault(), this._open || (this._openPanel(), this.updateComplete.then(() => {
|
|
135
|
+
this._focusedIndex = this._navigableValues.length - 1, this._scrollToFocused();
|
|
136
|
+
}));
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
_onPanelKeydown(e) {
|
|
141
|
+
let t = this._navigableValues;
|
|
142
|
+
if (t.length) switch (e.key) {
|
|
143
|
+
case "ArrowDown":
|
|
144
|
+
e.preventDefault(), this._focusedIndex = this._focusedIndex < t.length - 1 ? this._focusedIndex + 1 : 0, this._scrollToFocused();
|
|
145
|
+
break;
|
|
146
|
+
case "ArrowUp":
|
|
147
|
+
e.preventDefault(), this._focusedIndex = this._focusedIndex > 0 ? this._focusedIndex - 1 : t.length - 1, this._scrollToFocused();
|
|
148
|
+
break;
|
|
149
|
+
case "Home":
|
|
150
|
+
e.preventDefault(), this._focusedIndex = 0, this._scrollToFocused();
|
|
151
|
+
break;
|
|
152
|
+
case "End":
|
|
153
|
+
e.preventDefault(), this._focusedIndex = t.length - 1, this._scrollToFocused();
|
|
154
|
+
break;
|
|
155
|
+
case "Enter":
|
|
156
|
+
case " ":
|
|
157
|
+
e.preventDefault(), this._focusedIndex >= 0 && this._focusedIndex < t.length && this._select(t[this._focusedIndex]);
|
|
158
|
+
break;
|
|
159
|
+
case "Escape":
|
|
160
|
+
e.preventDefault(), this._close(), this.shadowRoot?.querySelector(".trigger")?.focus();
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
_scrollToFocused() {
|
|
165
|
+
this.updateComplete.then(() => {
|
|
166
|
+
(this.shadowRoot?.querySelector(".option.is-focused"))?.scrollIntoView({ block: "nearest" });
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
_onSearchInput(e) {
|
|
170
|
+
this._search = e.target.value, this._focusedIndex = -1;
|
|
171
|
+
}
|
|
172
|
+
_onChipRemove(e, t) {
|
|
173
|
+
e.stopPropagation(), this._deselect(t);
|
|
174
|
+
}
|
|
175
|
+
_renderOptionIcon(e) {
|
|
176
|
+
return e.icon == null ? n : typeof e.icon == "string" ? t`<span class="option-icon"><slot name=${`icon-${e.icon}`}></slot></span>` : t`<span class="option-icon">${e.icon}</span>`;
|
|
177
|
+
}
|
|
178
|
+
_renderChipIcon(e) {
|
|
179
|
+
return e.icon == null || typeof e.icon == "string" ? n : t`<span class="chip-icon">${e.icon}</span>`;
|
|
180
|
+
}
|
|
181
|
+
_renderTriggerContent() {
|
|
182
|
+
if (this.value.length === 0) return t`<span class="placeholder">${this.placeholder}</span>`;
|
|
183
|
+
if (!this.multiple) {
|
|
184
|
+
let e = this._getOptionById(this.value[0]);
|
|
185
|
+
return e ? t`
|
|
186
|
+
<span class="single-value">
|
|
187
|
+
${this._renderChipIcon(e)}
|
|
188
|
+
${e.label}
|
|
189
|
+
</span>
|
|
190
|
+
` : t`<span class="placeholder">${this.placeholder}</span>`;
|
|
191
|
+
}
|
|
192
|
+
return s(this.value, (e) => e, (e) => {
|
|
193
|
+
let r = this._getOptionById(e);
|
|
194
|
+
return r ? t`
|
|
195
|
+
<span class="chip">
|
|
196
|
+
${this._renderChipIcon(r)}
|
|
197
|
+
<span class="chip-label">${r.label}</span>
|
|
198
|
+
<button
|
|
199
|
+
type="button"
|
|
200
|
+
class="chip-remove"
|
|
201
|
+
aria-label="Remove ${r.label}"
|
|
202
|
+
@click=${(t) => this._onChipRemove(t, e)}
|
|
203
|
+
@keydown=${(t) => {
|
|
204
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), t.stopPropagation(), this._deselect(e));
|
|
205
|
+
}}
|
|
206
|
+
>${f}</button>
|
|
207
|
+
</span>
|
|
208
|
+
` : n;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
_renderOptions() {
|
|
212
|
+
let e = this._getGroupedItems(), r = this._navigableValues;
|
|
213
|
+
return e.some((e) => e.items.length > 0) ? e.map(({ group: e, items: i }) => t`
|
|
214
|
+
${e ? t`<div class="group-header" role="presentation">${e.label}</div>` : n}
|
|
215
|
+
${s(i, (e) => e.value, (e) => {
|
|
216
|
+
let i = this._isSelected(e.value), a = r.indexOf(e.value) === this._focusedIndex;
|
|
217
|
+
return t`
|
|
218
|
+
<div
|
|
219
|
+
role="option"
|
|
220
|
+
aria-selected=${i ? "true" : "false"}
|
|
221
|
+
aria-disabled=${e.disabled ? "true" : "false"}
|
|
222
|
+
id=${`${this._uid}-opt-${e.value}`}
|
|
223
|
+
class="option ${i ? "is-selected" : ""} ${a ? "is-focused" : ""} ${e.disabled ? "is-disabled" : ""}"
|
|
224
|
+
@click=${() => this._select(e.value)}
|
|
225
|
+
>
|
|
226
|
+
${this.multiple ? t`<span class="option-check">${d}</span>` : n}
|
|
227
|
+
${this._renderOptionIcon(e)}
|
|
228
|
+
<span class="option-label">${e.label}</span>
|
|
229
|
+
</div>
|
|
230
|
+
`;
|
|
231
|
+
})}
|
|
232
|
+
`) : t`<div class="empty-message">No options found</div>`;
|
|
233
|
+
}
|
|
234
|
+
render() {
|
|
235
|
+
let e = `${this._uid}-error`, r = this.state === "invalid" && this.errorMessage, i = `${this._uid}-listbox`, a = this._navigableValues, o = this._focusedIndex >= 0 && this._focusedIndex < a.length ? `${this._uid}-opt-${a[this._focusedIndex]}` : void 0;
|
|
236
|
+
return t`
|
|
237
|
+
<div class="wrapper">
|
|
238
|
+
${this.label ? t`<label id=${`${this._uid}-label`} class="label">${this.label}</label>` : n}
|
|
239
|
+
<div
|
|
240
|
+
class="trigger ${this._open ? "is-open" : ""} ${this.disabled ? "is-disabled" : ""}"
|
|
241
|
+
role="combobox"
|
|
242
|
+
aria-expanded=${this._open ? "true" : "false"}
|
|
243
|
+
aria-haspopup="listbox"
|
|
244
|
+
aria-owns=${i}
|
|
245
|
+
aria-labelledby=${this.label ? `${this._uid}-label` : n}
|
|
246
|
+
aria-describedby=${r ? e : n}
|
|
247
|
+
aria-activedescendant=${o ?? n}
|
|
248
|
+
tabindex=${this.disabled ? "-1" : "0"}
|
|
249
|
+
@click=${this._toggle}
|
|
250
|
+
@keydown=${this._onTriggerKeydown}
|
|
251
|
+
>
|
|
252
|
+
${this._renderTriggerContent()}
|
|
253
|
+
<span class="chevron">${u}</span>
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<div
|
|
257
|
+
id=${i}
|
|
258
|
+
class="panel ${this._open ? "is-open" : ""}"
|
|
259
|
+
role="listbox"
|
|
260
|
+
aria-multiselectable=${this.multiple ? "true" : "false"}
|
|
261
|
+
aria-label=${this.label || "Options"}
|
|
262
|
+
@keydown=${this._onPanelKeydown}
|
|
263
|
+
>
|
|
264
|
+
${this.searchable ? t`
|
|
265
|
+
<div class="search-wrapper">
|
|
266
|
+
<input
|
|
267
|
+
type="text"
|
|
268
|
+
class="search-input"
|
|
269
|
+
placeholder="Search…"
|
|
270
|
+
.value=${this._search}
|
|
271
|
+
@input=${this._onSearchInput}
|
|
272
|
+
@keydown=${this._onPanelKeydown}
|
|
273
|
+
aria-label="Search options"
|
|
274
|
+
/>
|
|
275
|
+
</div>
|
|
276
|
+
` : n}
|
|
277
|
+
<div class="option-list">
|
|
278
|
+
${this._renderOptions()}
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<span class="sr-only" aria-live="polite">${this._liveMessage}</span>
|
|
283
|
+
|
|
284
|
+
${r ? t`<span id=${e} class="error-text" role="alert">${this.errorMessage}</span>` : n}
|
|
285
|
+
</div>
|
|
286
|
+
`;
|
|
287
|
+
}
|
|
288
|
+
constructor(...e) {
|
|
289
|
+
super(...e), this._uid = `app-selector-${++p}`, this.items = [], this.groups = [], this.value = [], this.label = "", this.placeholder = "Select…", this.searchable = !1, this.multiple = !1, this.disabled = !1, this.name = "", this.state = "default", this.errorMessage = "", this._open = !1, this._search = "", this._focusedIndex = -1, this._liveMessage = "", this._onDocumentClick = (e) => {
|
|
290
|
+
this._open && (e.composedPath().includes(this) || this._close());
|
|
291
|
+
}, this._onDocumentKeydown = (e) => {
|
|
292
|
+
e.key === "Escape" && this._open && (this._close(), this.shadowRoot?.querySelector(".trigger")?.focus());
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
l([a({ attribute: !1 })], m.prototype, "items", void 0), l([a({ attribute: !1 })], m.prototype, "groups", void 0), l([a({ attribute: !1 })], m.prototype, "value", void 0), l([a({ type: String })], m.prototype, "label", void 0), l([a({ type: String })], m.prototype, "placeholder", void 0), l([a({ type: Boolean })], m.prototype, "searchable", void 0), l([a({ type: Boolean })], m.prototype, "multiple", void 0), l([a({ type: Boolean })], m.prototype, "disabled", void 0), l([a({ type: String })], m.prototype, "name", void 0), l([a({ type: String })], m.prototype, "state", void 0), l([a({
|
|
297
|
+
type: String,
|
|
298
|
+
attribute: "error-message"
|
|
299
|
+
})], m.prototype, "errorMessage", void 0), l([o()], m.prototype, "_open", void 0), l([o()], m.prototype, "_search", void 0), l([o()], m.prototype, "_focusedIndex", void 0), l([o()], m.prototype, "_liveMessage", void 0), m = l([i("app-selector")], m);
|
|
300
|
+
export { m as t };
|
package/dist/selector.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const tailwindBase: import('lit').CSSResult;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { LitElement as e, html as t, nothing as n, unsafeCSS as r } from "lit";
|
|
2
|
+
import { customElement as i, property as a, state as o } from "lit/decorators.js";
|
|
3
|
+
import { repeat as s } from "lit/directives/repeat.js";
|
|
4
|
+
var c = ":host{color:var(--table-text-color,var(--color-text));font-size:.875rem;display:block}.toolbar{justify-content:flex-end;margin-block-end:.5rem;display:flex;position:relative}.toggle-btn{color:var(--color-text-muted);background:var(--color-surface-elevated);border:1px solid var(--table-border-color,var(--color-border));border-radius:var(--radius-button);cursor:pointer;align-items:center;gap:.375rem;padding:.375rem .625rem;font-size:.8125rem;font-weight:500;transition:color .15s,background .15s;display:inline-flex}.toggle-btn:hover{color:var(--color-text);background:var(--color-primary-muted)}.toggle-panel{z-index:10;background:var(--color-surface);border:1px solid var(--table-border-color,var(--color-border));border-radius:var(--radius-card);min-width:160px;padding:.375rem;position:absolute;top:calc(100% + 4px);right:0;box-shadow:0 4px 12px oklch(0% 0 0/.1)}.toggle-item{border-radius:calc(var(--radius-card) - 2px);cursor:pointer;user-select:none;align-items:center;gap:.5rem;padding:.375rem .5rem;font-size:.8125rem;display:flex}.toggle-item:hover{background:var(--color-primary-muted)}.toggle-item input[type=checkbox]{accent-color:var(--color-primary);cursor:pointer;width:14px;height:14px}.table-wrapper{border:1px solid var(--table-border-color,var(--color-border));border-radius:var(--radius-card);position:relative;overflow-x:auto}.loading-overlay{background:oklch(from var(--color-surface) l c h / .7);z-index:2;border-radius:inherit;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.spinner{border:2px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;width:1.5rem;height:1.5rem;animation:.6s linear infinite table-spin}@keyframes table-spin{to{transform:rotate(360deg)}}table{table-layout:fixed;border-collapse:collapse;background:var(--table-body-bg,var(--color-surface));width:100%}thead{z-index:1;position:sticky;top:0}th{padding:var(--table-cell-padding-block,.5rem) var(--table-cell-padding-inline,.75rem);font-weight:var(--table-header-font-weight,600);text-align:left;background:var(--table-header-bg,var(--color-surface-elevated));border-bottom:1px solid var(--table-border-color,var(--color-border));white-space:nowrap}.group-row th{border-bottom:none;padding-block-end:.25rem}.group-header{text-align:center;border-inline:1px solid var(--table-border-color,var(--color-border));color:var(--color-primary);text-transform:uppercase;letter-spacing:.05em;font-size:.75rem;border-bottom:2px solid var(--color-primary)!important}.group-empty{border-inline:none;border-bottom:1px solid #0000!important}th.sortable{padding:0}.sort-btn{width:100%;padding:var(--table-cell-padding-block,.5rem) var(--table-cell-padding-inline,.75rem);font-weight:inherit;font-size:inherit;text-align:left;cursor:pointer;color:inherit;white-space:nowrap;background:0 0;border:none;align-items:center;gap:.375rem;display:flex}.sort-btn:hover{background:var(--color-primary-muted)}.sort-icon{color:var(--color-text-muted);flex-shrink:0;transition:color .15s}.sort-icon--none .sort-asc,.sort-icon--none .sort-desc{opacity:.35}.sort-icon--asc{color:var(--color-primary)}.sort-icon--asc .sort-asc{opacity:1}.sort-icon--asc .sort-desc{opacity:0}.sort-icon--desc{color:var(--color-primary)}.sort-icon--desc .sort-asc{opacity:0}.sort-icon--desc .sort-desc{opacity:1}td{padding:var(--table-cell-padding-block,.5rem) var(--table-cell-padding-inline,.75rem);border-bottom:1px solid var(--table-border-color,var(--color-border));vertical-align:middle}tbody tr:last-child td{border-bottom:none}tbody tr:hover td{background:var(--color-primary-muted)}.empty-cell{text-align:center;color:var(--color-text-muted);padding-block:2rem}.pagination{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.5rem;margin-block-start:.75rem;display:flex}.page-info{color:var(--color-text-muted);font-size:.8125rem}.page-controls{align-items:center;gap:.25rem;display:flex}.page-btn{border:1px solid var(--table-border-color,var(--color-border));border-radius:var(--radius-button);background:var(--color-surface);min-width:2rem;height:2rem;color:var(--color-text);cursor:pointer;justify-content:center;align-items:center;padding-inline:.375rem;font-size:.8125rem;transition:background .15s,color .15s,border-color .15s;display:inline-flex}.page-btn:hover:not(:disabled){background:var(--color-primary-muted);border-color:var(--color-primary);color:var(--color-primary)}.page-btn.active{background:var(--color-primary);border-color:var(--color-primary);color:var(--color-text-inverse)}.page-btn:disabled{opacity:.4;cursor:not-allowed}.page-ellipsis{min-width:2rem;height:2rem;color:var(--color-text-muted);justify-content:center;align-items:center;font-size:.8125rem;display:inline-flex}.sr-only{clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}";
|
|
5
|
+
function l(e, t, n, r) {
|
|
6
|
+
var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
|
|
7
|
+
if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
|
|
8
|
+
else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
|
|
9
|
+
return i > 3 && a && Object.defineProperty(t, n, a), a;
|
|
10
|
+
}
|
|
11
|
+
var u = class extends e {
|
|
12
|
+
static {
|
|
13
|
+
this.styles = [r(c)];
|
|
14
|
+
}
|
|
15
|
+
willUpdate(e) {
|
|
16
|
+
if (e.has("columns")) {
|
|
17
|
+
let e = /* @__PURE__ */ new Set();
|
|
18
|
+
for (let t of this.columns) t.hidden && e.add(t.key);
|
|
19
|
+
this._hiddenCols = e;
|
|
20
|
+
}
|
|
21
|
+
(e.has("rows") || e.has("pageSize")) && !this._isServerPagination && (this.page = 1);
|
|
22
|
+
}
|
|
23
|
+
get _visibleCols() {
|
|
24
|
+
return this.columns.filter((e) => !this._hiddenCols.has(e.key));
|
|
25
|
+
}
|
|
26
|
+
get _hasGroups() {
|
|
27
|
+
return this.columns.some((e) => e.group);
|
|
28
|
+
}
|
|
29
|
+
get _hasPagination() {
|
|
30
|
+
return this.pageSize > 0;
|
|
31
|
+
}
|
|
32
|
+
get _isServerPagination() {
|
|
33
|
+
return this.totalItems > 0 && this.pageSize > 0;
|
|
34
|
+
}
|
|
35
|
+
get _sortedRows() {
|
|
36
|
+
if (this.externalSort || !this._sortCol) return this.rows;
|
|
37
|
+
let e = this._sortCol, t = this._sortDir === "asc" ? 1 : -1;
|
|
38
|
+
return [...this.rows].sort((n, r) => {
|
|
39
|
+
let i = n[e], a = r[e];
|
|
40
|
+
return i == null && a == null ? 0 : i == null ? t : a == null ? -t : typeof i == "number" && typeof a == "number" ? (i - a) * t : String(i).localeCompare(String(a)) * t;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
get _pagedRows() {
|
|
44
|
+
if (this._isServerPagination || !this._hasPagination) return this._sortedRows;
|
|
45
|
+
let e = (this.page - 1) * this.pageSize;
|
|
46
|
+
return this._sortedRows.slice(e, e + this.pageSize);
|
|
47
|
+
}
|
|
48
|
+
get _totalPages() {
|
|
49
|
+
return this._isServerPagination ? Math.max(1, Math.ceil(this.totalItems / this.pageSize)) : this._hasPagination ? Math.max(1, Math.ceil(this.rows.length / this.pageSize)) : 1;
|
|
50
|
+
}
|
|
51
|
+
_dispatchSort(e, t) {
|
|
52
|
+
this.dispatchEvent(new CustomEvent("table-sort", {
|
|
53
|
+
detail: {
|
|
54
|
+
column: e,
|
|
55
|
+
dir: t,
|
|
56
|
+
pageSize: this.pageSize
|
|
57
|
+
},
|
|
58
|
+
bubbles: !0,
|
|
59
|
+
composed: !0
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
_dispatchPage(e) {
|
|
63
|
+
this.dispatchEvent(new CustomEvent("table-page", {
|
|
64
|
+
detail: {
|
|
65
|
+
page: e,
|
|
66
|
+
pageSize: this.pageSize
|
|
67
|
+
},
|
|
68
|
+
bubbles: !0,
|
|
69
|
+
composed: !0
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
_dispatchColumnToggle(e, t) {
|
|
73
|
+
this.dispatchEvent(new CustomEvent("table-column-toggle", {
|
|
74
|
+
detail: {
|
|
75
|
+
column: e,
|
|
76
|
+
hidden: t
|
|
77
|
+
},
|
|
78
|
+
bubbles: !0,
|
|
79
|
+
composed: !0
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
_handleSortClick(e) {
|
|
83
|
+
this._sortCol === e ? this._sortDir = this._sortDir === "asc" ? "desc" : "asc" : (this._sortCol = e, this._sortDir = "asc"), this._isServerPagination || (this.page = 1), this._dispatchSort(this._sortCol, this._sortDir);
|
|
84
|
+
}
|
|
85
|
+
_handleToggleColumn(e) {
|
|
86
|
+
let t = new Set(this._hiddenCols), n = !t.has(e);
|
|
87
|
+
n ? t.add(e) : t.delete(e), this._hiddenCols = t, this._dispatchColumnToggle(e, n);
|
|
88
|
+
}
|
|
89
|
+
_handlePageChange(e) {
|
|
90
|
+
this.page = Math.max(1, Math.min(e, this._totalPages)), this._dispatchPage(this.page);
|
|
91
|
+
}
|
|
92
|
+
_renderColumnToggle() {
|
|
93
|
+
return t`
|
|
94
|
+
<div class="toolbar">
|
|
95
|
+
<button
|
|
96
|
+
class="toggle-btn"
|
|
97
|
+
aria-expanded=${this._togglePanelOpen}
|
|
98
|
+
@click=${() => {
|
|
99
|
+
this._togglePanelOpen = !this._togglePanelOpen;
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
103
|
+
<rect x="1" y="3" width="14" height="1.5" rx=".75" fill="currentColor"/>
|
|
104
|
+
<rect x="1" y="7.25" width="14" height="1.5" rx=".75" fill="currentColor"/>
|
|
105
|
+
<rect x="1" y="11.5" width="14" height="1.5" rx=".75" fill="currentColor"/>
|
|
106
|
+
<circle cx="5" cy="3.75" r="2" fill="var(--color-surface)" stroke="currentColor" stroke-width="1.5"/>
|
|
107
|
+
<circle cx="11" cy="8" r="2" fill="var(--color-surface)" stroke="currentColor" stroke-width="1.5"/>
|
|
108
|
+
<circle cx="5" cy="12.25" r="2" fill="var(--color-surface)" stroke="currentColor" stroke-width="1.5"/>
|
|
109
|
+
</svg>
|
|
110
|
+
Columns
|
|
111
|
+
</button>
|
|
112
|
+
|
|
113
|
+
${this._togglePanelOpen ? t`
|
|
114
|
+
<div class="toggle-panel" role="menu">
|
|
115
|
+
${this.columns.map((e) => t`
|
|
116
|
+
<label class="toggle-item" role="menuitemcheckbox">
|
|
117
|
+
<input
|
|
118
|
+
type="checkbox"
|
|
119
|
+
.checked=${!this._hiddenCols.has(e.key)}
|
|
120
|
+
@change=${() => this._handleToggleColumn(e.key)}
|
|
121
|
+
/>
|
|
122
|
+
${e.label}
|
|
123
|
+
</label>
|
|
124
|
+
`)}
|
|
125
|
+
</div>
|
|
126
|
+
` : n}
|
|
127
|
+
</div>
|
|
128
|
+
`;
|
|
129
|
+
}
|
|
130
|
+
_renderGroupRow(e) {
|
|
131
|
+
let n = [];
|
|
132
|
+
for (let t of e) {
|
|
133
|
+
let e = n[n.length - 1];
|
|
134
|
+
e && e.label === (t.group ?? null) ? e.span++ : n.push({
|
|
135
|
+
label: t.group ?? null,
|
|
136
|
+
span: 1
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return t`
|
|
140
|
+
<tr class="group-row">
|
|
141
|
+
${n.map((e) => t`
|
|
142
|
+
<th
|
|
143
|
+
colspan=${e.span}
|
|
144
|
+
class=${e.label ? "group-header" : "group-empty"}
|
|
145
|
+
>${e.label ?? ""}</th>
|
|
146
|
+
`)}
|
|
147
|
+
</tr>
|
|
148
|
+
`;
|
|
149
|
+
}
|
|
150
|
+
_renderHeaderRow(e) {
|
|
151
|
+
return t`
|
|
152
|
+
<tr>
|
|
153
|
+
${e.map((e) => {
|
|
154
|
+
let n = this._sortCol === e.key;
|
|
155
|
+
return t`
|
|
156
|
+
<th
|
|
157
|
+
style=${e.width ? `width:${e.width}` : ""}
|
|
158
|
+
class=${e.sortable ? "sortable" : ""}
|
|
159
|
+
aria-sort=${n ? this._sortDir === "asc" ? "ascending" : "descending" : "none"}
|
|
160
|
+
>
|
|
161
|
+
${e.sortable ? t`
|
|
162
|
+
<button class="sort-btn" @click=${() => this._handleSortClick(e.key)}>
|
|
163
|
+
<span>${e.label}</span>
|
|
164
|
+
<svg
|
|
165
|
+
class="sort-icon sort-icon--${n ? this._sortDir : "none"}"
|
|
166
|
+
width="12"
|
|
167
|
+
height="12"
|
|
168
|
+
viewBox="0 0 12 12"
|
|
169
|
+
fill="currentColor"
|
|
170
|
+
aria-hidden="true"
|
|
171
|
+
>
|
|
172
|
+
<path class="sort-asc" d="M6 1 L10 6 H2 Z"/>
|
|
173
|
+
<path class="sort-desc" d="M6 11 L2 6 H10 Z"/>
|
|
174
|
+
</svg>
|
|
175
|
+
</button>
|
|
176
|
+
` : e.label}
|
|
177
|
+
</th>
|
|
178
|
+
`;
|
|
179
|
+
})}
|
|
180
|
+
</tr>
|
|
181
|
+
`;
|
|
182
|
+
}
|
|
183
|
+
_renderRows(e) {
|
|
184
|
+
let n = this._pagedRows;
|
|
185
|
+
return n.length === 0 ? t`
|
|
186
|
+
<tr>
|
|
187
|
+
<td class="empty-cell" colspan=${e.length}>No data</td>
|
|
188
|
+
</tr>
|
|
189
|
+
` : s(n, (e, t) => t, (n, r) => t`
|
|
190
|
+
<tr>
|
|
191
|
+
${e.map((e) => t`
|
|
192
|
+
<td style=${e.width ? `width:${e.width}` : ""}>
|
|
193
|
+
${e.renderCell ? e.renderCell(n, r) : n[e.key] ?? ""}
|
|
194
|
+
</td>
|
|
195
|
+
`)}
|
|
196
|
+
</tr>
|
|
197
|
+
`);
|
|
198
|
+
}
|
|
199
|
+
_renderPagination() {
|
|
200
|
+
let e = this._totalPages, r = this.page, i = this._isServerPagination ? this.totalItems : this.rows.length, a = [], o = (e) => {
|
|
201
|
+
a.includes(e) || a.push(e);
|
|
202
|
+
};
|
|
203
|
+
o(1), r - 2 > 2 && a.push("ellipsis");
|
|
204
|
+
for (let t = Math.max(2, r - 1); t <= Math.min(e - 1, r + 1); t++) o(t);
|
|
205
|
+
return r + 2 < e - 1 && a.push("ellipsis"), e > 1 && o(e), t`
|
|
206
|
+
<div class="pagination" role="navigation" aria-label="Pagination">
|
|
207
|
+
<span class="page-info">${(r - 1) * this.pageSize + 1}–${Math.min(r * this.pageSize, i)} of ${i}</span>
|
|
208
|
+
<div class="page-controls">
|
|
209
|
+
<button
|
|
210
|
+
class="page-btn"
|
|
211
|
+
?disabled=${r === 1}
|
|
212
|
+
aria-label="Previous page"
|
|
213
|
+
@click=${() => this._handlePageChange(r - 1)}
|
|
214
|
+
>‹</button>
|
|
215
|
+
|
|
216
|
+
${a.map((e) => e === "ellipsis" ? t`<span class="page-ellipsis">…</span>` : t`
|
|
217
|
+
<button
|
|
218
|
+
class="page-btn ${e === r ? "active" : ""}"
|
|
219
|
+
aria-current=${e === r ? "page" : n}
|
|
220
|
+
@click=${() => this._handlePageChange(e)}
|
|
221
|
+
>${e}</button>
|
|
222
|
+
`)}
|
|
223
|
+
|
|
224
|
+
<button
|
|
225
|
+
class="page-btn"
|
|
226
|
+
?disabled=${r === e}
|
|
227
|
+
aria-label="Next page"
|
|
228
|
+
@click=${() => this._handlePageChange(r + 1)}
|
|
229
|
+
>›</button>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
<span class="sr-only" aria-live="polite">Page ${r} of ${e}</span>
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
render() {
|
|
236
|
+
let e = this._visibleCols;
|
|
237
|
+
return t`
|
|
238
|
+
${this.showColumnToggle ? this._renderColumnToggle() : n}
|
|
239
|
+
|
|
240
|
+
<div class="table-wrapper" role="region" aria-label="Data table">
|
|
241
|
+
<table aria-busy=${this.loading}>
|
|
242
|
+
<thead>
|
|
243
|
+
${this._hasGroups ? this._renderGroupRow(e) : n}
|
|
244
|
+
${this._renderHeaderRow(e)}
|
|
245
|
+
</thead>
|
|
246
|
+
<tbody>
|
|
247
|
+
${this._renderRows(e)}
|
|
248
|
+
</tbody>
|
|
249
|
+
</table>
|
|
250
|
+
|
|
251
|
+
${this.loading ? t`
|
|
252
|
+
<div class="loading-overlay" role="status">
|
|
253
|
+
<div class="spinner" aria-hidden="true"></div>
|
|
254
|
+
<span class="sr-only">Loading table data</span>
|
|
255
|
+
</div>
|
|
256
|
+
` : n}
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
${this._hasPagination ? this._renderPagination() : n}
|
|
260
|
+
`;
|
|
261
|
+
}
|
|
262
|
+
constructor(...e) {
|
|
263
|
+
super(...e), this.columns = [], this.rows = [], this.pageSize = 0, this.totalItems = 0, this.page = 1, this.loading = !1, this.externalSort = !1, this.showColumnToggle = !1, this._hiddenCols = /* @__PURE__ */ new Set(), this._sortCol = null, this._sortDir = "asc", this._togglePanelOpen = !1;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
l([a({ attribute: !1 })], u.prototype, "columns", void 0), l([a({ attribute: !1 })], u.prototype, "rows", void 0), l([a({
|
|
267
|
+
type: Number,
|
|
268
|
+
attribute: "page-size"
|
|
269
|
+
})], u.prototype, "pageSize", void 0), l([a({
|
|
270
|
+
type: Number,
|
|
271
|
+
attribute: "total-items"
|
|
272
|
+
})], u.prototype, "totalItems", void 0), l([a({ type: Number })], u.prototype, "page", void 0), l([a({ type: Boolean })], u.prototype, "loading", void 0), l([a({
|
|
273
|
+
type: Boolean,
|
|
274
|
+
attribute: "external-sort"
|
|
275
|
+
})], u.prototype, "externalSort", void 0), l([a({
|
|
276
|
+
type: Boolean,
|
|
277
|
+
attribute: "show-column-toggle"
|
|
278
|
+
})], u.prototype, "showColumnToggle", void 0), l([o()], u.prototype, "_hiddenCols", void 0), l([o()], u.prototype, "_sortCol", void 0), l([o()], u.prototype, "_sortDir", void 0), l([o()], u.prototype, "_togglePanelOpen", void 0), u = l([i("app-table")], u);
|
|
279
|
+
export { u as t };
|