@leavepulse/ui 0.29.3 → 0.29.4
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/assets/{LpTable-B9Iko3XD.css → LpTable-Bz3uJNa3.css} +8 -8
- package/dist/chunks/{LpAppShell-CGX0DlIW.js → LpAppShell-BJk3b-u4.js} +1 -1
- package/dist/chunks/{LpAvatar-CzCE5cXg.js → LpAvatar-D3l4nabg.js} +1 -1
- package/dist/chunks/{LpCard-DSefTGEH.js → LpCard-D0M2ZCnB.js} +1 -1
- package/dist/chunks/{LpChart-UiU4RhXP.js → LpChart-Bmw7y34Z.js} +1 -1
- package/dist/chunks/{LpContextMenu-D0mzXqA7.js → LpContextMenu-B6WBLleS.js} +55 -8
- package/dist/chunks/{LpFileTree-BaV7f0O7.js → LpFileTree-DfFqY__1.js} +1 -1
- package/dist/chunks/{LpFileTreeNode-BzpBa7R7.js → LpFileTreeNode-COchUMNn.js} +1 -1
- package/dist/chunks/{LpLogViewer-CKmEQYnm.js → LpLogViewer-CVaGfTF_.js} +1 -1
- package/dist/chunks/{LpNotificationBell-Dvu-b6Vn.js → LpNotificationBell-CTsIcPqX.js} +1 -1
- package/dist/chunks/{LpPie-BkjWlfSw.js → LpPie-BL1vTDSM.js} +1 -1
- package/dist/chunks/{LpSidebar-CWehDCxN.js → LpSidebar-C_Mr-JPI.js} +1 -1
- package/dist/chunks/{LpSidebarNav-5RGNr2D3.js → LpSidebarNav-D6v12-36.js} +1 -1
- package/dist/chunks/{LpThemeSwitcher-Dj4VcTu7.js → LpThemeSwitcher-r1te9nB2.js} +1 -1
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.js +1 -1
- package/dist/components/LpContextMenu.vue.d.ts +7 -0
- package/dist/components/LpContextMenu.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpTable.vue.d.ts +19 -0
- package/dist/components/LpTable.vue.js +233 -143
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/index.js +12 -12
- package/package.json +1 -1
- package/src/components/LpContextMenu.vue +49 -0
- package/src/components/LpTable.vue +166 -23
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { defineComponent, ref, computed, watch, onBeforeUnmount, openBlock, createBlock, withCtx, createElementVNode, normalizeClass, createElementBlock,
|
|
2
|
-
import { _ as _sfc_main$
|
|
3
|
-
import { _ as _sfc_main$
|
|
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-
|
|
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
|
|
98
|
+
if (!s) return filteredRows.value;
|
|
58
99
|
const col = props.columns.find((c) => c.key === s.key);
|
|
59
|
-
if (!col?.sortable) return
|
|
100
|
+
if (!col?.sortable) return filteredRows.value;
|
|
60
101
|
const factor = s.dir === "asc" ? 1 : -1;
|
|
61
|
-
return [...
|
|
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.
|
|
95
|
-
icon: "lucide:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
"
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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-
|
|
406
|
+
const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f9c874a7"]]);
|
|
317
407
|
export {
|
|
318
408
|
LpTable as default
|
|
319
409
|
};
|
package/dist/index.js
CHANGED
|
@@ -3,21 +3,21 @@ import { _ as _2 } from "./chunks/LpAddressInput-Bk6D8Bcy.js";
|
|
|
3
3
|
import { _ as _3 } from "./chunks/LpMapPicker-CXvoTrAe.js";
|
|
4
4
|
import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
|
|
5
5
|
import { _ as _4 } from "./chunks/LpAlert-BAYHDSS1.js";
|
|
6
|
-
import { _ as _5 } from "./chunks/LpAppShell-
|
|
6
|
+
import { _ as _5 } from "./chunks/LpAppShell-BJk3b-u4.js";
|
|
7
7
|
import { _ as _6 } from "./chunks/LpAutocomplete-DExlIZe_.js";
|
|
8
|
-
import { _ as _7 } from "./chunks/LpAvatar-
|
|
8
|
+
import { _ as _7 } from "./chunks/LpAvatar-D3l4nabg.js";
|
|
9
9
|
import { _ as _8 } from "./chunks/LpBadge-BPodVcJa.js";
|
|
10
10
|
import { _ as _9 } from "./chunks/LpBreadcrumbs-5uvViCXi.js";
|
|
11
11
|
import { _ as _10 } from "./chunks/LpButton-5VXXCjwF.js";
|
|
12
12
|
import { _ as _11 } from "./chunks/LpCalendar-B7ZL0ty3.js";
|
|
13
|
-
import { _ as _12 } from "./chunks/LpCard-
|
|
14
|
-
import { _ as _13 } from "./chunks/LpChart-
|
|
13
|
+
import { _ as _12 } from "./chunks/LpCard-D0M2ZCnB.js";
|
|
14
|
+
import { _ as _13 } from "./chunks/LpChart-Bmw7y34Z.js";
|
|
15
15
|
import { CHART_PALETTE, axisTicks, formatTick, niceScale, resolveSlices } from "./components/chart.js";
|
|
16
16
|
import { _ as _14 } from "./chunks/LpCheckbox-BO0zuuPh.js";
|
|
17
17
|
import { _ as _15 } from "./chunks/LpCodeBlock-rS_6mO3D.js";
|
|
18
18
|
import { default as default2 } from "./components/LpCommandPalette.vue.js";
|
|
19
19
|
import { _ as _16 } from "./chunks/LpConfirmDialog-CjOGcj1e.js";
|
|
20
|
-
import { _ as _17 } from "./chunks/LpContextMenu-
|
|
20
|
+
import { _ as _17 } from "./chunks/LpContextMenu-B6WBLleS.js";
|
|
21
21
|
import { _ as _18 } from "./chunks/LpDatePicker-dY2q4dr4.js";
|
|
22
22
|
import { _ as _19 } from "./chunks/LpDisclosure-BnwP4Q-b.js";
|
|
23
23
|
import { _ as _20 } from "./chunks/LpDivider-CUX46KR0.js";
|
|
@@ -25,7 +25,7 @@ import { _ as _21 } from "./chunks/LpDrawer-DAJN5rGK.js";
|
|
|
25
25
|
import { _ as _22 } from "./chunks/LpDropdownMenu-DJpoqRCb.js";
|
|
26
26
|
import { default as default3 } from "./components/LpDropzone.vue.js";
|
|
27
27
|
import { _ as _23 } from "./chunks/LpEmptyState-BV3q7Qyi.js";
|
|
28
|
-
import { _ as _24 } from "./chunks/LpFileTree-
|
|
28
|
+
import { _ as _24 } from "./chunks/LpFileTree-DfFqY__1.js";
|
|
29
29
|
import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
|
|
30
30
|
import { _ as _25 } from "./chunks/LpFormField-fV_2ZdCk.js";
|
|
31
31
|
import { _ as _26 } from "./chunks/LpIcon-CCnX5_2j.js";
|
|
@@ -35,15 +35,15 @@ import { _ as _28 } from "./chunks/LpInput-CYcTL9gj.js";
|
|
|
35
35
|
import { _ as _29 } from "./chunks/LpLightbox-Ci35Y_xP.js";
|
|
36
36
|
import { fileNameOf } from "./components/lightbox.js";
|
|
37
37
|
import { _ as _30 } from "./chunks/LpLink-BHZ1CLlF.js";
|
|
38
|
-
import { _ as _31 } from "./chunks/LpLogViewer-
|
|
38
|
+
import { _ as _31 } from "./chunks/LpLogViewer-CVaGfTF_.js";
|
|
39
39
|
import { _ as _32 } from "./chunks/LpModal-D_o-56To.js";
|
|
40
|
-
import { _ as _33 } from "./chunks/LpNotificationBell-
|
|
40
|
+
import { _ as _33 } from "./chunks/LpNotificationBell-CTsIcPqX.js";
|
|
41
41
|
import { _ as _34 } from "./chunks/LpNumberField-NPE8Bumx.js";
|
|
42
42
|
import { _ as _35 } from "./chunks/LpNumberFlow-amWYaeuA.js";
|
|
43
43
|
import { _ as _36 } from "./chunks/LpOtpInput-DqaT0Z75.js";
|
|
44
44
|
import { _ as _37 } from "./chunks/LpPagination-CeGuNe_q.js";
|
|
45
45
|
import { _ as _38 } from "./chunks/LpPasswordInput-DrYE4J5d.js";
|
|
46
|
-
import { _ as _39 } from "./chunks/LpPie-
|
|
46
|
+
import { _ as _39 } from "./chunks/LpPie-BL1vTDSM.js";
|
|
47
47
|
import { _ as _40 } from "./chunks/LpPhoneInput-NXXjciJJ.js";
|
|
48
48
|
import { flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
|
|
49
49
|
import { _ as _41 } from "./chunks/LpPopover-8268UmlC.js";
|
|
@@ -58,7 +58,7 @@ import { _ as _49 } from "./chunks/LpSelect-ANIVtrpM.js";
|
|
|
58
58
|
import { _ as _50 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
59
59
|
import { _ as _51 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
60
60
|
import { default as default5 } from "./components/LpShortcutsDialog.vue.js";
|
|
61
|
-
import { _ as _52 } from "./chunks/LpSidebar-
|
|
61
|
+
import { _ as _52 } from "./chunks/LpSidebar-C_Mr-JPI.js";
|
|
62
62
|
import { _ as _53 } from "./chunks/LpSkeleton-CTI-vBgW.js";
|
|
63
63
|
import { _ as _54 } from "./chunks/LpSlider-B1SF3pRV.js";
|
|
64
64
|
import { _ as _55 } from "./chunks/LpSparkline-C6xQ2dwv.js";
|
|
@@ -69,8 +69,8 @@ import { default as default6 } from "./components/LpTable.vue.js";
|
|
|
69
69
|
import { _ as _59 } from "./chunks/LpTableOfContents-CjvxPMpU.js";
|
|
70
70
|
import { _ as _60 } from "./chunks/LpTabs-Cefe_lys.js";
|
|
71
71
|
import { _ as _61 } from "./chunks/LpTextarea-BMIOfw5l.js";
|
|
72
|
-
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/LpThemeSwitcher-
|
|
73
|
-
import { D, _ as _62, N, T, b, c, d, e, f, g, i, l, h, j, n, r, t, k, m, u, v } from "./chunks/LpThemeSwitcher-
|
|
72
|
+
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/LpThemeSwitcher-r1te9nB2.js";
|
|
73
|
+
import { D, _ as _62, N, T, b, c, d, e, f, g, i, l, h, j, n, r, t, k, m, u, v } from "./chunks/LpThemeSwitcher-r1te9nB2.js";
|
|
74
74
|
import { _ as _63 } from "./chunks/LpTilt-DuyKbpkA.js";
|
|
75
75
|
import { _ as _64 } from "./chunks/LpToaster-gDB1EaU3.js";
|
|
76
76
|
import { _ as _65 } from "./chunks/LpTooltip-hCLPAqMG.js";
|
package/package.json
CHANGED
|
@@ -32,6 +32,13 @@ export interface ContextMenuItemDef {
|
|
|
32
32
|
onSelect?: () => void
|
|
33
33
|
/** Nested submenu. When present, onSelect is ignored. */
|
|
34
34
|
children?: ContextMenuItemDef[]
|
|
35
|
+
/**
|
|
36
|
+
* Renders as a tick-box rather than a plain item, and the menu stays open on
|
|
37
|
+
* select. For the lists where the point is to set several at once — which
|
|
38
|
+
* columns to show, which values to filter by — and closing after each one
|
|
39
|
+
* would mean reopening the menu for every tick.
|
|
40
|
+
*/
|
|
41
|
+
checked?: boolean
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
const props = defineProps<{
|
|
@@ -85,7 +92,28 @@ const ICON =
|
|
|
85
92
|
<ContextMenuSubContent :class="PANEL" :side-offset="2" :align-offset="-4">
|
|
86
93
|
<template v-for="(sub, j) in item.children" :key="j">
|
|
87
94
|
<ContextMenuSeparator v-if="sub.separatorBefore" class="my-1 h-px bg-line" />
|
|
95
|
+
<!-- The tick-box case, as in the top-level menu: this is
|
|
96
|
+
where most of them live, since a submenu is what a list
|
|
97
|
+
of choices opens into. -->
|
|
98
|
+
<ContextMenuItem
|
|
99
|
+
v-if="sub.checked !== undefined"
|
|
100
|
+
:class="[ITEM, 'justify-between text-ink data-[highlighted]:text-brand']"
|
|
101
|
+
:disabled="sub.disabled"
|
|
102
|
+
@select.prevent="sub.onSelect?.()"
|
|
103
|
+
>
|
|
104
|
+
<span class="flex items-center gap-2">
|
|
105
|
+
<LpIcon
|
|
106
|
+
:name="sub.checked ? 'lucide:check' : 'lucide:minus'"
|
|
107
|
+
:size="15"
|
|
108
|
+
:class="[ICON, sub.checked ? '' : 'opacity-25']"
|
|
109
|
+
/>
|
|
110
|
+
{{ sub.label }}
|
|
111
|
+
</span>
|
|
112
|
+
<kbd v-if="sub.shortcut" class="text-xs text-muted">{{ sub.shortcut }}</kbd>
|
|
113
|
+
</ContextMenuItem>
|
|
114
|
+
|
|
88
115
|
<ContextMenuItem
|
|
116
|
+
v-else
|
|
89
117
|
:class="[ITEM, 'justify-between', sub.danger ? 'text-danger data-[highlighted]:bg-danger-soft data-[highlighted]:text-danger' : 'text-ink data-[highlighted]:text-brand']"
|
|
90
118
|
:disabled="sub.disabled"
|
|
91
119
|
@select="sub.onSelect?.()"
|
|
@@ -101,6 +129,27 @@ const ICON =
|
|
|
101
129
|
</ContextMenuPortal>
|
|
102
130
|
</ContextMenuSub>
|
|
103
131
|
|
|
132
|
+
<!-- Tick-box item. `@select.prevent` keeps the menu open: these come
|
|
133
|
+
in lists where several are set in one visit, and closing after
|
|
134
|
+
each tick would mean reopening for the next. The tick occupies a
|
|
135
|
+
fixed slot so unticked rows stay aligned with ticked ones. -->
|
|
136
|
+
<ContextMenuItem
|
|
137
|
+
v-else-if="item.checked !== undefined"
|
|
138
|
+
:class="[ITEM, 'justify-between text-ink data-[highlighted]:text-brand']"
|
|
139
|
+
:disabled="item.disabled"
|
|
140
|
+
@select.prevent="item.onSelect?.()"
|
|
141
|
+
>
|
|
142
|
+
<span class="flex items-center gap-2">
|
|
143
|
+
<LpIcon
|
|
144
|
+
:name="item.checked ? 'lucide:check' : 'lucide:minus'"
|
|
145
|
+
:size="15"
|
|
146
|
+
:class="[ICON, item.checked ? '' : 'opacity-25']"
|
|
147
|
+
/>
|
|
148
|
+
{{ item.label }}
|
|
149
|
+
</span>
|
|
150
|
+
<kbd v-if="item.shortcut" class="text-xs text-muted">{{ item.shortcut }}</kbd>
|
|
151
|
+
</ContextMenuItem>
|
|
152
|
+
|
|
104
153
|
<!-- Leaf item -->
|
|
105
154
|
<ContextMenuItem
|
|
106
155
|
v-else
|