@leavepulse/ui 0.60.0 → 0.61.0

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 (62) hide show
  1. package/README.md +8 -0
  2. package/dist/assets/{LpTable-BZZf_rrt.css → LpTable-DpXyPzs8.css} +19 -19
  3. package/dist/chunks/{LpAddressInput-DD4zTN4P.js → LpAddressInput-CzdZguBo.js} +1 -1
  4. package/dist/chunks/{LpAppShell-Cv-Y9qNA.js → LpAppShell-BXMNDEpF.js} +1 -1
  5. package/dist/chunks/{LpAutocomplete-PnL2ntKl.js → LpAutocomplete-D9mY5Tqk.js} +101 -36
  6. package/dist/chunks/{LpAvatar-CwGs1JCQ.js → LpAvatar-K6MOMfgn.js} +1 -1
  7. package/dist/chunks/{LpCard-B2D0GIUU.js → LpCard-D9HVgX8Y.js} +1 -1
  8. package/dist/chunks/{LpColorPicker-CvBF8TeL.js → LpColorPicker-BO1ZTY51.js} +1 -1
  9. package/dist/chunks/{LpContextMenu-BnN1k7ga.js → LpContextMenu-Cv_F2iCG.js} +6 -3
  10. package/dist/chunks/{LpFileTree-DEqh2ySW.js → LpFileTree-DTwUj0L-.js} +1 -1
  11. package/dist/chunks/{LpFileTreeNode-DCZA7sQ-.js → LpFileTreeNode-D-XLPZ6T.js} +1 -1
  12. package/dist/chunks/{LpLogViewer-BuPe23sZ.js → LpLogViewer-D9UgNz2m.js} +1 -1
  13. package/dist/chunks/{LpModalNav-Cw7m-eks.js → LpModalNav-D4rmflQn.js} +1 -1
  14. package/dist/chunks/{LpNotificationBell-xH_JphpS.js → LpNotificationBell-CyylOlZR.js} +1 -1
  15. package/dist/chunks/{LpPie-BD5Lsh-2.js → LpPie-B2deu8CI.js} +1 -1
  16. package/dist/chunks/{LpSidebar-B3E_iViL.js → LpSidebar-D8tub3bt.js} +1 -1
  17. package/dist/chunks/{LpSidebarNav-32sAXNM-.js → LpSidebarNav-BBSRg34G.js} +1 -1
  18. package/dist/chunks/LpSwap-D82jiecV.js +38 -0
  19. package/dist/chunks/{LpThemeSwitcher-CeBG0e_D.js → LpThemeSwitcher-ZFFftBQn.js} +1 -1
  20. package/dist/chunks/{LpToaster-BcKs7vX7.js → LpToaster-D3OisETH.js} +1 -1
  21. package/dist/component-names.d.ts +1 -1
  22. package/dist/components/LpAddressInput.vue.js +1 -1
  23. package/dist/components/LpAppShell.vue.js +1 -1
  24. package/dist/components/LpAutocomplete.vue.d.ts +24 -0
  25. package/dist/components/LpAutocomplete.vue.js +1 -1
  26. package/dist/components/LpAvatar.vue.js +1 -1
  27. package/dist/components/LpCard.vue.js +1 -1
  28. package/dist/components/LpChart.vue.js +1 -1
  29. package/dist/components/LpColorPicker.vue.js +1 -1
  30. package/dist/components/LpCommandPalette.vue.js +1 -1
  31. package/dist/components/LpContextMenu.vue.js +1 -1
  32. package/dist/components/LpFileTree.vue.js +1 -1
  33. package/dist/components/LpFileTreeNode.vue.js +1 -1
  34. package/dist/components/LpLogViewer.vue.js +1 -1
  35. package/dist/components/LpModalNav.vue.js +1 -1
  36. package/dist/components/LpNotificationBell.vue.js +1 -1
  37. package/dist/components/LpPaletteHeader.vue.js +1 -1
  38. package/dist/components/LpPie.vue.js +1 -1
  39. package/dist/components/LpSidebar.vue.js +1 -1
  40. package/dist/components/LpSidebarNav.vue.js +1 -1
  41. package/dist/components/LpSwap.vue.d.ts +19 -0
  42. package/dist/components/LpSwap.vue.js +4 -0
  43. package/dist/components/LpTable.vue.js +5 -4
  44. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  45. package/dist/components/LpToaster.vue.js +1 -1
  46. package/dist/composables/useHintSystem.d.ts +2 -0
  47. package/dist/composables/useHintSystem.js +16 -4
  48. package/dist/composables/useToast.d.ts +13 -4
  49. package/dist/composables/useToast.js +13 -2
  50. package/dist/index.d.ts +3 -2
  51. package/dist/index.js +62 -60
  52. package/package.json +2 -1
  53. package/src/component-names.ts +1 -0
  54. package/src/components/LpAutocomplete.vue +110 -24
  55. package/src/components/LpContextMenu.vue +6 -3
  56. package/src/components/LpSwap.vue +45 -0
  57. package/src/components/LpTable.vue +1 -0
  58. package/src/components/LpToaster.vue +1 -1
  59. package/src/composables/useHintSystem.ts +26 -4
  60. package/src/composables/useToast.ts +32 -5
  61. package/src/index.ts +3 -1
  62. package/src/tokens/selection.css +20 -0
package/README.md CHANGED
@@ -161,6 +161,14 @@ scroll restoration and anchor jumps keep working:
161
161
 
162
162
  Hide a specific scrollbar with the `lp-scrollbar-none` class.
163
163
 
164
+ Selected text takes the operating system's accent unless told otherwise (on
165
+ Linux that is the GTK theme, so it can come out red or green next to the kit
166
+ palette). Opt into the theme's colour the same way:
167
+
168
+ ```css
169
+ @import "@leavepulse/ui/selection.css"; /* after the tokens — reads --color-brand */
170
+ ```
171
+
164
172
  ## Develop
165
173
 
166
174
  ```bash
@@ -11,17 +11,17 @@
11
11
  * fade before closing the gap and the whole list lurches at the end instead of
12
12
  * gliding.
13
13
  */
14
- .lp-row-enter-active[data-v-1d2375a8],
15
- .lp-row-leave-active[data-v-1d2375a8] {
14
+ .lp-row-enter-active[data-v-a9d69d56],
15
+ .lp-row-leave-active[data-v-a9d69d56] {
16
16
  transition:
17
17
  opacity var(--duration-fast) var(--ease-emphasized),
18
18
  transform var(--duration-fast) var(--ease-emphasized);
19
19
  }
20
- .lp-row-move[data-v-1d2375a8] {
20
+ .lp-row-move[data-v-a9d69d56] {
21
21
  transition: transform var(--duration-medium) var(--ease-emphasized);
22
22
  }
23
- .lp-row-enter-from[data-v-1d2375a8],
24
- .lp-row-leave-to[data-v-1d2375a8] {
23
+ .lp-row-enter-from[data-v-a9d69d56],
24
+ .lp-row-leave-to[data-v-a9d69d56] {
25
25
  opacity: 0;
26
26
  transform: translateX(-0.5rem);
27
27
  }
@@ -35,7 +35,7 @@
35
35
  * drops out of the table layout entirely. Nothing sits below this row to be
36
36
  * dragged around, so simply not animating its exit costs nothing.
37
37
  */
38
- .lp-row-empty.lp-row-leave-active[data-v-1d2375a8] {
38
+ .lp-row-empty.lp-row-leave-active[data-v-a9d69d56] {
39
39
  display: none;
40
40
  }
41
41
 
@@ -54,7 +54,7 @@
54
54
  * once anything is selected. An earlier version collapsed the column to nothing
55
55
  * and floated the hover box over the first cell, where it sat on the text.
56
56
  */
57
- .lp-tick[data-v-1d2375a8] {
57
+ .lp-tick[data-v-a9d69d56] {
58
58
  display: flex;
59
59
  align-items: center;
60
60
  max-width: 0;
@@ -66,17 +66,17 @@
66
66
  padding var(--duration-medium) var(--ease-emphasized),
67
67
  opacity var(--duration-fast) ease;
68
68
  }
69
- .lp-tick-open[data-v-1d2375a8] {
69
+ .lp-tick-open[data-v-a9d69d56] {
70
70
  max-width: 3.25rem;
71
71
  padding-inline: 1rem;
72
72
  opacity: 1;
73
73
  }
74
- .lp-tick-hidden[data-v-1d2375a8],
75
- .lp-tick-cue[data-v-1d2375a8] {
74
+ .lp-tick-hidden[data-v-a9d69d56],
75
+ .lp-tick-cue[data-v-a9d69d56] {
76
76
  opacity: 0;
77
77
  }
78
- tr:hover .lp-tick-cue[data-v-1d2375a8],
79
- .lp-tick-cue[data-v-1d2375a8]:focus-within {
78
+ tr:hover .lp-tick-cue[data-v-a9d69d56],
79
+ .lp-tick-cue[data-v-a9d69d56]:focus-within {
80
80
  opacity: 1;
81
81
  }
82
82
 
@@ -84,24 +84,24 @@ tr:hover .lp-tick-cue[data-v-1d2375a8],
84
84
  turned down the rows change without animating rather than not changing. */
85
85
  /* Only where there is a hover to reveal it; a finger long-presses instead. */
86
86
  @media (hover: none) {
87
- tr:hover .lp-tick-cue[data-v-1d2375a8] {
87
+ tr:hover .lp-tick-cue[data-v-a9d69d56] {
88
88
  opacity: 0;
89
89
  }
90
90
 
91
91
  /* Nor is there anything for the column's width to hold until then: on a
92
92
  touch screen it stays closed until a long press starts selecting, and
93
93
  eases open like the rest of the column. */
94
- .lp-tick-hidden[data-v-1d2375a8],
95
- .lp-tick-cue[data-v-1d2375a8] {
94
+ .lp-tick-hidden[data-v-a9d69d56],
95
+ .lp-tick-cue[data-v-a9d69d56] {
96
96
  max-width: 0;
97
97
  padding-inline: 0;
98
98
  }
99
99
  }
100
100
  @media (prefers-reduced-motion: reduce) {
101
- .lp-row-enter-active[data-v-1d2375a8],
102
- .lp-row-leave-active[data-v-1d2375a8],
103
- .lp-row-move[data-v-1d2375a8],
104
- .lp-tick[data-v-1d2375a8] {
101
+ .lp-row-enter-active[data-v-a9d69d56],
102
+ .lp-row-leave-active[data-v-a9d69d56],
103
+ .lp-row-move[data-v-a9d69d56],
104
+ .lp-tick[data-v-a9d69d56] {
105
105
  transition: none;
106
106
  }
107
107
  }
@@ -2,7 +2,7 @@ import { defineComponent, defineAsyncComponent, computed, watch, ref, onMounted,
2
2
  import { useAsyncTask } from "../composables/useAsyncTask.js";
3
3
  import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress } from "../components/address.js";
4
4
  import { flagEmoji, loadCountries } from "../components/countries.js";
5
- import { _ as _sfc_main$2 } from "./LpAutocomplete-PnL2ntKl.js";
5
+ import { _ as _sfc_main$2 } from "./LpAutocomplete-D9mY5Tqk.js";
6
6
  import { _ as _sfc_main$3 } from "./LpButton-CJSD7N0Z.js";
7
7
  import { _ as _sfc_main$1 } from "./LpFormField-DMPPL1jF.js";
8
8
  import { _ as _sfc_main$4 } from "./LpIcon-CTuDVTYv.js";
@@ -4,7 +4,7 @@ import { _ as _sfc_main$2 } from "./LpButton-CJSD7N0Z.js";
4
4
  import { _ as _sfc_main$3 } from "./LpIcon-CTuDVTYv.js";
5
5
  import { _ as _sfc_main$5 } from "./LpScrollArea-Hz3-JWUG.js";
6
6
  import { _ as _sfc_main$4 } from "./LpShift-DXNsauQZ.js";
7
- import { _ as _sfc_main$1 } from "./LpSidebar-B3E_iViL.js";
7
+ import { _ as _sfc_main$1 } from "./LpSidebar-D8tub3bt.js";
8
8
  import { useMergedAttrs } from "../composables/useMergedClass.js";
9
9
  const _hoisted_1 = ["href"];
10
10
  const _hoisted_2 = { class: "flex min-w-0 flex-1 flex-col" };
@@ -1,18 +1,27 @@
1
- import { defineComponent, computed, useAttrs, ref, watch, openBlock, createBlock, unref, normalizeStyle, normalizeClass, withCtx, createVNode, createCommentVNode, mergeProps, createElementBlock, withModifiers, toDisplayString, createTextVNode, Fragment, renderList, createElementVNode } from "vue";
1
+ import { defineComponent, computed, useAttrs, ref, watch, openBlock, createBlock, unref, normalizeStyle, normalizeClass, withCtx, createVNode, createElementBlock, createCommentVNode, createElementVNode, mergeProps, Transition, toDisplayString, withModifiers, createTextVNode, Fragment, renderList, nextTick } from "vue";
2
2
  import { ComboboxRoot, ComboboxAnchor, ComboboxInput, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxItem } from "reka-ui";
3
3
  import { useFieldControl } from "../composables/useField.js";
4
4
  import { useInputFilter } from "../composables/useInputFilter.js";
5
5
  import { useLabels } from "../composables/useLpConfig.js";
6
6
  import { CLOSE_ICON, POPOVER_PANEL, OPTION_ITEM } from "../components/dropdown.js";
7
7
  import { _ as _sfc_main$1 } from "./LpIcon-CTuDVTYv.js";
8
- const _hoisted_1 = ["aria-label"];
9
- const _hoisted_2 = {
8
+ const _hoisted_1 = ["src"];
9
+ const _hoisted_2 = { class: "relative flex min-w-0 flex-1 self-stretch" };
10
+ const _hoisted_3 = {
10
11
  key: 0,
11
- class: "px-3 py-4 text-center text-sm italic text-muted"
12
+ class: "pointer-events-none absolute inset-0 flex min-w-0 items-center gap-1.5",
13
+ "aria-hidden": "true"
12
14
  };
13
- const _hoisted_3 = { class: "flex min-w-0 flex-col" };
14
- const _hoisted_4 = { class: "truncate" };
15
+ const _hoisted_4 = ["aria-label"];
15
16
  const _hoisted_5 = {
17
+ key: 0,
18
+ class: "px-3 py-4 text-center text-sm italic text-muted"
19
+ };
20
+ const _hoisted_6 = { class: "flex min-w-0 items-center gap-2.5" };
21
+ const _hoisted_7 = ["src"];
22
+ const _hoisted_8 = { class: "flex min-w-0 flex-col" };
23
+ const _hoisted_9 = { class: "truncate" };
24
+ const _hoisted_10 = {
16
25
  key: 0,
17
26
  class: "truncate text-xs text-muted"
18
27
  };
@@ -35,7 +44,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
35
44
  filter: { type: Boolean, default: true },
36
45
  minChars: { default: 1 },
37
46
  pattern: {},
38
- restrict: {}
47
+ restrict: {},
48
+ selected: {}
39
49
  },
40
50
  emits: ["update:modelValue", "select"],
41
51
  setup(__props, { emit: __emit }) {
@@ -78,6 +88,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
78
88
  });
79
89
  const open = ref(false);
80
90
  const focused = ref(false);
91
+ const showSelected = computed(() => !!props.selected?.label && !focused.value);
92
+ const draft = ref(null);
93
+ const showImage = computed(() => !!props.selected?.image && (!focused.value || draft.value !== null));
81
94
  const canOpen = computed(
82
95
  () => text.value.length >= props.minChars && (props.loading || filtered.value.length > 0)
83
96
  );
@@ -96,21 +109,33 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
96
109
  function onInput(event) {
97
110
  filterInput(event);
98
111
  typing.value = true;
112
+ draft.value = null;
99
113
  text.value = event.target.value;
100
114
  }
101
- function onFocus() {
115
+ function onFocus(event) {
102
116
  typing.value = false;
103
117
  focused.value = true;
118
+ if (props.selected?.label) {
119
+ draft.value = props.selected.label;
120
+ const input = event.target;
121
+ void nextTick(() => input.select());
122
+ }
104
123
  if (canOpen.value) open.value = true;
105
124
  }
125
+ function onBlur() {
126
+ focused.value = false;
127
+ draft.value = null;
128
+ }
106
129
  function choose(opt) {
107
130
  typing.value = false;
131
+ draft.value = null;
108
132
  emit("update:modelValue", opt.value);
109
133
  emit("select", opt.value);
110
134
  open.value = false;
111
135
  }
112
136
  function clear() {
113
137
  typing.value = false;
138
+ draft.value = null;
114
139
  emit("update:modelValue", "");
115
140
  open.value = false;
116
141
  }
@@ -134,34 +159,66 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
134
159
  ]])
135
160
  }, {
136
161
  default: withCtx(() => [
137
- __props.icon ? (openBlock(), createBlock(_sfc_main$1, {
162
+ __props.icon || __props.selected?.image ? (openBlock(), createElementBlock("span", {
138
163
  key: 0,
139
- name: __props.icon,
140
- size: 16,
141
- class: "shrink-0 text-muted"
142
- }, null, 8, ["name"])) : createCommentVNode("", true),
143
- createVNode(unref(ComboboxInput), mergeProps(inputAttrs.value, {
144
- id: unref(field).id,
145
- "model-value": text.value,
146
- placeholder: __props.placeholder,
147
- disabled: unref(field).disabled,
148
- required: unref(field).required || void 0,
149
- "aria-invalid": isInvalidState.value || void 0,
150
- "aria-describedby": unref(field).describedBy,
151
- class: "lp-autofill min-w-0 flex-1 self-stretch bg-transparent outline-none placeholder:text-muted",
152
- onBeforeinput: unref(onBeforeInput),
153
- onPaste: unref(onPaste),
154
- onCompositionend: unref(onCompositionEnd),
155
- onInput,
156
- onFocus,
157
- onBlur: _cache[0] || (_cache[0] = ($event) => focused.value = false)
158
- }), null, 16, ["id", "model-value", "placeholder", "disabled", "required", "aria-invalid", "aria-describedby", "onBeforeinput", "onPaste", "onCompositionend"]),
164
+ class: normalizeClass(["relative grid shrink-0 place-items-center", __props.selected?.image ? "size-5" : "size-4"])
165
+ }, [
166
+ __props.icon ? (openBlock(), createBlock(_sfc_main$1, {
167
+ key: 0,
168
+ name: __props.icon,
169
+ size: 16,
170
+ class: normalizeClass(["col-start-1 row-start-1 text-muted transition-[opacity,scale] duration-[var(--duration-fast)] motion-reduce:transition-none", showImage.value ? "scale-75 opacity-0" : "opacity-100"])
171
+ }, null, 8, ["name", "class"])) : createCommentVNode("", true),
172
+ __props.selected?.image ? (openBlock(), createElementBlock("img", {
173
+ key: 1,
174
+ src: __props.selected.image,
175
+ alt: "",
176
+ class: normalizeClass(["col-start-1 row-start-1 size-5 rounded-full object-cover transition-[opacity,scale] duration-[var(--duration-fast)] motion-reduce:transition-none", showImage.value ? "opacity-100" : "scale-75 opacity-0"])
177
+ }, null, 10, _hoisted_1)) : createCommentVNode("", true)
178
+ ], 2)) : createCommentVNode("", true),
179
+ createElementVNode("div", _hoisted_2, [
180
+ createVNode(unref(ComboboxInput), mergeProps(inputAttrs.value, {
181
+ id: unref(field).id,
182
+ "model-value": draft.value ?? text.value,
183
+ placeholder: __props.placeholder,
184
+ disabled: unref(field).disabled,
185
+ required: unref(field).required || void 0,
186
+ "aria-invalid": isInvalidState.value || void 0,
187
+ "aria-describedby": unref(field).describedBy,
188
+ class: ["lp-autofill min-w-0 flex-1 self-stretch bg-transparent outline-none placeholder:text-muted", showSelected.value && "text-transparent placeholder:text-transparent"],
189
+ onBeforeinput: unref(onBeforeInput),
190
+ onPaste: unref(onPaste),
191
+ onCompositionend: unref(onCompositionEnd),
192
+ onInput,
193
+ onFocus,
194
+ onBlur
195
+ }), null, 16, ["id", "model-value", "placeholder", "disabled", "required", "aria-invalid", "aria-describedby", "class", "onBeforeinput", "onPaste", "onCompositionend"]),
196
+ createVNode(Transition, {
197
+ "enter-active-class": "transition-opacity duration-[var(--duration-fast)] motion-reduce:transition-none",
198
+ "leave-active-class": "transition-opacity duration-[var(--duration-fast)] motion-reduce:transition-none",
199
+ "enter-from-class": "opacity-0",
200
+ "leave-to-class": "opacity-0"
201
+ }, {
202
+ default: withCtx(() => [
203
+ __props.selected?.label ? (openBlock(), createElementBlock("span", _hoisted_3, [
204
+ createElementVNode("span", {
205
+ class: normalizeClass(["max-w-full shrink-0 truncate", showSelected.value ? "" : "invisible"])
206
+ }, toDisplayString(__props.selected.label), 3),
207
+ __props.selected.hint ? (openBlock(), createElementBlock("span", {
208
+ key: 0,
209
+ class: normalizeClass(["min-w-0 truncate text-sm text-muted transition-[opacity,translate] duration-[var(--duration-fast)] motion-reduce:transition-none", showSelected.value ? "opacity-100" : "-translate-x-1 opacity-0"])
210
+ }, toDisplayString(__props.selected.hint), 3)) : createCommentVNode("", true)
211
+ ])) : createCommentVNode("", true)
212
+ ]),
213
+ _: 1
214
+ })
215
+ ]),
159
216
  __props.clearable && hasValue.value ? (openBlock(), createElementBlock("button", {
160
217
  key: 1,
161
218
  type: "button",
162
219
  class: "group flex shrink-0 items-center text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink",
163
220
  "aria-label": unref(labels).clear,
164
- onPointerdown: _cache[1] || (_cache[1] = withModifiers(() => {
221
+ onPointerdown: _cache[0] || (_cache[0] = withModifiers(() => {
165
222
  }, ["prevent"])),
166
223
  onClick: clear
167
224
  }, [
@@ -170,7 +227,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
170
227
  size: 16,
171
228
  class: normalizeClass(unref(CLOSE_ICON))
172
229
  }, null, 8, ["class"])
173
- ], 40, _hoisted_1)) : createCommentVNode("", true)
230
+ ], 40, _hoisted_4)) : createCommentVNode("", true)
174
231
  ]),
175
232
  _: 1
176
233
  }, 8, ["class"]),
@@ -181,13 +238,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
181
238
  position: "popper",
182
239
  "side-offset": 6,
183
240
  class: normalizeClass([unref(POPOVER_PANEL), "z-(--z-popover) max-h-72 w-(--reka-combobox-trigger-width) overflow-hidden"]),
184
- onOpenAutoFocus: _cache[2] || (_cache[2] = withModifiers(() => {
241
+ onOpenAutoFocus: _cache[1] || (_cache[1] = withModifiers(() => {
185
242
  }, ["prevent"]))
186
243
  }, {
187
244
  default: withCtx(() => [
188
245
  createVNode(unref(ComboboxViewport), { class: "max-h-72 overflow-y-auto p-1" }, {
189
246
  default: withCtx(() => [
190
- __props.loading ? (openBlock(), createElementBlock("div", _hoisted_2, toDisplayString(__props.loadingText), 1)) : (openBlock(), createBlock(unref(ComboboxEmpty), {
247
+ __props.loading ? (openBlock(), createElementBlock("div", _hoisted_5, toDisplayString(__props.loadingText), 1)) : (openBlock(), createBlock(unref(ComboboxEmpty), {
191
248
  key: 1,
192
249
  class: "px-3 py-4 text-center text-sm italic text-muted"
193
250
  }, {
@@ -205,9 +262,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
205
262
  onSelect: withModifiers(($event) => choose(opt), ["prevent"])
206
263
  }, {
207
264
  default: withCtx(() => [
208
- createElementVNode("span", _hoisted_3, [
209
- createElementVNode("span", _hoisted_4, toDisplayString(opt.label ?? opt.value), 1),
210
- opt.description ? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString(opt.description), 1)) : createCommentVNode("", true)
265
+ createElementVNode("span", _hoisted_6, [
266
+ opt.image ? (openBlock(), createElementBlock("img", {
267
+ key: 0,
268
+ src: opt.image,
269
+ alt: "",
270
+ class: "size-6 shrink-0 rounded-full object-cover"
271
+ }, null, 8, _hoisted_7)) : createCommentVNode("", true),
272
+ createElementVNode("span", _hoisted_8, [
273
+ createElementVNode("span", _hoisted_9, toDisplayString(opt.label ?? opt.value), 1),
274
+ opt.description ? (openBlock(), createElementBlock("span", _hoisted_10, toDisplayString(opt.description), 1)) : createCommentVNode("", true)
275
+ ])
211
276
  ])
212
277
  ]),
213
278
  _: 2
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, computed, ref, onMounted, openBlock, createBlock, withCtx, createVNode, unref, mergeProps, createCommentVNode, createElementBlock, Fragment, createTextVNode, toDisplayString } from "vue";
2
2
  import { AvatarRoot, AvatarImage, AvatarFallback } from "reka-ui";
3
3
  import { tv } from "tailwind-variants";
4
- import { _ as _sfc_main$1 } from "./LpContextMenu-BnN1k7ga.js";
4
+ import { _ as _sfc_main$1 } from "./LpContextMenu-Cv_F2iCG.js";
5
5
  import { _ as _sfc_main$2 } from "./LpIcon-CTuDVTYv.js";
6
6
  import { useMergedAttrs } from "../composables/useMergedClass.js";
7
7
  const __default__ = { inheritAttrs: false };
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, computed, openBlock, createBlock, withCtx, resolveDynamicComponent, mergeProps, unref, renderSlot } from "vue";
2
2
  import { tv } from "tailwind-variants";
3
3
  import { useMergedAttrs } from "../composables/useMergedClass.js";
4
- import { _ as _sfc_main$1 } from "./LpContextMenu-BnN1k7ga.js";
4
+ import { _ as _sfc_main$1 } from "./LpContextMenu-Cv_F2iCG.js";
5
5
  const __default__ = { inheritAttrs: false };
6
6
  const _sfc_main = /* @__PURE__ */ defineComponent({
7
7
  ...__default__,
@@ -5,7 +5,7 @@ import { useFieldControl } from "../composables/useField.js";
5
5
  import { DEFAULT_SWATCHES, formatColor, opaqueCss, parseColor, rgbToHsv, isLight, clampHsv } from "../components/color.js";
6
6
  import { useClipboard } from "../composables/useClipboard.js";
7
7
  import { POPOVER_PANEL } from "../components/dropdown.js";
8
- import { _ as _sfc_main$1 } from "./LpContextMenu-BnN1k7ga.js";
8
+ import { _ as _sfc_main$1 } from "./LpContextMenu-Cv_F2iCG.js";
9
9
  import { _ as _sfc_main$2 } from "./LpIcon-CTuDVTYv.js";
10
10
  import { _ as _sfc_main$3 } from "./LpRollingText-DB7upf-5.js";
11
11
  const _hoisted_1 = ["id", "disabled", "aria-label", "aria-invalid", "aria-describedby"];
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, computed, openBlock, createBlock, unref, withCtx, createVNode, renderSlot, normalizeClass, createCommentVNode } from "vue";
2
2
  import { ContextMenuRoot, ContextMenuTrigger, ContextMenuPortal, ContextMenuContent } from "reka-ui";
3
3
  import { hints } from "../composables/useHints.js";
4
- import { HINT_SIGNALS } from "../composables/useHintSystem.js";
4
+ import { HINT_SIGNALS, noteContextTarget } from "../composables/useHintSystem.js";
5
5
  import { _ as _sfc_main$2 } from "./ContextMenuItems-qXReFtQW.js";
6
6
  import { _ as _sfc_main$1 } from "./MenuTitle-FeC6I24N.js";
7
7
  import { POPOVER_PANEL } from "../components/dropdown.js";
@@ -34,8 +34,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
34
34
  function opened(open) {
35
35
  if (open) hints.use(HINT_SIGNALS.contextMenu);
36
36
  }
37
- function leftClick() {
38
- if (hinted.value) hints.use(HINT_SIGNALS.contextTarget);
37
+ function leftClick(event) {
38
+ if (!hinted.value) return;
39
+ hints.use(HINT_SIGNALS.contextTarget);
40
+ const el = event.currentTarget;
41
+ noteContextTarget(event.target.closest?.("[data-lp-context-row]") ?? el);
39
42
  }
40
43
  function returnFocus(event) {
41
44
  const saved = field;
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, ref, watch, computed, openBlock, createElementBlock, mergeProps, unref, Fragment, renderList, normalizeStyle, createBlock, createVNode, withCtx, createElementVNode, renderSlot, normalizeProps, guardReactiveProps, createTextVNode, toDisplayString, createCommentVNode } from "vue";
2
2
  import { computeStats, formatSize, sortNodes, subtreeIds, ancestorIds } from "../components/fileTree.js";
3
3
  import { _ as _sfc_main$1 } from "./LpEmptyState-CX8fdGSU.js";
4
- import { _ as _sfc_main$3 } from "./LpFileTreeNode-DCZA7sQ-.js";
4
+ import { _ as _sfc_main$3 } from "./LpFileTreeNode-D-XLPZ6T.js";
5
5
  import { _ as _sfc_main$2 } from "./LpScrollArea-Hz3-JWUG.js";
6
6
  import { useMergedAttrs } from "../composables/useMergedClass.js";
7
7
  import { useLabels } from "../composables/useLpConfig.js";
@@ -2,7 +2,7 @@ import { defineComponent, computed, resolveComponent, openBlock, createElementBl
2
2
  import { prefersReducedMotion, easingToken } from "../composables/easing.js";
3
3
  import { sortNodes, formatSize, formatModified, fileIcon } from "../components/fileTree.js";
4
4
  import { _ as _sfc_main$3 } from "./LpCheckbox-DV9W6T3H.js";
5
- import { _ as _sfc_main$1 } from "./LpContextMenu-BnN1k7ga.js";
5
+ import { _ as _sfc_main$1 } from "./LpContextMenu-Cv_F2iCG.js";
6
6
  import { _ as _sfc_main$2 } from "./LpIcon-CTuDVTYv.js";
7
7
  import { useMergedAttrs } from "../composables/useMergedClass.js";
8
8
  const _hoisted_1 = ["aria-level", "aria-selected", "aria-expanded", "aria-disabled"];
@@ -2,7 +2,7 @@ import { defineComponent, useModel, computed, ref, shallowRef, onMounted, onBefo
2
2
  import { prefersReducedMotion } from "../composables/easing.js";
3
3
  import { useClipboard } from "../composables/useClipboard.js";
4
4
  import { useHotkeys } from "../composables/useHotkeys.js";
5
- import { _ as _sfc_main$3 } from "./LpContextMenu-BnN1k7ga.js";
5
+ import { _ as _sfc_main$3 } from "./LpContextMenu-Cv_F2iCG.js";
6
6
  import { _ as _sfc_main$1 } from "./LpIcon-CTuDVTYv.js";
7
7
  import { _ as _sfc_main$2 } from "./LpScrollArea-Hz3-JWUG.js";
8
8
  import { useMergedAttrs } from "../composables/useMergedClass.js";
@@ -4,7 +4,7 @@ import { useLabels } from "../composables/useLpConfig.js";
4
4
  import { _ as _sfc_main$2 } from "./LpButton-CJSD7N0Z.js";
5
5
  import { _ as _sfc_main$3 } from "./LpIcon-CTuDVTYv.js";
6
6
  import { _ as _sfc_main$1 } from "./LpModal-QFfctZsj.js";
7
- import { _ as _sfc_main$4 } from "./LpSidebar-B3E_iViL.js";
7
+ import { _ as _sfc_main$4 } from "./LpSidebar-D8tub3bt.js";
8
8
  const _hoisted_1 = { class: "flex items-center gap-2" };
9
9
  const _sfc_main = /* @__PURE__ */ defineComponent({
10
10
  __name: "LpModalNav",
@@ -2,7 +2,7 @@ import { defineComponent, computed, useModel, getCurrentInstance, ref, onMounted
2
2
  import { useLabels } from "../composables/useLpConfig.js";
3
3
  import { _ as _sfc_main$8 } from "./LpBadge-Fe0D1bYx.js";
4
4
  import { _ as _sfc_main$7 } from "./LpButton-CJSD7N0Z.js";
5
- import { _ as _sfc_main$5 } from "./LpContextMenu-BnN1k7ga.js";
5
+ import { _ as _sfc_main$5 } from "./LpContextMenu-Cv_F2iCG.js";
6
6
  import { _ as _sfc_main$3 } from "./LpEmptyState-CX8fdGSU.js";
7
7
  import { _ as _sfc_main$6 } from "./LpIcon-CTuDVTYv.js";
8
8
  import { _ as _sfc_main$1 } from "./LpPopover-DCKeqiVn.js";
@@ -2,7 +2,7 @@ import { defineComponent, computed, ref, watch, onBeforeUnmount, openBlock, crea
2
2
  import { prefersReducedMotion, easeTravel } from "../composables/easing.js";
3
3
  import { useReveal } from "../composables/useReveal.js";
4
4
  import { resolveSlices, arcPath, calloutLabels, formatTick } from "../components/chart.js";
5
- import { _ as _sfc_main$2 } from "./LpContextMenu-BnN1k7ga.js";
5
+ import { _ as _sfc_main$2 } from "./LpContextMenu-Cv_F2iCG.js";
6
6
  import { _ as _sfc_main$1 } from "./LpIcon-CTuDVTYv.js";
7
7
  import { _ as _sfc_main$4 } from "./LpNumberFlow-z4WPZcZu.js";
8
8
  import { _ as _sfc_main$5 } from "./LpRollingText-DB7upf-5.js";
@@ -2,7 +2,7 @@ import { defineComponent, computed, ref, useId, openBlock, createElementBlock, F
2
2
  import { useLabels } from "../composables/useLpConfig.js";
3
3
  import { _ as _sfc_main$3 } from "./LpDrawer-C97yoWmh.js";
4
4
  import { _ as _sfc_main$1 } from "./LpInput-C7FHxzj2.js";
5
- import { _ as _sfc_main$2 } from "./LpSidebarNav-32sAXNM-.js";
5
+ import { _ as _sfc_main$2 } from "./LpSidebarNav-BBSRg34G.js";
6
6
  const _hoisted_1 = ["aria-label"];
7
7
  const _hoisted_2 = {
8
8
  key: 2,
@@ -3,7 +3,7 @@ import { Motion } from "motion-v";
3
3
  import { CollapsibleRoot, CollapsibleTrigger, CollapsibleContent } from "reka-ui";
4
4
  import { usePillTransition } from "../composables/usePillTransition.js";
5
5
  import { _ as _sfc_main$3 } from "./LpBadge-Fe0D1bYx.js";
6
- import { _ as _sfc_main$4 } from "./LpContextMenu-BnN1k7ga.js";
6
+ import { _ as _sfc_main$4 } from "./LpContextMenu-Cv_F2iCG.js";
7
7
  import { _ as _sfc_main$2 } from "./LpIcon-CTuDVTYv.js";
8
8
  import { _ as _sfc_main$1 } from "./LpScrollArea-Hz3-JWUG.js";
9
9
  import { resolveLink } from "../components/link.js";
@@ -0,0 +1,38 @@
1
+ import { defineComponent, openBlock, createBlock, withCtx, createVNode, Transition, createElementBlock, renderSlot } from "vue";
2
+ import { _ as _sfc_main$1 } from "./LpShift-DXNsauQZ.js";
3
+ const _sfc_main = /* @__PURE__ */ defineComponent({
4
+ __name: "LpSwap",
5
+ props: {
6
+ swapKey: {},
7
+ disabled: { type: Boolean }
8
+ },
9
+ setup(__props) {
10
+ return (_ctx, _cache) => {
11
+ return openBlock(), createBlock(_sfc_main$1, {
12
+ axis: "height",
13
+ disabled: __props.disabled
14
+ }, {
15
+ default: withCtx(() => [
16
+ createVNode(Transition, {
17
+ mode: "out-in",
18
+ css: !__props.disabled,
19
+ "enter-active-class": "animate-[tab-in_220ms_var(--ease-emphasized)] motion-reduce:animate-none",
20
+ "leave-active-class": "transition-opacity duration-[var(--duration-fast)] ease-out motion-reduce:transition-none",
21
+ "leave-to-class": "opacity-0"
22
+ }, {
23
+ default: withCtx(() => [
24
+ (openBlock(), createElementBlock("div", { key: __props.swapKey }, [
25
+ renderSlot(_ctx.$slots, "default")
26
+ ]))
27
+ ]),
28
+ _: 3
29
+ }, 8, ["css"])
30
+ ]),
31
+ _: 3
32
+ }, 8, ["disabled"]);
33
+ };
34
+ }
35
+ });
36
+ export {
37
+ _sfc_main as _
38
+ };
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, computed, onMounted, ref, openBlock, createBlock, withCtx, createElementVNode, normalizeClass, createElementBlock, createVNode, toDisplayString, createCommentVNode } from "vue";
2
2
  import { useLabels } from "../composables/useLpConfig.js";
3
3
  import { u as useTheme, p as presets } from "./useTheme-2qHG8NEU.js";
4
- import { _ as _sfc_main$1 } from "./LpContextMenu-BnN1k7ga.js";
4
+ import { _ as _sfc_main$1 } from "./LpContextMenu-Cv_F2iCG.js";
5
5
  import { _ as _sfc_main$2 } from "./LpIcon-CTuDVTYv.js";
6
6
  const _hoisted_1 = ["aria-label", "title"];
7
7
  const _hoisted_2 = {
@@ -154,7 +154,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
154
154
  let copiedTimer;
155
155
  const copyable = (t) => t.variant === "error" || t.variant === "warning";
156
156
  async function copyToast(t) {
157
- if (!await copy([t.title, t.message].filter(Boolean).join("\n"))) return;
157
+ if (!await copy([t.title, t.message, t.details].filter(Boolean).join("\n"))) return;
158
158
  copiedId.value = tag(t);
159
159
  clearTimeout(copiedTimer);
160
160
  copiedTimer = setTimeout(() => copiedId.value = null, 1500);
@@ -1 +1 @@
1
- export declare const COMPONENT_NAMES: readonly ["LayoutCanvas", "LpActionBar", "LpAddressInput", "LpAlert", "LpAppShell", "LpAutocomplete", "LpAvatar", "LpBadge", "LpBreadcrumbs", "LpButton", "LpCalendar", "LpCard", "LpChart", "LpCheckbox", "LpCodeBlock", "LpColorPicker", "LpCommandPalette", "LpConfirmDialog", "LpConfirmHost", "LpContextMenu", "LpDatePicker", "LpDateRangePicker", "LpDisclosure", "LpDivider", "LpDrawer", "LpDropdownMenu", "LpDropzone", "LpEmptyState", "LpFieldNotice", "LpFileTree", "LpFormField", "LpHintLayer", "LpHints", "LpIcon", "LpImageEditor", "LpInfraNode", "LpInput", "LpKeys", "LpLightbox", "LpLink", "LpLogViewer", "LpMapPicker", "LpMediaGallery", "LpModal", "LpModalNav", "LpNotificationBell", "LpNumberField", "LpNumberFlow", "LpOtpInput", "LpPagination", "LpPaletteFacts", "LpPaletteHeader", "LpPalettePreview", "LpPaletteStats", "LpPaletteSwatches", "LpPasswordInput", "LpPhoneInput", "LpPie", "LpPopover", "LpProgress", "LpRadio", "LpRadioGroup", "LpRangeCalendar", "LpRangeSlider", "LpRollingText", "LpScrollArea", "LpSection", "LpSegmented", "LpSelect", "LpServiceNode", "LpShift", "LpShortcutsDialog", "LpSidebar", "LpSkeleton", "LpSlider", "LpSparkline", "LpStat", "LpStepper", "LpSwitch", "LpTable", "LpTableOfContents", "LpTabs", "LpTagsInput", "LpTextarea", "LpThemeProvider", "LpThemeSwitcher", "LpTilt", "LpTimeField", "LpToaster", "LpTooltip", "LpTooltipProvider", "LpTopologyCanvas", "LpTour", "LpUptimeBar", "LpVideoBackdrop"];
1
+ export declare const COMPONENT_NAMES: readonly ["LayoutCanvas", "LpActionBar", "LpAddressInput", "LpAlert", "LpAppShell", "LpAutocomplete", "LpAvatar", "LpBadge", "LpBreadcrumbs", "LpButton", "LpCalendar", "LpCard", "LpChart", "LpCheckbox", "LpCodeBlock", "LpColorPicker", "LpCommandPalette", "LpConfirmDialog", "LpConfirmHost", "LpContextMenu", "LpDatePicker", "LpDateRangePicker", "LpDisclosure", "LpDivider", "LpDrawer", "LpDropdownMenu", "LpDropzone", "LpEmptyState", "LpFieldNotice", "LpFileTree", "LpFormField", "LpHintLayer", "LpHints", "LpIcon", "LpImageEditor", "LpInfraNode", "LpInput", "LpKeys", "LpLightbox", "LpLink", "LpLogViewer", "LpMapPicker", "LpMediaGallery", "LpModal", "LpModalNav", "LpNotificationBell", "LpNumberField", "LpNumberFlow", "LpOtpInput", "LpPagination", "LpPaletteFacts", "LpPaletteHeader", "LpPalettePreview", "LpPaletteStats", "LpPaletteSwatches", "LpPasswordInput", "LpPhoneInput", "LpPie", "LpPopover", "LpProgress", "LpRadio", "LpRadioGroup", "LpRangeCalendar", "LpRangeSlider", "LpRollingText", "LpScrollArea", "LpSection", "LpSegmented", "LpSelect", "LpServiceNode", "LpShift", "LpShortcutsDialog", "LpSidebar", "LpSkeleton", "LpSlider", "LpSparkline", "LpStat", "LpStepper", "LpSwap", "LpSwitch", "LpTable", "LpTableOfContents", "LpTabs", "LpTagsInput", "LpTextarea", "LpThemeProvider", "LpThemeSwitcher", "LpTilt", "LpTimeField", "LpToaster", "LpTooltip", "LpTooltipProvider", "LpTopologyCanvas", "LpTour", "LpUptimeBar", "LpVideoBackdrop"];
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpAddressInput-DD4zTN4P.js";
1
+ import { _ as _sfc_main } from "../chunks/LpAddressInput-CzdZguBo.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpAppShell-Cv-Y9qNA.js";
1
+ import { _ as _sfc_main } from "../chunks/LpAppShell-BXMNDEpF.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -2,6 +2,14 @@ export interface AutocompleteOption {
2
2
  value: string;
3
3
  label?: string;
4
4
  description?: string;
5
+ /** A picture beside the option: an avatar, an icon of a server. */
6
+ image?: string;
7
+ }
8
+ /** What the field's value stands for: a name for an id, with an optional muted hint and picture. */
9
+ export interface AutocompleteSelection {
10
+ label: string;
11
+ hint?: string;
12
+ image?: string;
5
13
  }
6
14
  declare const _default: typeof __VLS_export;
7
15
  export default _default;
@@ -31,6 +39,14 @@ declare const __VLS_export: import("vue").DefineComponent<{
31
39
  pattern?: RegExp | string;
32
40
  /** Allowed-character RegExp; hard-blocks other input (see LpInput). */
33
41
  restrict?: RegExp;
42
+ /**
43
+ * What the current value stands for, shown in the field itself while it is
44
+ * not being edited: a picked id reads as a person (avatar in place of the
45
+ * icon, name, muted hint) instead of digits nobody recognises, and nothing
46
+ * appears or jumps below the field. Focusing it brings the raw text back.
47
+ * When room runs short the hint gives way first; the name stays.
48
+ */
49
+ selected?: AutocompleteSelection | null;
34
50
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
35
51
  select: (value: string) => any;
36
52
  "update:modelValue": (value: string) => any;
@@ -60,6 +76,14 @@ declare const __VLS_export: import("vue").DefineComponent<{
60
76
  pattern?: RegExp | string;
61
77
  /** Allowed-character RegExp; hard-blocks other input (see LpInput). */
62
78
  restrict?: RegExp;
79
+ /**
80
+ * What the current value stands for, shown in the field itself while it is
81
+ * not being edited: a picked id reads as a person (avatar in place of the
82
+ * icon, name, muted hint) instead of digits nobody recognises, and nothing
83
+ * appears or jumps below the field. Focusing it brings the raw text back.
84
+ * When room runs short the hint gives way first; the name stays.
85
+ */
86
+ selected?: AutocompleteSelection | null;
63
87
  }> & Readonly<{
64
88
  onSelect?: ((value: string) => any) | undefined;
65
89
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpAutocomplete-PnL2ntKl.js";
1
+ import { _ as _sfc_main } from "../chunks/LpAutocomplete-D9mY5Tqk.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };