@leavepulse/ui 0.22.0 → 0.22.2

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.
@@ -6,7 +6,7 @@ import { _ as _sfc_main$3 } from "./LpButton-5VXXCjwF.js";
6
6
  import { _ as _sfc_main$1 } from "./LpFormField-Bn-ZwC6z.js";
7
7
  import { _ as _sfc_main$4 } from "./LpIcon-CCnX5_2j.js";
8
8
  import { _ as _sfc_main$5 } from "./LpInput-BauZRyzm.js";
9
- import { _ as _sfc_main$7 } from "./LpModal-CNAFRgCU.js";
9
+ import { _ as _sfc_main$7 } from "./LpModal-CF7G_0D_.js";
10
10
  import { _ as _sfc_main$6 } from "./LpSelect-D5mU4cZO.js";
11
11
  const _hoisted_1 = { class: "flex flex-col gap-3" };
12
12
  const _hoisted_2 = { class: "flex items-stretch gap-2" };
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, openBlock, createBlock, withCtx, renderSlot, createVNode, createTextVNode, toDisplayString } from "vue";
2
2
  import { _ as _sfc_main$2 } from "./LpButton-5VXXCjwF.js";
3
- import { _ as _sfc_main$1 } from "./LpModal-CNAFRgCU.js";
3
+ import { _ as _sfc_main$1 } from "./LpModal-CF7G_0D_.js";
4
4
  const _sfc_main = /* @__PURE__ */ defineComponent({
5
5
  __name: "LpConfirmDialog",
6
6
  props: {
@@ -47,7 +47,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
47
47
  const bodyPad = computed(
48
48
  () => [
49
49
  "px-5",
50
- props.title || slots.title ? "" : "pt-5",
50
+ props.title || slots.title ? "pt-1" : "pt-5",
51
51
  slots.footer ? "" : "pb-5"
52
52
  ].filter(Boolean).join(" ")
53
53
  );
@@ -1,4 +1,4 @@
1
- import { defineComponent, markRaw, computed, watch, openBlock, createBlock, unref, withCtx, createVNode, createElementVNode, createElementBlock, Fragment, renderList, createTextVNode, toDisplayString, createCommentVNode } from "vue";
1
+ import { defineComponent, markRaw, computed, watch, openBlock, createBlock, unref, withCtx, createVNode, normalizeClass, createElementVNode, createElementBlock, Fragment, renderList, createTextVNode, toDisplayString, createCommentVNode } from "vue";
2
2
  import { Background } from "@vue-flow/background";
3
3
  import { Controls } from "@vue-flow/controls";
4
4
  import { MarkerType, useVueFlow, VueFlow, SelectionMode, Panel } from "@vue-flow/core";
@@ -22,6 +22,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
22
22
  connectable: { type: Boolean, default: false },
23
23
  selectable: { type: Boolean, default: false },
24
24
  legend: { type: Boolean, default: true },
25
+ legendPosition: { default: "bottom-left" },
25
26
  lanes: { default: () => [] }
26
27
  },
27
28
  emits: ["connect", "node-select", "node-contextmenu", "edge-contextmenu", "pane-click", "selection-change", "update:nodes", "node-drag-stop", "viewport-change"],
@@ -149,6 +150,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
149
150
  e.preventDefault?.();
150
151
  emit("node-contextmenu", { id: node.id, x: e.clientX, y: e.clientY });
151
152
  });
153
+ const legendOffset = computed(() => {
154
+ if (props.legendPosition === "bottom-left") return "!left-12";
155
+ if (props.legendPosition === "bottom-right") return "!bottom-40";
156
+ return "";
157
+ });
152
158
  const legendItems = [
153
159
  { label: "Network", color: CATEGORY_COLOR.network, width: 2, dash: "0" },
154
160
  { label: "Depends-on", color: CATEGORY_COLOR.structural, width: 1.5, dash: "1 5" },
@@ -198,7 +204,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
198
204
  createVNode(unref(Controls)),
199
205
  __props.legend ? (openBlock(), createBlock(unref(Panel), {
200
206
  key: 0,
201
- position: "top-right"
207
+ position: __props.legendPosition,
208
+ class: normalizeClass(legendOffset.value)
202
209
  }, {
203
210
  default: withCtx(() => [
204
211
  createElementVNode("div", _hoisted_1, [
@@ -225,7 +232,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
225
232
  ])
226
233
  ]),
227
234
  _: 1
228
- })) : createCommentVNode("", true)
235
+ }, 8, ["position", "class"])) : createCommentVNode("", true)
229
236
  ]),
230
237
  _: 1
231
238
  }, 8, ["nodes", "edges", "nodes-connectable", "selection-on-drag", "pan-on-drag", "selection-key-code", "selection-mode"]);
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpAddressInput-Dah7asXy.js";
1
+ import { _ as _sfc_main } from "../chunks/LpAddressInput-BWuIOt_4.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpConfirmDialog-CkMzeKdp.js";
1
+ import { _ as _sfc_main } from "../chunks/LpConfirmDialog-B_3ML33f.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpModal-CNAFRgCU.js";
1
+ import { _ as _sfc_main } from "../chunks/LpModal-CF7G_0D_.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,5 +1,5 @@
1
1
  import { defineComponent, openBlock, createBlock, withCtx, createElementVNode, createElementBlock, Fragment, renderList, toDisplayString, unref } from "vue";
2
- import { _ as _sfc_main$1 } from "../chunks/LpModal-CNAFRgCU.js";
2
+ import { _ as _sfc_main$1 } from "../chunks/LpModal-CF7G_0D_.js";
3
3
  import { appleModifierLabel } from "../composables/useHotkeys.js";
4
4
  import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
5
5
  import '../assets/LpShortcutsDialog-B7H-RZLQ.css';const _hoisted_1 = { class: "shortcut-groups" };
@@ -78,6 +78,12 @@ type __VLS_Props = {
78
78
  selectable?: boolean;
79
79
  /** Show the edge-type legend (Network / Depends-on / Pending / Drift). */
80
80
  legend?: boolean;
81
+ /**
82
+ * Where the legend sits. Defaults to bottom-left: hosts commonly float a
83
+ * toolbar across the top, which would cover a top-anchored legend, and the
84
+ * minimap owns the bottom-right.
85
+ */
86
+ legendPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
81
87
  /**
82
88
  * Background swimlanes drawn beneath the nodes (one per project / overlay).
83
89
  * Non-interactive; pan/zoom with the graph. Empty = no lanes.
@@ -148,6 +154,7 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {
148
154
  legend: boolean;
149
155
  connectable: boolean;
150
156
  selectable: boolean;
157
+ legendPosition: "top-left" | "top-right" | "bottom-left" | "bottom-right";
151
158
  lanes: TopologyLane[];
152
159
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
153
160
  declare const _default: typeof __VLS_export;
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpTopologyCanvas-DVwyQfKa.js";
1
+ import { _ as _sfc_main } from "../chunks/LpTopologyCanvas-CQt-G9KL.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { _ } from "./chunks/LayoutCanvas-Dd20boUG.js";
2
- import { _ as _2 } from "./chunks/LpAddressInput-Dah7asXy.js";
2
+ import { _ as _2 } from "./chunks/LpAddressInput-BWuIOt_4.js";
3
3
  import { _ as _3 } from "./chunks/LpMapPicker-DFKrd1Ne.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";
@@ -14,7 +14,7 @@ import { _ as _12 } from "./chunks/LpCard-BmrTvWOe.js";
14
14
  import { _ as _13 } from "./chunks/LpCheckbox-BO0zuuPh.js";
15
15
  import { _ as _14 } from "./chunks/LpCodeBlock-CSiOSPs8.js";
16
16
  import { default as default2 } from "./components/LpCommandPalette.vue.js";
17
- import { _ as _15 } from "./chunks/LpConfirmDialog-CkMzeKdp.js";
17
+ import { _ as _15 } from "./chunks/LpConfirmDialog-B_3ML33f.js";
18
18
  import { _ as _16 } from "./chunks/LpContextMenu-D0mzXqA7.js";
19
19
  import { _ as _17 } from "./chunks/LpDatePicker-dY2q4dr4.js";
20
20
  import { _ as _18 } from "./chunks/LpDisclosure-DP6yfgfM.js";
@@ -32,7 +32,7 @@ import { _ as _28 } from "./chunks/LpLightbox-Ci35Y_xP.js";
32
32
  import { fileNameOf } from "./components/lightbox.js";
33
33
  import { _ as _29 } from "./chunks/LpLink-DHwOEp4e.js";
34
34
  import { _ as _30 } from "./chunks/LpLogViewer-B1aLUVdz.js";
35
- import { _ as _31 } from "./chunks/LpModal-CNAFRgCU.js";
35
+ import { _ as _31 } from "./chunks/LpModal-CF7G_0D_.js";
36
36
  import { _ as _32 } from "./chunks/LpNotificationBell-HSGo1pcf.js";
37
37
  import { _ as _33 } from "./chunks/LpNumberField-C5ar-OwE.js";
38
38
  import { _ as _34 } from "./chunks/LpOtpInput-DqaT0Z75.js";
@@ -64,7 +64,7 @@ import { D, _ as _56, N, T, b, c, d, e, f, g, i, l, h, j, n, r, t, k, m, u, v }
64
64
  import { _ as _57 } from "./chunks/LpTilt-DuyKbpkA.js";
65
65
  import { _ as _58 } from "./chunks/LpToaster-gDB1EaU3.js";
66
66
  import { _ as _59 } from "./chunks/LpTooltip-D1hbjQWG.js";
67
- import { _ as _60 } from "./chunks/LpTopologyCanvas-DVwyQfKa.js";
67
+ import { _ as _60 } from "./chunks/LpTopologyCanvas-CQt-G9KL.js";
68
68
  import { _ as _61 } from "./chunks/LpUptimeBar-CB366k0O.js";
69
69
  import { deserializeLayout, serializeLayout } from "./layout/tree.js";
70
70
  import { addLeaf, addTab, countBlocks, countLeaves, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, setActiveTab } from "./layout/tree.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leavepulse/ui",
3
- "version": "0.22.0",
3
+ "version": "0.22.2",
4
4
  "type": "module",
5
5
  "description": "LeavePulse token-driven Vue component kit.",
6
6
  "repository": {
@@ -72,10 +72,16 @@ const widthClass = computed(() => {
72
72
  // inset horizontally; top only when there's no header, bottom only when there's
73
73
  // no footer (header/footer own those edges).
74
74
  const slots = useSlots()
75
+ /*
76
+ * The body clips its overflow, and a focus ring is drawn OUTSIDE the control it
77
+ * belongs to — so a field sitting flush against the top of the body had its
78
+ * ring sliced off. Under a header the gap is only the ring's width plus a
79
+ * hair; without one the existing pt-5 already clears it.
80
+ */
75
81
  const bodyPad = computed(() =>
76
82
  [
77
83
  "px-5",
78
- props.title || slots.title ? "" : "pt-5",
84
+ props.title || slots.title ? "pt-1" : "pt-5",
79
85
  slots.footer ? "" : "pb-5",
80
86
  ]
81
87
  .filter(Boolean)
@@ -22,6 +22,10 @@
22
22
  * Either way the trigger keeps a real accessible name, which is what `title`
23
23
  * alone could not guarantee. reka opens the tip on keyboard focus as well as
24
24
  * hover and closes it on Escape, satisfying WCAG 1.4.13.
25
+ *
26
+ * Do NOT wrap the `#trigger` of LpDropdownMenu, LpPopover or LpContextMenu:
27
+ * those bind their handlers to the slot's direct child, so a wrapper swallows
28
+ * them and the control stops opening. Put `aria-label` on the trigger instead.
25
29
  */
26
30
  import {
27
31
  TooltipContent,
@@ -113,13 +113,25 @@ const props = withDefaults(
113
113
  selectable?: boolean
114
114
  /** Show the edge-type legend (Network / Depends-on / Pending / Drift). */
115
115
  legend?: boolean
116
+ /**
117
+ * Where the legend sits. Defaults to bottom-left: hosts commonly float a
118
+ * toolbar across the top, which would cover a top-anchored legend, and the
119
+ * minimap owns the bottom-right.
120
+ */
121
+ legendPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right"
116
122
  /**
117
123
  * Background swimlanes drawn beneath the nodes (one per project / overlay).
118
124
  * Non-interactive; pan/zoom with the graph. Empty = no lanes.
119
125
  */
120
126
  lanes?: TopologyLane[]
121
127
  }>(),
122
- { connectable: false, selectable: false, legend: true, lanes: () => [] },
128
+ {
129
+ connectable: false,
130
+ selectable: false,
131
+ legend: true,
132
+ legendPosition: "bottom-left",
133
+ lanes: () => [],
134
+ },
123
135
  )
124
136
 
125
137
  const emit = defineEmits<{
@@ -290,6 +302,14 @@ onNodeContextMenu(({ node, event }) => {
290
302
  e.preventDefault?.()
291
303
  emit("node-contextmenu", { id: node.id, x: e.clientX, y: e.clientY })
292
304
  })
305
+ // Vue Flow's zoom Controls sit bottom-left and the MiniMap bottom-right; clear
306
+ // whichever the legend shares a corner with so they don't stack.
307
+ const legendOffset = computed(() => {
308
+ if (props.legendPosition === "bottom-left") return "!left-12"
309
+ if (props.legendPosition === "bottom-right") return "!bottom-40"
310
+ return ""
311
+ })
312
+
293
313
  // Legend rows mirror the edge encoding exactly (same colours/dashes).
294
314
  const legendItems = [
295
315
  { label: "Network", color: CATEGORY_COLOR.network, width: 2, dash: "0" },
@@ -338,7 +358,7 @@ defineExpose({ fitView, setViewport: applyViewport })
338
358
  <Controls />
339
359
 
340
360
  <!-- Edge-type legend: makes the colour/dash encoding self-explanatory. -->
341
- <Panel v-if="legend" position="top-right">
361
+ <Panel v-if="legend" :position="legendPosition" :class="legendOffset">
342
362
  <div
343
363
  class="flex flex-col gap-1.5 rounded-card border border-line bg-surface-overlay/90 px-3 py-2 text-[11px] backdrop-blur"
344
364
  >