@leavepulse/ui 0.22.1 → 0.22.3

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"],
@@ -102,7 +103,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
102
103
  source: e.source,
103
104
  target: e.target,
104
105
  type: "default",
105
- animated: obs !== "applied",
106
+ animated: obs !== "applied" && !e.dimmed,
106
107
  label: e.kind,
107
108
  labelBgStyle: { fill: "var(--color-surface)" },
108
109
  labelStyle: { fill: "var(--color-muted-strong)", fontSize: "10px" },
@@ -110,7 +111,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
110
111
  stroke: color,
111
112
  strokeWidth: cat === "structural" ? 1.5 : 2,
112
113
  strokeDasharray: edgeDash(cat, obs),
113
- strokeLinecap: "round"
114
+ strokeLinecap: "round",
115
+ opacity: e.dimmed ? 0.12 : 1
114
116
  },
115
117
  markerEnd: { type: MarkerType.ArrowClosed, color }
116
118
  };
@@ -149,6 +151,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
149
151
  e.preventDefault?.();
150
152
  emit("node-contextmenu", { id: node.id, x: e.clientX, y: e.clientY });
151
153
  });
154
+ const legendOffset = computed(() => {
155
+ if (props.legendPosition === "bottom-left") return "!left-12";
156
+ if (props.legendPosition === "bottom-right") return "!bottom-40";
157
+ return "";
158
+ });
152
159
  const legendItems = [
153
160
  { label: "Network", color: CATEGORY_COLOR.network, width: 2, dash: "0" },
154
161
  { label: "Depends-on", color: CATEGORY_COLOR.structural, width: 1.5, dash: "1 5" },
@@ -198,7 +205,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
198
205
  createVNode(unref(Controls)),
199
206
  __props.legend ? (openBlock(), createBlock(unref(Panel), {
200
207
  key: 0,
201
- position: "top-right"
208
+ position: __props.legendPosition,
209
+ class: normalizeClass(legendOffset.value)
202
210
  }, {
203
211
  default: withCtx(() => [
204
212
  createElementVNode("div", _hoisted_1, [
@@ -225,7 +233,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
225
233
  ])
226
234
  ]),
227
235
  _: 1
228
- })) : createCommentVNode("", true)
236
+ }, 8, ["position", "class"])) : createCommentVNode("", true)
229
237
  ]),
230
238
  _: 1
231
239
  }, 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" };
@@ -40,6 +40,12 @@ export interface TopologyEdge {
40
40
  /** Semantic class driving colour + dash. Inferred from `kind` if omitted. */
41
41
  category?: EdgeCategory;
42
42
  observed?: EdgeObserved;
43
+ /**
44
+ * Push the edge into the background, matching the node data's `dimmed`. A
45
+ * focus highlight has to fade the edges too — dimming only the nodes leaves
46
+ * every unrelated line at full strength.
47
+ */
48
+ dimmed?: boolean;
43
49
  }
44
50
  /**
45
51
  * A background swimlane: a sized zone (one per project / overlay network) drawn
@@ -78,6 +84,12 @@ type __VLS_Props = {
78
84
  selectable?: boolean;
79
85
  /** Show the edge-type legend (Network / Depends-on / Pending / Drift). */
80
86
  legend?: boolean;
87
+ /**
88
+ * Where the legend sits. Defaults to bottom-left: hosts commonly float a
89
+ * toolbar across the top, which would cover a top-anchored legend, and the
90
+ * minimap owns the bottom-right.
91
+ */
92
+ legendPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
81
93
  /**
82
94
  * Background swimlanes drawn beneath the nodes (one per project / overlay).
83
95
  * Non-interactive; pan/zoom with the graph. Empty = no lanes.
@@ -148,6 +160,7 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {
148
160
  legend: boolean;
149
161
  connectable: boolean;
150
162
  selectable: boolean;
163
+ legendPosition: "top-left" | "top-right" | "bottom-left" | "bottom-right";
151
164
  lanes: TopologyLane[];
152
165
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
153
166
  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-DCQINTZE.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-DCQINTZE.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.1",
3
+ "version": "0.22.3",
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)
@@ -71,6 +71,12 @@ export interface TopologyEdge {
71
71
  /** Semantic class driving colour + dash. Inferred from `kind` if omitted. */
72
72
  category?: EdgeCategory
73
73
  observed?: EdgeObserved
74
+ /**
75
+ * Push the edge into the background, matching the node data's `dimmed`. A
76
+ * focus highlight has to fade the edges too — dimming only the nodes leaves
77
+ * every unrelated line at full strength.
78
+ */
79
+ dimmed?: boolean
74
80
  }
75
81
 
76
82
  /**
@@ -113,13 +119,25 @@ const props = withDefaults(
113
119
  selectable?: boolean
114
120
  /** Show the edge-type legend (Network / Depends-on / Pending / Drift). */
115
121
  legend?: boolean
122
+ /**
123
+ * Where the legend sits. Defaults to bottom-left: hosts commonly float a
124
+ * toolbar across the top, which would cover a top-anchored legend, and the
125
+ * minimap owns the bottom-right.
126
+ */
127
+ legendPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right"
116
128
  /**
117
129
  * Background swimlanes drawn beneath the nodes (one per project / overlay).
118
130
  * Non-interactive; pan/zoom with the graph. Empty = no lanes.
119
131
  */
120
132
  lanes?: TopologyLane[]
121
133
  }>(),
122
- { connectable: false, selectable: false, legend: true, lanes: () => [] },
134
+ {
135
+ connectable: false,
136
+ selectable: false,
137
+ legend: true,
138
+ legendPosition: "bottom-left",
139
+ lanes: () => [],
140
+ },
123
141
  )
124
142
 
125
143
  const emit = defineEmits<{
@@ -236,7 +254,7 @@ const flowEdges = computed(() =>
236
254
  source: e.source,
237
255
  target: e.target,
238
256
  type: "default",
239
- animated: obs !== "applied",
257
+ animated: obs !== "applied" && !e.dimmed,
240
258
  label: e.kind,
241
259
  labelBgStyle: { fill: "var(--color-surface)" },
242
260
  labelStyle: { fill: "var(--color-muted-strong)", fontSize: "10px" },
@@ -245,6 +263,7 @@ const flowEdges = computed(() =>
245
263
  strokeWidth: cat === "structural" ? 1.5 : 2,
246
264
  strokeDasharray: edgeDash(cat, obs),
247
265
  strokeLinecap: "round" as const,
266
+ opacity: e.dimmed ? 0.12 : 1,
248
267
  },
249
268
  markerEnd: { type: MarkerType.ArrowClosed, color },
250
269
  }
@@ -290,6 +309,14 @@ onNodeContextMenu(({ node, event }) => {
290
309
  e.preventDefault?.()
291
310
  emit("node-contextmenu", { id: node.id, x: e.clientX, y: e.clientY })
292
311
  })
312
+ // Vue Flow's zoom Controls sit bottom-left and the MiniMap bottom-right; clear
313
+ // whichever the legend shares a corner with so they don't stack.
314
+ const legendOffset = computed(() => {
315
+ if (props.legendPosition === "bottom-left") return "!left-12"
316
+ if (props.legendPosition === "bottom-right") return "!bottom-40"
317
+ return ""
318
+ })
319
+
293
320
  // Legend rows mirror the edge encoding exactly (same colours/dashes).
294
321
  const legendItems = [
295
322
  { label: "Network", color: CATEGORY_COLOR.network, width: 2, dash: "0" },
@@ -338,7 +365,7 @@ defineExpose({ fitView, setViewport: applyViewport })
338
365
  <Controls />
339
366
 
340
367
  <!-- Edge-type legend: makes the colour/dash encoding self-explanatory. -->
341
- <Panel v-if="legend" position="top-right">
368
+ <Panel v-if="legend" :position="legendPosition" :class="legendOffset">
342
369
  <div
343
370
  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
371
  >