@leavepulse/ui 0.12.0 → 0.14.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/LpCommandPalette-D315B47-.css +16 -0
- package/dist/chunks/LayoutCanvas-Dd20boUG.js +50 -0
- package/dist/chunks/LayoutNode-DGpZA9LX.js +225 -0
- package/dist/chunks/LpAlert-BAYHDSS1.js +69 -0
- package/dist/chunks/LpAppShell-C22642JK.js +170 -0
- package/dist/chunks/LpAutocomplete-B9uoCs4t.js +196 -0
- package/dist/chunks/LpAvatar-B1Ez0ZAx.js +88 -0
- package/dist/chunks/LpBadge-CXzBPnwO.js +42 -0
- package/dist/chunks/LpBreadcrumbs-B7Aqatzw.js +42 -0
- package/dist/chunks/LpButton-5VXXCjwF.js +101 -0
- package/dist/chunks/LpCalendar-B7ZL0ty3.js +150 -0
- package/dist/chunks/LpCard-1yvWT9fx.js +66 -0
- package/dist/chunks/LpCheckbox-BO0zuuPh.js +55 -0
- package/dist/chunks/LpCodeBlock-CSiOSPs8.js +253 -0
- package/dist/chunks/LpConfirmDialog-CnHtHWHm.js +62 -0
- package/dist/chunks/LpContextMenu-D0mzXqA7.js +151 -0
- package/dist/chunks/LpDatePicker-dY2q4dr4.js +122 -0
- package/dist/chunks/LpDisclosure-DP6yfgfM.js +76 -0
- package/dist/chunks/LpDivider-CUX46KR0.js +43 -0
- package/dist/chunks/LpDrawer-CBNVhkg0.js +310 -0
- package/dist/chunks/LpDropdownMenu-DJpoqRCb.js +65 -0
- package/dist/chunks/LpEmptyState-CrfyRJUG.js +47 -0
- package/dist/chunks/LpFormField-Bn-ZwC6z.js +47 -0
- package/dist/chunks/LpIcon-CCnX5_2j.js +41 -0
- package/dist/chunks/LpInfraNode-C_PHcthC.js +99 -0
- package/dist/chunks/LpInput-BauZRyzm.js +136 -0
- package/dist/chunks/LpLaneNode-HtnQf2FF.js +33 -0
- package/dist/chunks/LpLink-DHwOEp4e.js +36 -0
- package/dist/chunks/LpLogViewer-CDBjhXl6.js +469 -0
- package/dist/chunks/LpModal-D17Bocq7.js +128 -0
- package/dist/chunks/LpNotificationBell-Bm51SkgV.js +232 -0
- package/dist/chunks/LpNumberField-C5ar-OwE.js +55 -0
- package/dist/chunks/LpOtpInput-DqaT0Z75.js +65 -0
- package/dist/chunks/LpPagination-CeGuNe_q.js +132 -0
- package/dist/chunks/LpPasswordInput-DIHFw4u0.js +64 -0
- package/dist/chunks/LpPhoneInput-LQvVFGMw.js +199 -0
- package/dist/chunks/LpPopover-8268UmlC.js +54 -0
- package/dist/chunks/LpProgress-BhI0IbjC.js +37 -0
- package/dist/chunks/LpRadio-CL-pI0_O.js +39 -0
- package/dist/chunks/LpRadioGroup-B4yDTmi6.js +52 -0
- package/dist/chunks/LpScrollArea-CcHul_XS.js +67 -0
- package/dist/chunks/LpSegmented-BmpanyAo.js +74 -0
- package/dist/chunks/LpSelect-DznhPEWX.js +222 -0
- package/dist/chunks/LpServiceNode-Dc-Ut5RS.js +51 -0
- package/dist/chunks/LpSidebar-CTUdtX7W.js +152 -0
- package/dist/chunks/LpSidebarNav-BRwovIc8.js +126 -0
- package/dist/chunks/LpSkeleton-eSFIo4kD.js +22 -0
- package/dist/chunks/LpSlider-B1SF3pRV.js +53 -0
- package/dist/chunks/LpStat-CdbEFOvn.js +88 -0
- package/dist/chunks/LpStepper-5dFTrW21.js +53 -0
- package/dist/chunks/LpSwitch-v6fnccSM.js +28 -0
- package/dist/chunks/LpTable-PHE6UKor.js +229 -0
- package/dist/chunks/LpTableOfContents-CjvxPMpU.js +155 -0
- package/dist/chunks/LpTabs-D7aTVPOb.js +115 -0
- package/dist/chunks/LpTextarea-CRAkhemZ.js +44 -0
- package/dist/chunks/LpThemeSwitcher-BgWwfkxs.js +601 -0
- package/dist/chunks/LpTilt-DuyKbpkA.js +49 -0
- package/dist/chunks/LpToaster-gDB1EaU3.js +196 -0
- package/dist/chunks/LpTooltip-CIwoRCag.js +49 -0
- package/dist/chunks/LpTopologyCanvas-DVwyQfKa.js +237 -0
- package/dist/chunks/LpUptimeBar-CB366k0O.js +127 -0
- package/dist/component-names.d.ts +1 -1
- package/dist/components/LayoutCanvas.vue.js +4 -0
- package/dist/components/LayoutNode.vue.js +4 -0
- package/dist/components/LpAlert.vue.js +4 -0
- package/dist/components/LpAppShell.vue.js +4 -0
- package/dist/components/LpAutocomplete.vue.js +4 -0
- package/dist/components/LpAvatar.vue.js +4 -0
- package/dist/components/LpBadge.vue.js +4 -0
- package/dist/components/LpBreadcrumbs.vue.js +4 -0
- package/dist/components/LpButton.vue.js +4 -0
- package/dist/components/LpCalendar.vue.js +4 -0
- package/dist/components/LpCard.vue.js +4 -0
- package/dist/components/LpCheckbox.vue.js +4 -0
- package/dist/components/LpCodeBlock.vue.js +4 -0
- package/dist/components/LpCommandPalette.vue.js +310 -0
- package/dist/components/LpConfirmDialog.vue.js +4 -0
- package/dist/components/LpContextMenu.vue.d.ts +7 -0
- package/dist/components/LpContextMenu.vue.js +4 -0
- package/dist/components/LpDatePicker.vue.js +4 -0
- package/dist/components/LpDisclosure.vue.js +4 -0
- package/dist/components/LpDivider.vue.js +4 -0
- package/dist/components/LpDrawer.vue.d.ts +8 -0
- package/dist/components/LpDrawer.vue.js +4 -0
- package/dist/components/LpDropdownMenu.vue.js +4 -0
- package/dist/components/LpEmptyState.vue.js +4 -0
- package/dist/components/LpFormField.vue.js +4 -0
- package/dist/components/LpIcon.vue.js +4 -0
- package/dist/components/LpInfraNode.vue.js +4 -0
- package/dist/components/LpInput.vue.js +4 -0
- package/dist/components/LpLaneNode.vue.js +4 -0
- package/dist/components/LpLink.vue.js +4 -0
- package/dist/components/LpLogViewer.vue.js +4 -0
- package/dist/components/LpModal.vue.js +4 -0
- package/dist/components/LpNotificationBell.vue.js +4 -0
- package/dist/components/LpNumberField.vue.js +4 -0
- package/dist/components/LpOtpInput.vue.js +4 -0
- package/dist/components/LpPagination.vue.js +4 -0
- package/dist/components/LpPasswordInput.vue.js +4 -0
- package/dist/components/LpPhoneInput.vue.js +4 -0
- package/dist/components/LpPopover.vue.js +4 -0
- package/dist/components/LpProgress.vue.js +4 -0
- package/dist/components/LpRadio.vue.js +4 -0
- package/dist/components/LpRadioGroup.vue.js +4 -0
- package/dist/components/LpScrollArea.vue.js +4 -0
- package/dist/components/LpSegmented.vue.js +4 -0
- package/dist/components/LpSelect.vue.d.ts +2 -0
- package/dist/components/LpSelect.vue.js +4 -0
- package/dist/components/LpServiceNode.vue.js +4 -0
- package/dist/components/LpSidebar.vue.js +4 -0
- package/dist/components/LpSidebarNav.vue.js +4 -0
- package/dist/components/LpSkeleton.vue.js +4 -0
- package/dist/components/LpSlider.vue.js +4 -0
- package/dist/components/LpStat.vue.js +4 -0
- package/dist/components/LpStepper.vue.js +4 -0
- package/dist/components/LpSwitch.vue.js +4 -0
- package/dist/components/LpTable.vue.js +4 -0
- package/dist/components/LpTableOfContents.vue.js +4 -0
- package/dist/components/LpTabs.vue.d.ts +4 -2
- package/dist/components/LpTabs.vue.js +4 -0
- package/dist/components/LpTextarea.vue.js +4 -0
- package/dist/components/LpThemeSwitcher.vue.js +4 -0
- package/dist/components/LpTilt.vue.d.ts +31 -0
- package/dist/components/LpTilt.vue.js +4 -0
- package/dist/components/LpToaster.vue.js +4 -0
- package/dist/components/LpTooltip.vue.js +4 -0
- package/dist/components/LpTopologyCanvas.vue.js +4 -0
- package/dist/components/LpUptimeBar.vue.js +4 -0
- package/dist/components/codeHighlight.js +230 -0
- package/dist/{countries-data-9rgqJWHo.js → components/countries-data.js} +2 -2
- package/dist/components/countries.js +38 -0
- package/dist/components/dropdown.js +14 -0
- package/dist/components/sidebar.js +1 -0
- package/dist/composables/useInputFilter.js +44 -0
- package/dist/composables/usePillTransition.js +11 -0
- package/dist/composables/useTilt.d.ts +23 -0
- package/dist/composables/useTilt.js +57 -0
- package/dist/composables/useToast.d.ts +2 -0
- package/dist/composables/useToast.js +49 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +197 -17596
- package/dist/layout/registry.js +10 -0
- package/dist/layout/tree.js +192 -0
- package/dist/layout/useLayout.js +61 -0
- package/package.json +5 -3
- package/src/component-names.ts +1 -0
- package/src/components/LpContextMenu.vue +14 -4
- package/src/components/LpDrawer.vue +29 -1
- package/src/components/LpLogViewer.vue +161 -31
- package/src/components/LpSelect.vue +0 -0
- package/src/components/LpSidebar.vue +5 -2
- package/src/components/LpTabs.vue +19 -6
- package/src/components/LpThemeSwitcher.vue +13 -2
- package/src/components/LpTilt.vue +61 -0
- package/src/components/LpToaster.vue +11 -4
- package/src/composables/useTilt.ts +103 -0
- package/src/composables/useToast.ts +2 -0
- package/src/index.ts +3 -0
- package/src/nuxt.ts +10 -1
- package/dist/index.css +0 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { reactive } from "vue";
|
|
2
|
+
let uid = 0;
|
|
3
|
+
const nid = () => `lp-n${uid++}`;
|
|
4
|
+
function leaf(block) {
|
|
5
|
+
return { kind: "leaf", id: nid(), blocks: [block], active: 0, size: 1 };
|
|
6
|
+
}
|
|
7
|
+
function makeLayout(blocks) {
|
|
8
|
+
return reactive({
|
|
9
|
+
kind: "split",
|
|
10
|
+
id: nid(),
|
|
11
|
+
dir: "row",
|
|
12
|
+
size: 1,
|
|
13
|
+
children: blocks.map(leaf)
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function findParent(node, childId) {
|
|
17
|
+
for (const c of node.children) {
|
|
18
|
+
if (c.id === childId) return node;
|
|
19
|
+
if (c.kind === "split") {
|
|
20
|
+
const r = findParent(c, childId);
|
|
21
|
+
if (r) return r;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
function findLeaf(node, id) {
|
|
27
|
+
if (node.kind === "leaf") return node.id === id ? node : null;
|
|
28
|
+
for (const c of node.children) {
|
|
29
|
+
const r = findLeaf(c, id);
|
|
30
|
+
if (r) return r;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
function countLeaves(node) {
|
|
35
|
+
if (node.kind === "leaf") return 1;
|
|
36
|
+
return node.children.reduce((s, c) => s + countLeaves(c), 0);
|
|
37
|
+
}
|
|
38
|
+
function countBlocks(node) {
|
|
39
|
+
if (node.kind === "leaf") return node.blocks.length;
|
|
40
|
+
return node.children.reduce((s, c) => s + countBlocks(c), 0);
|
|
41
|
+
}
|
|
42
|
+
function detach(root, id) {
|
|
43
|
+
const parent = findParent(root, id);
|
|
44
|
+
if (!parent) return;
|
|
45
|
+
const idx = parent.children.findIndex((c) => c.id === id);
|
|
46
|
+
parent.children.splice(idx, 1);
|
|
47
|
+
collapse(root, parent);
|
|
48
|
+
}
|
|
49
|
+
function collapse(root, parent) {
|
|
50
|
+
if (parent === root || parent.children.length !== 1) return;
|
|
51
|
+
const grand = findParent(root, parent.id);
|
|
52
|
+
if (!grand) return;
|
|
53
|
+
const only = parent.children[0];
|
|
54
|
+
only.size = parent.size;
|
|
55
|
+
const pIdx = grand.children.findIndex((c) => c.id === parent.id);
|
|
56
|
+
grand.children.splice(pIdx, 1, only);
|
|
57
|
+
}
|
|
58
|
+
function removeLeaf(root, id) {
|
|
59
|
+
if (countLeaves(root) <= 1) return;
|
|
60
|
+
detach(root, id);
|
|
61
|
+
}
|
|
62
|
+
function removeBlock(root, leafId, index) {
|
|
63
|
+
const target = findLeaf(root, leafId);
|
|
64
|
+
if (!target || index < 0 || index >= target.blocks.length) return;
|
|
65
|
+
if (target.blocks.length > 1) {
|
|
66
|
+
target.blocks.splice(index, 1);
|
|
67
|
+
if (target.active >= target.blocks.length) target.active = target.blocks.length - 1;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (countBlocks(root) <= 1) return;
|
|
71
|
+
detach(root, leafId);
|
|
72
|
+
}
|
|
73
|
+
function addLeaf(root, block, side = "right") {
|
|
74
|
+
const targetId = root.children[root.children.length - 1]?.id;
|
|
75
|
+
if (!targetId) {
|
|
76
|
+
root.children.push(leaf(block));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (side === "center") {
|
|
80
|
+
addTab(root, targetId, block);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
insertBeside(root, leaf(block), targetId, side);
|
|
84
|
+
}
|
|
85
|
+
function addTab(root, leafId, block) {
|
|
86
|
+
const target = findLeaf(root, leafId);
|
|
87
|
+
if (!target) return;
|
|
88
|
+
target.blocks.push(block);
|
|
89
|
+
target.active = target.blocks.length - 1;
|
|
90
|
+
}
|
|
91
|
+
function setActiveTab(root, leafId, index) {
|
|
92
|
+
const target = findLeaf(root, leafId);
|
|
93
|
+
if (!target || index < 0 || index >= target.blocks.length) return;
|
|
94
|
+
target.active = index;
|
|
95
|
+
}
|
|
96
|
+
function reorderTab(root, leafId, from, to) {
|
|
97
|
+
const target = findLeaf(root, leafId);
|
|
98
|
+
if (!target) return;
|
|
99
|
+
const n = target.blocks.length;
|
|
100
|
+
if (from < 0 || from >= n || to < 0 || to >= n || from === to) return;
|
|
101
|
+
const activeBlock = target.blocks[target.active];
|
|
102
|
+
const [moved] = target.blocks.splice(from, 1);
|
|
103
|
+
target.blocks.splice(to, 0, moved);
|
|
104
|
+
target.active = target.blocks.indexOf(activeBlock);
|
|
105
|
+
}
|
|
106
|
+
function insertBeside(root, moving, targetId, side) {
|
|
107
|
+
const parent = findParent(root, targetId);
|
|
108
|
+
if (!parent) return;
|
|
109
|
+
const idx = parent.children.findIndex((c) => c.id === targetId);
|
|
110
|
+
const target = parent.children[idx];
|
|
111
|
+
const wantDir = side === "left" || side === "right" ? "row" : "col";
|
|
112
|
+
const before = side === "left" || side === "top";
|
|
113
|
+
if (parent.dir === wantDir) {
|
|
114
|
+
moving.size = target.size / 2;
|
|
115
|
+
target.size = target.size / 2;
|
|
116
|
+
parent.children.splice(before ? idx : idx + 1, 0, moving);
|
|
117
|
+
} else {
|
|
118
|
+
const wrap = {
|
|
119
|
+
kind: "split",
|
|
120
|
+
id: nid(),
|
|
121
|
+
dir: wantDir,
|
|
122
|
+
size: target.size,
|
|
123
|
+
children: before ? [{ ...moving, size: 1 }, { ...target, size: 1 }] : [{ ...target, size: 1 }, { ...moving, size: 1 }]
|
|
124
|
+
};
|
|
125
|
+
parent.children.splice(idx, 1, wrap);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function moveLeaf(root, movingId, targetId, side) {
|
|
129
|
+
if (movingId === targetId) return;
|
|
130
|
+
const moving = findLeaf(root, movingId);
|
|
131
|
+
if (!moving) return;
|
|
132
|
+
if (side === "center") {
|
|
133
|
+
const target = findLeaf(root, targetId);
|
|
134
|
+
if (!target) return;
|
|
135
|
+
const merged = moving.blocks;
|
|
136
|
+
detach(root, movingId);
|
|
137
|
+
target.active = target.blocks.length;
|
|
138
|
+
target.blocks.push(...merged);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
detach(root, movingId);
|
|
142
|
+
moving.size = 1;
|
|
143
|
+
insertBeside(root, moving, targetId, side);
|
|
144
|
+
}
|
|
145
|
+
function resizeAt(parent, index, deltaFraction) {
|
|
146
|
+
const a = parent.children[index];
|
|
147
|
+
const b = parent.children[index + 1];
|
|
148
|
+
if (!a || !b) return;
|
|
149
|
+
const total = a.size + b.size;
|
|
150
|
+
const min = total * 0.12;
|
|
151
|
+
const na = Math.max(min, Math.min(total - min, a.size + deltaFraction * total));
|
|
152
|
+
a.size = na;
|
|
153
|
+
b.size = total - na;
|
|
154
|
+
}
|
|
155
|
+
function serializeLayout(root) {
|
|
156
|
+
const strip = (n) => n.kind === "leaf" ? { kind: "leaf", blocks: [...n.blocks], active: n.active, size: n.size } : { kind: "split", dir: n.dir, size: n.size, children: n.children.map(strip) };
|
|
157
|
+
return strip(root);
|
|
158
|
+
}
|
|
159
|
+
function deserializeLayout(data) {
|
|
160
|
+
const hydrate = (n) => {
|
|
161
|
+
if (n.kind === "leaf") {
|
|
162
|
+
const blocks = n.blocks ?? (n.block != null ? [n.block] : []);
|
|
163
|
+
const active = Math.min(Math.max(n.active ?? 0, 0), Math.max(blocks.length - 1, 0));
|
|
164
|
+
return { kind: "leaf", id: nid(), blocks, active, size: n.size ?? 1 };
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
kind: "split",
|
|
168
|
+
id: nid(),
|
|
169
|
+
dir: n.dir,
|
|
170
|
+
size: n.size ?? 1,
|
|
171
|
+
children: n.children.map(hydrate)
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
return reactive(hydrate(data));
|
|
175
|
+
}
|
|
176
|
+
export {
|
|
177
|
+
addLeaf,
|
|
178
|
+
addTab,
|
|
179
|
+
countBlocks,
|
|
180
|
+
countLeaves,
|
|
181
|
+
deserializeLayout,
|
|
182
|
+
findLeaf,
|
|
183
|
+
findParent,
|
|
184
|
+
makeLayout,
|
|
185
|
+
moveLeaf,
|
|
186
|
+
removeBlock,
|
|
187
|
+
removeLeaf,
|
|
188
|
+
reorderTab,
|
|
189
|
+
resizeAt,
|
|
190
|
+
serializeLayout,
|
|
191
|
+
setActiveTab
|
|
192
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { shallowRef, computed, ref } from "vue";
|
|
2
|
+
import { makeLayout, countBlocks, serializeLayout, resizeAt, setActiveTab, deserializeLayout, moveLeaf, removeLeaf, removeBlock, reorderTab, addTab, addLeaf } from "./tree.js";
|
|
3
|
+
function useLayout(options) {
|
|
4
|
+
const limit = options.historyLimit ?? 50;
|
|
5
|
+
const layout = shallowRef(makeLayout(options.initial));
|
|
6
|
+
const count = computed(() => countBlocks(layout.value));
|
|
7
|
+
const past = ref([]);
|
|
8
|
+
const future = ref([]);
|
|
9
|
+
const canUndo = computed(() => past.value.length > 0);
|
|
10
|
+
const canRedo = computed(() => future.value.length > 0);
|
|
11
|
+
const snapshot = () => JSON.stringify(serializeLayout(layout.value));
|
|
12
|
+
function record(mutate) {
|
|
13
|
+
const before = snapshot();
|
|
14
|
+
mutate();
|
|
15
|
+
past.value.push(before);
|
|
16
|
+
if (past.value.length > limit) past.value.shift();
|
|
17
|
+
future.value = [];
|
|
18
|
+
}
|
|
19
|
+
function restore(serialized) {
|
|
20
|
+
layout.value = deserializeLayout(JSON.parse(serialized));
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
layout,
|
|
24
|
+
count,
|
|
25
|
+
canUndo,
|
|
26
|
+
canRedo,
|
|
27
|
+
add: (block, side) => record(() => addLeaf(layout.value, block, side)),
|
|
28
|
+
addTab: (leafId, block) => record(() => addTab(layout.value, leafId, block)),
|
|
29
|
+
setActive: (leafId, index) => setActiveTab(layout.value, leafId, index),
|
|
30
|
+
reorderTab: (leafId, from, to) => record(() => reorderTab(layout.value, leafId, from, to)),
|
|
31
|
+
removeBlock: (leafId, index) => record(() => removeBlock(layout.value, leafId, index)),
|
|
32
|
+
remove: (leafId) => record(() => removeLeaf(layout.value, leafId)),
|
|
33
|
+
move: (movingId, targetId, side) => record(() => moveLeaf(layout.value, movingId, targetId, side)),
|
|
34
|
+
// Resize fires continuously during a divider drag; recording every frame
|
|
35
|
+
// would flood history, so it mutates without a snapshot. (A consumer that
|
|
36
|
+
// wants resize in history can wrap a single record() around the gesture.)
|
|
37
|
+
resize: (parent, index, delta) => resizeAt(parent, index, delta),
|
|
38
|
+
undo: () => {
|
|
39
|
+
const prev = past.value.pop();
|
|
40
|
+
if (prev === void 0) return;
|
|
41
|
+
future.value.push(snapshot());
|
|
42
|
+
restore(prev);
|
|
43
|
+
},
|
|
44
|
+
redo: () => {
|
|
45
|
+
const next = future.value.pop();
|
|
46
|
+
if (next === void 0) return;
|
|
47
|
+
past.value.push(snapshot());
|
|
48
|
+
restore(next);
|
|
49
|
+
},
|
|
50
|
+
reset: (blocks) => record(() => {
|
|
51
|
+
layout.value = makeLayout(blocks ?? options.initial);
|
|
52
|
+
}),
|
|
53
|
+
serialize: () => serializeLayout(layout.value),
|
|
54
|
+
hydrate: (data) => record(() => {
|
|
55
|
+
layout.value = deserializeLayout(data);
|
|
56
|
+
})
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
useLayout
|
|
61
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leavepulse/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "LeavePulse token-driven Vue component kit.",
|
|
6
6
|
"repository": {
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
"./css": "./src/index.css",
|
|
27
27
|
"./tokens.css": "./src/tokens/tokens.css",
|
|
28
28
|
"./scrollbar.css": "./src/tokens/scrollbar.css",
|
|
29
|
-
"./canvas.css": "./src/canvas.css"
|
|
29
|
+
"./canvas.css": "./src/canvas.css",
|
|
30
|
+
"./package.json": "./package.json",
|
|
31
|
+
"./dist/*": "./dist/*"
|
|
30
32
|
},
|
|
31
33
|
"publishConfig": {
|
|
32
34
|
"registry": "https://npm.pkg.github.com"
|
|
@@ -58,7 +60,6 @@
|
|
|
58
60
|
"tailwind-merge": "^3.0.0",
|
|
59
61
|
"tailwind-variants": "^3.0.0",
|
|
60
62
|
"tailwindcss": "^4.0.0",
|
|
61
|
-
"vaul-vue": "^0.4.0",
|
|
62
63
|
"vue": "^3.5.0"
|
|
63
64
|
},
|
|
64
65
|
"peerDependenciesMeta": {
|
|
@@ -80,6 +81,7 @@
|
|
|
80
81
|
"typescript": "^5.6.3",
|
|
81
82
|
"vite": "^7.0.0",
|
|
82
83
|
"vite-plugin-dts": "^5.0.2",
|
|
84
|
+
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
83
85
|
"vue": "3.5.31",
|
|
84
86
|
"vue-tsc": "^3.0.0"
|
|
85
87
|
},
|
package/src/component-names.ts
CHANGED
|
@@ -34,12 +34,22 @@ export interface ContextMenuItemDef {
|
|
|
34
34
|
children?: ContextMenuItemDef[]
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
const props = defineProps<{
|
|
37
|
+
const props = defineProps<{
|
|
38
|
+
items: ContextMenuItemDef[]
|
|
39
|
+
/**
|
|
40
|
+
* Keep the reka menu mounted even while `items` is momentarily empty. Use when
|
|
41
|
+
* the items are resolved on the right-click itself (e.g. a list that figures
|
|
42
|
+
* out which row was clicked): without this the trigger would still be in
|
|
43
|
+
* native-menu mode on that first click and swallow it.
|
|
44
|
+
*/
|
|
45
|
+
always?: boolean
|
|
46
|
+
}>()
|
|
38
47
|
|
|
39
48
|
// With no items, render just the trigger slot — no reka machinery — so the
|
|
40
49
|
// element keeps the browser's native context menu. Lets callers wrap
|
|
41
|
-
// unconditionally and pass [] to opt out per element.
|
|
42
|
-
|
|
50
|
+
// unconditionally and pass [] to opt out per element. `always` overrides this so
|
|
51
|
+
// a late-populated menu is ready on the very first click.
|
|
52
|
+
const enabled = computed(() => props.always || props.items.length > 0)
|
|
43
53
|
|
|
44
54
|
const PANEL = `${POPOVER_PANEL} z-(--z-popover) min-w-48 p-1 outline-none`
|
|
45
55
|
const ITEM =
|
|
@@ -55,7 +65,7 @@ const ICON =
|
|
|
55
65
|
<ContextMenuTrigger as-child>
|
|
56
66
|
<slot />
|
|
57
67
|
</ContextMenuTrigger>
|
|
58
|
-
<ContextMenuPortal>
|
|
68
|
+
<ContextMenuPortal v-if="items.length">
|
|
59
69
|
<ContextMenuContent :class="PANEL">
|
|
60
70
|
<template v-for="(item, i) in items" :key="i">
|
|
61
71
|
<ContextMenuSeparator v-if="item.separatorBefore" class="my-1 h-px bg-line" />
|
|
@@ -73,6 +73,14 @@ const props = withDefaults(
|
|
|
73
73
|
* meaningful for left/right drawers.
|
|
74
74
|
*/
|
|
75
75
|
edgeOpen?: boolean
|
|
76
|
+
/**
|
|
77
|
+
* Tailwind breakpoint above which the edge strip is disabled. Edge
|
|
78
|
+
* swipe-to-open only makes sense on mobile: the strip listens for
|
|
79
|
+
* touch/pen pointers only, so on a desktop it can never open the drawer
|
|
80
|
+
* but still overlays the screen edge and swallows clicks. Pass the same
|
|
81
|
+
* breakpoint at which the host switches to the drawer (LpSidebar does).
|
|
82
|
+
*/
|
|
83
|
+
edgeBreakpoint?: "sm" | "md" | "lg" | "xl"
|
|
76
84
|
/** Width (px) of the edge grab strip. */
|
|
77
85
|
edgeSize?: number
|
|
78
86
|
/** Fraction (0–1) of the panel width the pull must reach to open on release. */
|
|
@@ -287,6 +295,19 @@ const edgeStripStyle = computed(() => {
|
|
|
287
295
|
? { right: "0", width: w }
|
|
288
296
|
: { left: "0", width: w }
|
|
289
297
|
})
|
|
298
|
+
|
|
299
|
+
// The strip must only exist below the host's mobile breakpoint. It is hidden
|
|
300
|
+
// with the same Tailwind breakpoint classes the rest of the mobile logic
|
|
301
|
+
// (LpSidebar rail, burger) uses — no JS media query needed.
|
|
302
|
+
const EDGE_STRIP_HIDDEN: Record<NonNullable<typeof props.edgeBreakpoint>, string> = {
|
|
303
|
+
sm: "sm:hidden",
|
|
304
|
+
md: "md:hidden",
|
|
305
|
+
lg: "lg:hidden",
|
|
306
|
+
xl: "xl:hidden",
|
|
307
|
+
}
|
|
308
|
+
const edgeStripClass = computed(() =>
|
|
309
|
+
props.edgeBreakpoint ? EDGE_STRIP_HIDDEN[props.edgeBreakpoint] : "",
|
|
310
|
+
)
|
|
290
311
|
</script>
|
|
291
312
|
|
|
292
313
|
<template>
|
|
@@ -296,6 +317,7 @@ const edgeStripStyle = computed(() => {
|
|
|
296
317
|
<div
|
|
297
318
|
ref="edgeStrip"
|
|
298
319
|
class="fixed inset-y-0 z-(--z-overlay) touch-none"
|
|
320
|
+
:class="edgeStripClass"
|
|
299
321
|
:style="edgeStripStyle"
|
|
300
322
|
aria-hidden="true"
|
|
301
323
|
/>
|
|
@@ -380,9 +402,15 @@ const edgeStripStyle = computed(() => {
|
|
|
380
402
|
no-drag wiring on the OUTER element so vaul still sees one content
|
|
381
403
|
container (overlay scroll lives one level in); padding moves to the
|
|
382
404
|
scroll content so the bar floats at the panel edge. -->
|
|
405
|
+
<!-- select-text (arbitrary + important): vaul injects a global
|
|
406
|
+
`[data-vaul-drawer]{user-select:none}` rule for pointer devices to
|
|
407
|
+
stop a swipe-drag from selecting text. That also kills legitimate
|
|
408
|
+
selection/Ctrl+C in the body (e.g. log lines), so we override it back
|
|
409
|
+
to selectable here. Drag-to-dismiss still starts on the handle/header
|
|
410
|
+
and empty space, not on this text. -->
|
|
383
411
|
<div
|
|
384
412
|
v-no-drag-controls="noDragControls"
|
|
385
|
-
class="flex min-h-0 min-w-0 flex-1 flex-col"
|
|
413
|
+
class="flex min-h-0 min-w-0 flex-1 flex-col [-webkit-user-select:text]! [user-select:text]!"
|
|
386
414
|
:data-vaul-no-drag="noDragContent ? '' : undefined"
|
|
387
415
|
>
|
|
388
416
|
<!-- min-w-0 on the body + scroll content so a wide child (e.g. a log
|