@leavepulse/ui 0.29.3 → 0.29.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/assets/LpChart-CzgCGaAA.css +8 -0
  2. package/dist/assets/{LpTable-B9Iko3XD.css → LpTable-Bz3uJNa3.css} +8 -8
  3. package/dist/chunks/{LpAppShell-CGX0DlIW.js → LpAppShell-BJk3b-u4.js} +1 -1
  4. package/dist/chunks/{LpAvatar-CzCE5cXg.js → LpAvatar-D3l4nabg.js} +1 -1
  5. package/dist/chunks/{LpCard-DSefTGEH.js → LpCard-D0M2ZCnB.js} +1 -1
  6. package/dist/chunks/{LpContextMenu-D0mzXqA7.js → LpContextMenu-B6WBLleS.js} +55 -8
  7. package/dist/chunks/{LpFileTree-BaV7f0O7.js → LpFileTree-DfFqY__1.js} +1 -1
  8. package/dist/chunks/{LpFileTreeNode-BzpBa7R7.js → LpFileTreeNode-COchUMNn.js} +1 -1
  9. package/dist/chunks/{LpLogViewer-CKmEQYnm.js → LpLogViewer-CVaGfTF_.js} +1 -1
  10. package/dist/chunks/{LpNotificationBell-Dvu-b6Vn.js → LpNotificationBell-CTsIcPqX.js} +1 -1
  11. package/dist/chunks/{LpPie-BkjWlfSw.js → LpPie-BL1vTDSM.js} +1 -1
  12. package/dist/chunks/{LpSidebar-CWehDCxN.js → LpSidebar-C_Mr-JPI.js} +1 -1
  13. package/dist/chunks/{LpSidebarNav-5RGNr2D3.js → LpSidebarNav-D6v12-36.js} +1 -1
  14. package/dist/chunks/{LpThemeSwitcher-Dj4VcTu7.js → LpThemeSwitcher-r1te9nB2.js} +1 -1
  15. package/dist/components/LpAppShell.vue.js +1 -1
  16. package/dist/components/LpAvatar.vue.js +1 -1
  17. package/dist/components/LpCard.vue.js +1 -1
  18. package/dist/components/LpChart.vue.js +814 -2
  19. package/dist/components/LpContextMenu.vue.d.ts +7 -0
  20. package/dist/components/LpContextMenu.vue.js +1 -1
  21. package/dist/components/LpFileTree.vue.js +1 -1
  22. package/dist/components/LpFileTreeNode.vue.js +1 -1
  23. package/dist/components/LpLogViewer.vue.js +1 -1
  24. package/dist/components/LpNotificationBell.vue.js +1 -1
  25. package/dist/components/LpPie.vue.js +1 -1
  26. package/dist/components/LpSidebar.vue.js +1 -1
  27. package/dist/components/LpSidebarNav.vue.js +1 -1
  28. package/dist/components/LpTable.vue.d.ts +19 -0
  29. package/dist/components/LpTable.vue.js +233 -143
  30. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  31. package/dist/index.js +124 -124
  32. package/package.json +1 -1
  33. package/src/components/LpChart.vue +337 -63
  34. package/src/components/LpContextMenu.vue +49 -0
  35. package/src/components/LpTable.vue +166 -23
  36. package/dist/chunks/LpChart-UiU4RhXP.js +0 -672
@@ -9,6 +9,13 @@ export interface ContextMenuItemDef {
9
9
  onSelect?: () => void;
10
10
  /** Nested submenu. When present, onSelect is ignored. */
11
11
  children?: ContextMenuItemDef[];
12
+ /**
13
+ * Renders as a tick-box rather than a plain item, and the menu stays open on
14
+ * select. For the lists where the point is to set several at once — which
15
+ * columns to show, which values to filter by — and closing after each one
16
+ * would mean reopening the menu for every tick.
17
+ */
18
+ checked?: boolean;
12
19
  }
13
20
  type __VLS_Props = {
14
21
  items: ContextMenuItemDef[];
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpContextMenu-D0mzXqA7.js";
1
+ import { _ as _sfc_main } from "../chunks/LpContextMenu-B6WBLleS.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpFileTree-BaV7f0O7.js";
1
+ import { _ as _sfc_main } from "../chunks/LpFileTree-DfFqY__1.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpFileTreeNode-BzpBa7R7.js";
1
+ import { _ as _sfc_main } from "../chunks/LpFileTreeNode-COchUMNn.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpLogViewer-CKmEQYnm.js";
1
+ import { _ as _sfc_main } from "../chunks/LpLogViewer-CVaGfTF_.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpNotificationBell-Dvu-b6Vn.js";
1
+ import { _ as _sfc_main } from "../chunks/LpNotificationBell-CTsIcPqX.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpPie-BkjWlfSw.js";
1
+ import { _ as _sfc_main } from "../chunks/LpPie-BL1vTDSM.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpSidebar-CWehDCxN.js";
1
+ import { _ as _sfc_main } from "../chunks/LpSidebar-C_Mr-JPI.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpSidebarNav-5RGNr2D3.js";
1
+ import { _ as _sfc_main } from "../chunks/LpSidebarNav-D6v12-36.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -6,6 +6,21 @@ export interface TableColumn<Row> {
6
6
  width?: string;
7
7
  /** Allow clicking the header to sort by this column. */
8
8
  sortable?: boolean;
9
+ /**
10
+ * Offer "show only these values" in the header's menu, built from the values
11
+ * actually present in the rows. For a column that holds a small vocabulary —
12
+ * a type, a state, a site — where the question is "just the mains leads,
13
+ * please". Pointless on a column of unique values, so it is opt-in.
14
+ */
15
+ filterable?: boolean;
16
+ /**
17
+ * How a raw cell value reads in that filter list. `power_ac` is the stored
18
+ * vocabulary; the menu should say what the column itself says.
19
+ */
20
+ valueLabel?: (value: unknown) => string;
21
+ /** Keep this column out of the show/hide list — an actions column has no
22
+ * name to offer and nothing to gain from being hidden. */
23
+ alwaysVisible?: boolean;
9
24
  }
10
25
  export interface SortState {
11
26
  key: string;
@@ -36,6 +51,10 @@ declare const __VLS_export: <T extends Record<string, unknown>>(__VLS_props: Non
36
51
  sortAscLabel?: string;
37
52
  sortDescLabel?: string;
38
53
  sortClearLabel?: string;
54
+ /** Wording for the value filter and the column chooser. */
55
+ filterLabel?: string;
56
+ showAllLabel?: string;
57
+ columnsLabel?: string;
39
58
  } & {
40
59
  "onUpdate:selected"?: ((value: (string | number)[]) => any) | undefined;
41
60
  "onUpdate:sort"?: ((value: SortState | null) => any) | undefined;
@@ -1,11 +1,11 @@
1
- import { defineComponent, ref, computed, watch, onBeforeUnmount, openBlock, createBlock, withCtx, createElementVNode, normalizeClass, createElementBlock, createVNode, createCommentVNode, Fragment, renderList, normalizeStyle, createTextVNode, toDisplayString, TransitionGroup, unref, mergeProps, withModifiers, renderSlot } from "vue";
2
- import { _ as _sfc_main$2 } from "../chunks/LpCheckbox-BO0zuuPh.js";
3
- import { _ as _sfc_main$3 } from "../chunks/LpContextMenu-D0mzXqA7.js";
1
+ import { defineComponent, ref, computed, watch, onBeforeUnmount, openBlock, createBlock, withCtx, createVNode, createElementVNode, normalizeClass, createElementBlock, createCommentVNode, Fragment, renderList, normalizeStyle, createTextVNode, toDisplayString, TransitionGroup, unref, mergeProps, withModifiers, renderSlot } from "vue";
2
+ import { _ as _sfc_main$3 } from "../chunks/LpCheckbox-BO0zuuPh.js";
3
+ import { _ as _sfc_main$2 } from "../chunks/LpContextMenu-B6WBLleS.js";
4
4
  import { _ as _sfc_main$4 } from "../chunks/LpIcon-CCnX5_2j.js";
5
5
  import { _ as _sfc_main$1 } from "../chunks/LpScrollArea-D8xyKXcF.js";
6
6
  import { useRovingFocus } from "../composables/useRovingFocus.js";
7
7
  import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
8
- import '../assets/LpTable-B9Iko3XD.css';const _hoisted_1 = { class: "w-full border-collapse text-sm" };
8
+ import '../assets/LpTable-Bz3uJNa3.css';const _hoisted_1 = { class: "w-full border-collapse text-sm" };
9
9
  const _hoisted_2 = { class: "border-b border-line bg-surface-soft" };
10
10
  const _hoisted_3 = {
11
11
  key: 0,
@@ -31,7 +31,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
31
31
  rowMenu: {},
32
32
  sortAscLabel: { default: "Sort ascending" },
33
33
  sortDescLabel: { default: "Sort descending" },
34
- sortClearLabel: { default: "Clear sorting" }
34
+ sortClearLabel: { default: "Clear sorting" },
35
+ filterLabel: { default: "Show only" },
36
+ showAllLabel: { default: "Show all" },
37
+ columnsLabel: { default: "Columns" }
35
38
  },
36
39
  emits: ["update:selected", "update:sort", "rowClick"],
37
40
  setup(__props, { emit: __emit }) {
@@ -52,13 +55,51 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
52
55
  }
53
56
  const ownSort = ref(null);
54
57
  const activeSort = computed(() => props.sort ?? ownSort.value);
58
+ const hiddenValues = ref({});
59
+ const hiddenColumns = ref(/* @__PURE__ */ new Set());
60
+ const visibleColumns = computed(
61
+ () => props.columns.filter((c) => !hiddenColumns.value.has(c.key))
62
+ );
63
+ function valuesOf(col) {
64
+ const seen = [];
65
+ for (const row of props.rows) {
66
+ const v = row[col.key];
67
+ if (!seen.includes(v)) seen.push(v);
68
+ }
69
+ return seen;
70
+ }
71
+ function isValueHidden(key, value) {
72
+ return hiddenValues.value[key]?.has(value) ?? false;
73
+ }
74
+ function toggleValue(key, value) {
75
+ const next = new Set(hiddenValues.value[key] ?? []);
76
+ if (next.has(value)) next.delete(value);
77
+ else next.add(value);
78
+ hiddenValues.value = { ...hiddenValues.value, [key]: next };
79
+ }
80
+ function showAllValues(key) {
81
+ hiddenValues.value = { ...hiddenValues.value, [key]: /* @__PURE__ */ new Set() };
82
+ }
83
+ function toggleColumn(key) {
84
+ const next = new Set(hiddenColumns.value);
85
+ if (next.has(key)) next.delete(key);
86
+ else next.add(key);
87
+ hiddenColumns.value = next;
88
+ }
89
+ const filteredRows = computed(() => {
90
+ const active = Object.entries(hiddenValues.value).filter(([, set]) => set.size);
91
+ if (!active.length) return props.rows;
92
+ return props.rows.filter(
93
+ (row) => active.every(([key, hidden]) => !hidden.has(row[key]))
94
+ );
95
+ });
55
96
  const displayRows = computed(() => {
56
97
  const s = activeSort.value;
57
- if (!s) return props.rows;
98
+ if (!s) return filteredRows.value;
58
99
  const col = props.columns.find((c) => c.key === s.key);
59
- if (!col?.sortable) return props.rows;
100
+ if (!col?.sortable) return filteredRows.value;
60
101
  const factor = s.dir === "asc" ? 1 : -1;
61
- return [...props.rows].sort((a, b) => compare(a[s.key], b[s.key]) * factor);
102
+ return [...filteredRows.value].sort((a, b) => compare(a[s.key], b[s.key]) * factor);
62
103
  });
63
104
  function compare(a, b) {
64
105
  if (a == null && b == null) return 0;
@@ -83,31 +124,73 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
83
124
  return s.dir === "asc" ? "lucide:arrow-up" : "lucide:arrow-down";
84
125
  }
85
126
  function headerMenu(col) {
86
- if (!col.sortable) return [];
87
127
  const s = activeSort.value;
88
128
  const set = (next) => () => {
89
129
  ownSort.value = next;
90
130
  emit("update:sort", next);
91
131
  };
132
+ const items = [];
133
+ if (col.sortable) {
134
+ items.push(
135
+ {
136
+ label: props.sortAscLabel,
137
+ icon: "lucide:arrow-up",
138
+ disabled: s?.key === col.key && s.dir === "asc",
139
+ onSelect: set({ key: col.key, dir: "asc" })
140
+ },
141
+ {
142
+ label: props.sortDescLabel,
143
+ icon: "lucide:arrow-down",
144
+ disabled: s?.key === col.key && s.dir === "desc",
145
+ onSelect: set({ key: col.key, dir: "desc" })
146
+ },
147
+ {
148
+ label: props.sortClearLabel,
149
+ icon: "lucide:x",
150
+ disabled: !s,
151
+ onSelect: set(null)
152
+ }
153
+ );
154
+ }
155
+ if (col.filterable) {
156
+ const hidden = hiddenValues.value[col.key];
157
+ items.push({
158
+ label: props.filterLabel,
159
+ icon: "lucide:filter",
160
+ separatorBefore: items.length > 0,
161
+ children: [
162
+ ...valuesOf(col).map((value) => ({
163
+ label: col.valueLabel?.(value) ?? String(value ?? "—"),
164
+ checked: !isValueHidden(col.key, value),
165
+ onSelect: () => toggleValue(col.key, value)
166
+ })),
167
+ {
168
+ label: props.showAllLabel,
169
+ icon: "lucide:list",
170
+ separatorBefore: true,
171
+ disabled: !hidden?.size,
172
+ onSelect: () => showAllValues(col.key)
173
+ }
174
+ ]
175
+ });
176
+ }
177
+ return items;
178
+ }
179
+ function tableMenu() {
180
+ const offered = props.columns.filter((c) => !c.alwaysVisible && c.label);
181
+ if (!offered.length) return [];
92
182
  return [
93
183
  {
94
- label: props.sortAscLabel,
95
- icon: "lucide:arrow-up",
96
- disabled: s?.key === col.key && s.dir === "asc",
97
- onSelect: set({ key: col.key, dir: "asc" })
98
- },
99
- {
100
- label: props.sortDescLabel,
101
- icon: "lucide:arrow-down",
102
- disabled: s?.key === col.key && s.dir === "desc",
103
- onSelect: set({ key: col.key, dir: "desc" })
104
- },
105
- {
106
- label: props.sortClearLabel,
107
- icon: "lucide:x",
108
- separatorBefore: true,
109
- disabled: !s,
110
- onSelect: set(null)
184
+ label: props.columnsLabel,
185
+ icon: "lucide:columns-3",
186
+ children: offered.map((col) => ({
187
+ label: col.label,
188
+ checked: !hiddenColumns.value.has(col.key),
189
+ // The last visible column cannot be hidden: a table with no columns is
190
+ // a blank card the operator has no way back from.
191
+ disabled: !hiddenColumns.value.has(col.key) && visibleColumns.value.length <= 1,
192
+ onSelect: () => toggleColumn(col.key)
193
+ }))
111
194
  }
112
195
  ];
113
196
  }
@@ -190,130 +273,137 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
190
273
  "bar-inset-top": barInsetTop.value
191
274
  }, {
192
275
  default: withCtx(() => [
193
- createElementVNode("table", _hoisted_1, [
194
- createElementVNode("thead", {
195
- ref_key: "headEl",
196
- ref: headEl,
197
- class: normalizeClass(__props.stickyHeader ? "sticky top-0 z-10" : "")
198
- }, [
199
- createElementVNode("tr", _hoisted_2, [
200
- __props.selectable ? (openBlock(), createElementBlock("th", _hoisted_3, [
201
- createVNode(_sfc_main$2, {
202
- "model-value": allChecked.value,
203
- indeterminate: someChecked.value,
204
- "onUpdate:modelValue": toggleAll
205
- }, null, 8, ["model-value", "indeterminate"])
206
- ])) : createCommentVNode("", true),
207
- (openBlock(true), createElementBlock(Fragment, null, renderList(__props.columns, (col) => {
208
- return openBlock(), createElementBlock("th", {
209
- key: col.key,
210
- style: normalizeStyle(col.width ? { width: col.width } : void 0),
211
- class: normalizeClass(["px-4 py-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted", alignClass(col.align)]),
212
- "aria-sort": activeSort.value?.key === col.key ? activeSort.value.dir === "asc" ? "ascending" : "descending" : void 0
213
- }, [
214
- col.sortable ? (openBlock(), createBlock(_sfc_main$3, {
215
- key: 0,
216
- items: headerMenu(col)
217
- }, {
218
- default: withCtx(() => [
219
- createElementVNode("button", {
220
- type: "button",
221
- class: normalizeClass(["group/sort -mx-1 inline-flex items-center gap-1 rounded px-1 outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring", [
222
- col.align === "right" ? "flex-row-reverse" : "",
223
- activeSort.value?.key === col.key ? "text-ink" : ""
224
- ]]),
225
- onClick: ($event) => toggleSort(col)
226
- }, [
227
- createTextVNode(toDisplayString(col.label) + " ", 1),
228
- createVNode(_sfc_main$4, {
229
- name: sortIcon(col),
230
- size: 13,
231
- class: normalizeClass([
232
- "shrink-0 transition-[transform,opacity] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)]",
233
- activeSort.value?.key === col.key ? "opacity-100" : "opacity-40 group-hover/sort:opacity-70"
234
- ])
235
- }, null, 8, ["name", "class"])
236
- ], 10, _hoisted_5)
237
- ]),
238
- _: 2
239
- }, 1032, ["items"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
240
- createTextVNode(toDisplayString(col.label), 1)
241
- ], 64))
242
- ], 14, _hoisted_4);
243
- }), 128))
244
- ])
245
- ], 2),
246
- createVNode(TransitionGroup, {
247
- tag: "tbody",
248
- name: "lp-row",
249
- ref: (el) => unref(roving).setContainer(el?.$el ?? null)
250
- }, {
251
- default: withCtx(() => [
252
- displayRows.value.length === 0 ? (openBlock(), createElementBlock("tr", _hoisted_6, [
253
- createElementVNode("td", {
254
- colspan: colSpan.value,
255
- class: "px-4 py-10 text-center text-muted"
256
- }, [
257
- createVNode(_sfc_main$4, {
258
- name: __props.emptyIcon,
259
- size: 22,
260
- class: "mx-auto mb-2 opacity-60"
261
- }, null, 8, ["name"]),
262
- createElementVNode("div", null, toDisplayString(__props.emptyLabel), 1)
263
- ], 8, _hoisted_7)
264
- ])) : createCommentVNode("", true),
265
- (openBlock(true), createElementBlock(Fragment, null, renderList(displayRows.value, (row, index) => {
266
- return openBlock(), createBlock(_sfc_main$3, {
267
- key: keyFor(row, index),
268
- items: menuFor(row)
269
- }, {
270
- default: withCtx(() => [
271
- createElementVNode("tr", mergeProps({
272
- class: ["group border-b border-line/60 outline-none transition-colors last:border-0 hover:bg-surface-soft/60 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring data-[active]:bg-surface-soft/40", selectedSet.value.has(keyFor(row, index)) ? "bg-brand-soft/40" : ""]
273
- }, { ref_for: true }, unref(roving).itemProps(String(keyFor(row, index))), {
274
- onClick: ($event) => emit("rowClick", row),
275
- onKeydown: onRowKeydown
276
- }), [
277
- __props.selectable ? (openBlock(), createElementBlock("td", {
276
+ createVNode(_sfc_main$2, {
277
+ items: tableMenu()
278
+ }, {
279
+ default: withCtx(() => [
280
+ createElementVNode("table", _hoisted_1, [
281
+ createElementVNode("thead", {
282
+ ref_key: "headEl",
283
+ ref: headEl,
284
+ class: normalizeClass(__props.stickyHeader ? "sticky top-0 z-10" : "")
285
+ }, [
286
+ createElementVNode("tr", _hoisted_2, [
287
+ __props.selectable ? (openBlock(), createElementBlock("th", _hoisted_3, [
288
+ createVNode(_sfc_main$3, {
289
+ "model-value": allChecked.value,
290
+ indeterminate: someChecked.value,
291
+ "onUpdate:modelValue": toggleAll
292
+ }, null, 8, ["model-value", "indeterminate"])
293
+ ])) : createCommentVNode("", true),
294
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleColumns.value, (col) => {
295
+ return openBlock(), createElementBlock("th", {
296
+ key: col.key,
297
+ style: normalizeStyle(col.width ? { width: col.width } : void 0),
298
+ class: normalizeClass(["px-4 py-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted", alignClass(col.align)]),
299
+ "aria-sort": activeSort.value?.key === col.key ? activeSort.value.dir === "asc" ? "ascending" : "descending" : void 0
300
+ }, [
301
+ col.sortable ? (openBlock(), createBlock(_sfc_main$2, {
278
302
  key: 0,
279
- class: "w-px px-4 py-3",
280
- onClick: _cache[0] || (_cache[0] = withModifiers(() => {
281
- }, ["stop"]))
282
- }, [
283
- createVNode(_sfc_main$2, {
284
- "model-value": selectedSet.value.has(keyFor(row, index)),
285
- "onUpdate:modelValue": (v) => toggleRow(keyFor(row, index), v)
286
- }, null, 8, ["model-value", "onUpdate:modelValue"])
287
- ])) : createCommentVNode("", true),
288
- (openBlock(true), createElementBlock(Fragment, null, renderList(__props.columns, (col) => {
289
- return openBlock(), createElementBlock("td", {
290
- key: col.key,
291
- class: normalizeClass(["px-4 py-3 text-ink", alignClass(col.align)])
292
- }, [
293
- renderSlot(_ctx.$slots, `cell-${col.key}`, {
294
- row,
295
- value: row[col.key]
296
- }, () => [
297
- createTextVNode(toDisplayString(row[col.key]), 1)
298
- ], true)
299
- ], 2);
300
- }), 128))
301
- ], 16, _hoisted_8)
302
- ]),
303
- _: 2
304
- }, 1032, ["items"]);
305
- }), 128))
306
- ]),
307
- _: 3
308
- }, 512)
309
- ])
303
+ items: headerMenu(col)
304
+ }, {
305
+ default: withCtx(() => [
306
+ createElementVNode("button", {
307
+ type: "button",
308
+ class: normalizeClass(["group/sort -mx-1 inline-flex items-center gap-1 rounded px-1 outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring", [
309
+ col.align === "right" ? "flex-row-reverse" : "",
310
+ activeSort.value?.key === col.key ? "text-ink" : ""
311
+ ]]),
312
+ onClick: ($event) => toggleSort(col)
313
+ }, [
314
+ createTextVNode(toDisplayString(col.label) + " ", 1),
315
+ createVNode(_sfc_main$4, {
316
+ name: sortIcon(col),
317
+ size: 13,
318
+ class: normalizeClass([
319
+ "shrink-0 transition-[transform,opacity] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)]",
320
+ activeSort.value?.key === col.key ? "opacity-100" : "opacity-40 group-hover/sort:opacity-70"
321
+ ])
322
+ }, null, 8, ["name", "class"])
323
+ ], 10, _hoisted_5)
324
+ ]),
325
+ _: 2
326
+ }, 1032, ["items"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
327
+ createTextVNode(toDisplayString(col.label), 1)
328
+ ], 64))
329
+ ], 14, _hoisted_4);
330
+ }), 128))
331
+ ])
332
+ ], 2),
333
+ createVNode(TransitionGroup, {
334
+ tag: "tbody",
335
+ name: "lp-row",
336
+ ref: (el) => unref(roving).setContainer(el?.$el ?? null)
337
+ }, {
338
+ default: withCtx(() => [
339
+ displayRows.value.length === 0 ? (openBlock(), createElementBlock("tr", _hoisted_6, [
340
+ createElementVNode("td", {
341
+ colspan: colSpan.value,
342
+ class: "px-4 py-10 text-center text-muted"
343
+ }, [
344
+ createVNode(_sfc_main$4, {
345
+ name: __props.emptyIcon,
346
+ size: 22,
347
+ class: "mx-auto mb-2 opacity-60"
348
+ }, null, 8, ["name"]),
349
+ createElementVNode("div", null, toDisplayString(__props.emptyLabel), 1)
350
+ ], 8, _hoisted_7)
351
+ ])) : createCommentVNode("", true),
352
+ (openBlock(true), createElementBlock(Fragment, null, renderList(displayRows.value, (row, index) => {
353
+ return openBlock(), createBlock(_sfc_main$2, {
354
+ key: keyFor(row, index),
355
+ items: menuFor(row)
356
+ }, {
357
+ default: withCtx(() => [
358
+ createElementVNode("tr", mergeProps({
359
+ class: ["group border-b border-line/60 outline-none transition-colors last:border-0 hover:bg-surface-soft/60 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring data-[active]:bg-surface-soft/40", selectedSet.value.has(keyFor(row, index)) ? "bg-brand-soft/40" : ""]
360
+ }, { ref_for: true }, unref(roving).itemProps(String(keyFor(row, index))), {
361
+ onClick: ($event) => emit("rowClick", row),
362
+ onKeydown: onRowKeydown
363
+ }), [
364
+ __props.selectable ? (openBlock(), createElementBlock("td", {
365
+ key: 0,
366
+ class: "w-px px-4 py-3",
367
+ onClick: _cache[0] || (_cache[0] = withModifiers(() => {
368
+ }, ["stop"]))
369
+ }, [
370
+ createVNode(_sfc_main$3, {
371
+ "model-value": selectedSet.value.has(keyFor(row, index)),
372
+ "onUpdate:modelValue": (v) => toggleRow(keyFor(row, index), v)
373
+ }, null, 8, ["model-value", "onUpdate:modelValue"])
374
+ ])) : createCommentVNode("", true),
375
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleColumns.value, (col) => {
376
+ return openBlock(), createElementBlock("td", {
377
+ key: col.key,
378
+ class: normalizeClass(["px-4 py-3 text-ink", alignClass(col.align)])
379
+ }, [
380
+ renderSlot(_ctx.$slots, `cell-${col.key}`, {
381
+ row,
382
+ value: row[col.key]
383
+ }, () => [
384
+ createTextVNode(toDisplayString(row[col.key]), 1)
385
+ ], true)
386
+ ], 2);
387
+ }), 128))
388
+ ], 16, _hoisted_8)
389
+ ]),
390
+ _: 2
391
+ }, 1032, ["items"]);
392
+ }), 128))
393
+ ]),
394
+ _: 3
395
+ }, 512)
396
+ ])
397
+ ]),
398
+ _: 3
399
+ }, 8, ["items"])
310
400
  ]),
311
401
  _: 3
312
402
  }, 8, ["bar-inset-top"]);
313
403
  };
314
404
  }
315
405
  });
316
- const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-4fedb617"]]);
406
+ const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f9c874a7"]]);
317
407
  export {
318
408
  LpTable as default
319
409
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpThemeSwitcher-Dj4VcTu7.js";
1
+ import { _ as _sfc_main } from "../chunks/LpThemeSwitcher-r1te9nB2.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };