@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.
Files changed (83) hide show
  1. package/dist/button-DYrT530y.js +39 -0
  2. package/dist/button.js +2 -0
  3. package/dist/components/button/button-types.d.ts +2 -0
  4. package/dist/components/button/button.d.ts +14 -0
  5. package/dist/components/button/index.d.ts +2 -0
  6. package/dist/components/dropdown-button/dropdown-button-types.d.ts +13 -0
  7. package/dist/components/dropdown-button/dropdown-button.d.ts +34 -0
  8. package/dist/components/dropdown-button/index.d.ts +2 -0
  9. package/dist/components/input/index.d.ts +2 -0
  10. package/dist/components/input/input-types.d.ts +2 -0
  11. package/dist/components/input/input.d.ts +22 -0
  12. package/dist/components/layouts/form/form-layout-types.d.ts +3 -0
  13. package/dist/components/layouts/form/form-layout.d.ts +53 -0
  14. package/dist/components/layouts/form/index.d.ts +2 -0
  15. package/dist/components/layouts/index.d.ts +3 -0
  16. package/dist/components/layouts/page/index.d.ts +1 -0
  17. package/dist/components/layouts/page/layout.d.ts +20 -0
  18. package/dist/components/menu/index.d.ts +2 -0
  19. package/dist/components/menu/menu-types.d.ts +16 -0
  20. package/dist/components/menu/menu.d.ts +36 -0
  21. package/dist/components/modal/index.d.ts +2 -0
  22. package/dist/components/modal/modal-types.d.ts +2 -0
  23. package/dist/components/modal/modal.d.ts +103 -0
  24. package/dist/components/selector/index.d.ts +2 -0
  25. package/dist/components/selector/selector-types.d.ts +19 -0
  26. package/dist/components/selector/selector.d.ts +56 -0
  27. package/dist/components/table/index.d.ts +2 -0
  28. package/dist/components/table/table-types.d.ts +35 -0
  29. package/dist/components/table/table.d.ts +47 -0
  30. package/dist/components/tabs/index.d.ts +2 -0
  31. package/dist/components/tabs/tabs.d.ts +19 -0
  32. package/dist/components/toggle/index.d.ts +2 -0
  33. package/dist/components/toggle/toggle-types.d.ts +4 -0
  34. package/dist/components/toggle/toggle.d.ts +15 -0
  35. package/dist/dropdown-button-B6XNoy4L.js +172 -0
  36. package/dist/dropdown-button.js +2 -0
  37. package/dist/form-layout-DCX8X-8-.js +140 -0
  38. package/dist/index.d.ts +22 -0
  39. package/dist/input-BVlPYqTe.js +70 -0
  40. package/dist/input.js +2 -0
  41. package/dist/layout-CYvgu_WE.js +23 -0
  42. package/dist/layouts.js +3 -0
  43. package/dist/menu-DmAFaVi5.js +248 -0
  44. package/dist/menu.js +2 -0
  45. package/dist/mock/table-data.d.ts +16 -0
  46. package/dist/modal-v1GlqMF_.js +174 -0
  47. package/dist/modal.js +2 -0
  48. package/dist/react/button.d.ts +2 -0
  49. package/dist/react/button.js +9 -0
  50. package/dist/react/dropdown-button.d.ts +6 -0
  51. package/dist/react/dropdown-button.js +10 -0
  52. package/dist/react/form-layout.d.ts +8 -0
  53. package/dist/react/form-layout.js +14 -0
  54. package/dist/react/index.d.ts +21 -0
  55. package/dist/react/input.d.ts +2 -0
  56. package/dist/react/input.js +9 -0
  57. package/dist/react/layout.d.ts +2 -0
  58. package/dist/react/layout.js +9 -0
  59. package/dist/react/menu.d.ts +7 -0
  60. package/dist/react/menu.js +13 -0
  61. package/dist/react/modal.d.ts +7 -0
  62. package/dist/react/modal.js +14 -0
  63. package/dist/react/selector.d.ts +6 -0
  64. package/dist/react/selector.js +10 -0
  65. package/dist/react/table.d.ts +8 -0
  66. package/dist/react/table.js +14 -0
  67. package/dist/react/tabs.d.ts +5 -0
  68. package/dist/react/tabs.js +10 -0
  69. package/dist/react/toggle.d.ts +6 -0
  70. package/dist/react/toggle.js +10 -0
  71. package/dist/react.js +12 -0
  72. package/dist/selector-Bl7Nbkqo.js +300 -0
  73. package/dist/selector.js +2 -0
  74. package/dist/styles/tailwind-base.d.ts +1 -0
  75. package/dist/table--O5km0Wv.js +279 -0
  76. package/dist/table.js +2 -0
  77. package/dist/tabs-C2lP0uxY.js +94 -0
  78. package/dist/tabs.js +2 -0
  79. package/dist/toggle-D6UMZ8UZ.js +59 -0
  80. package/dist/toggle.js +2 -0
  81. package/dist/vite.svg +1 -0
  82. package/dist/web-components.js +24 -0
  83. 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 };
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./selector-Bl7Nbkqo.js";
2
+ export { e as Selector };
@@ -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 };