@leavepulse/ui 0.20.9 → 0.22.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 (53) hide show
  1. package/dist/assets/{LpCommandPalette-C3LdDNHk.css → LpCommandPalette-CEY-pajO.css} +4 -4
  2. package/dist/assets/LpShortcutsDialog-B7H-RZLQ.css +55 -0
  3. package/dist/chunks/{LpAddressInput-B411MOJa.js → LpAddressInput-Dah7asXy.js} +1 -1
  4. package/dist/chunks/{LpAppShell-CfM7fdr3.js → LpAppShell-DGZv907S.js} +2 -2
  5. package/dist/chunks/{LpConfirmDialog-D8pBGPOI.js → LpConfirmDialog-CkMzeKdp.js} +1 -1
  6. package/dist/chunks/{LpDrawer-B4cNj39a.js → LpDrawer-DAJN5rGK.js} +1 -1
  7. package/dist/chunks/{LpFileTree-d9nXtSVo.js → LpFileTree-DWx77B1F.js} +1 -1
  8. package/dist/chunks/{LpLogViewer-BXPBUV21.js → LpLogViewer-B1aLUVdz.js} +1 -1
  9. package/dist/chunks/{LpModal-DKFdzKwV.js → LpModal-CNAFRgCU.js} +36 -3
  10. package/dist/chunks/{LpNotificationBell-Nges4kJk.js → LpNotificationBell-HSGo1pcf.js} +1 -1
  11. package/dist/chunks/{LpScrollArea-Du8tW8c5.js → LpScrollArea-D8xyKXcF.js} +10 -2
  12. package/dist/chunks/{LpSidebar-Bd0148dd.js → LpSidebar-JvMaaYsy.js} +2 -2
  13. package/dist/chunks/{LpSidebarNav-BqGpNr4S.js → LpSidebarNav-BIYzk7e_.js} +1 -1
  14. package/dist/chunks/{LpTable-BBKlNR9j.js → LpTable-DTj52qlg.js} +45 -9
  15. package/dist/chunks/{LpTooltip-CIwoRCag.js → LpTooltip-D1hbjQWG.js} +23 -9
  16. package/dist/chunks/_plugin-vue_export-helper-1tPrXgE0.js +10 -0
  17. package/dist/component-names.d.ts +1 -1
  18. package/dist/components/LpAddressInput.vue.js +1 -1
  19. package/dist/components/LpAppShell.vue.js +1 -1
  20. package/dist/components/LpCommandPalette.vue.js +17 -21
  21. package/dist/components/LpConfirmDialog.vue.js +1 -1
  22. package/dist/components/LpDrawer.vue.js +1 -1
  23. package/dist/components/LpFileTree.vue.js +1 -1
  24. package/dist/components/LpLogViewer.vue.js +1 -1
  25. package/dist/components/LpModal.vue.d.ts +16 -5
  26. package/dist/components/LpModal.vue.js +1 -1
  27. package/dist/components/LpNotificationBell.vue.js +1 -1
  28. package/dist/components/LpScrollArea.vue.js +1 -1
  29. package/dist/components/LpShortcutsDialog.vue.d.ts +25 -0
  30. package/dist/components/LpShortcutsDialog.vue.js +63 -0
  31. package/dist/components/LpSidebar.vue.js +1 -1
  32. package/dist/components/LpSidebarNav.vue.js +1 -1
  33. package/dist/components/LpTable.vue.js +1 -1
  34. package/dist/components/LpTooltip.vue.d.ts +19 -1
  35. package/dist/components/LpTooltip.vue.js +1 -1
  36. package/dist/composables/useHotkeys.d.ts +45 -0
  37. package/dist/composables/useHotkeys.js +53 -0
  38. package/dist/composables/useRovingFocus.d.ts +49 -0
  39. package/dist/composables/useRovingFocus.js +160 -0
  40. package/dist/index.d.ts +6 -0
  41. package/dist/index.js +20 -12
  42. package/package.json +1 -1
  43. package/src/component-names.ts +1 -0
  44. package/src/components/LpCommandPalette.vue +18 -11
  45. package/src/components/LpModal.vue +67 -1
  46. package/src/components/LpScrollArea.vue +26 -6
  47. package/src/components/LpShortcutsDialog.vue +127 -0
  48. package/src/components/LpTable.vue +57 -2
  49. package/src/components/LpTooltip.vue +57 -5
  50. package/src/composables/useHotkeys.ts +131 -0
  51. package/src/composables/useRovingFocus.ts +275 -0
  52. package/src/index.ts +6 -0
  53. package/src/tokens/utilities.css +15 -0
@@ -1,16 +1,16 @@
1
1
 
2
2
  /* Each result eases in; honours reduced motion. */
3
- .lp-cmd-item[data-v-75a17488] {
4
- animation: lp-cmd-in-75a17488 140ms ease-out both;
3
+ .lp-cmd-item[data-v-a23a2f5f] {
4
+ animation: lp-cmd-in-a23a2f5f 140ms ease-out both;
5
5
  }
6
- @keyframes lp-cmd-in-75a17488 {
6
+ @keyframes lp-cmd-in-a23a2f5f {
7
7
  from {
8
8
  opacity: 0;
9
9
  transform: translateY(3px);
10
10
  }
11
11
  }
12
12
  @media (prefers-reduced-motion: reduce) {
13
- .lp-cmd-item[data-v-75a17488] {
13
+ .lp-cmd-item[data-v-a23a2f5f] {
14
14
  animation: none;
15
15
  }
16
16
  }
@@ -0,0 +1,55 @@
1
+
2
+ /* Two columns where there is room: the list is long enough that one column
3
+ pushes the last group off a laptop screen. */
4
+ .shortcut-groups[data-v-d86b724b] {
5
+ display: grid;
6
+ gap: 18px;
7
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
8
+ }
9
+ .shortcut-group h3[data-v-d86b724b] {
10
+ margin: 0 0 6px;
11
+ color: var(--color-muted);
12
+ font-size: 0.7rem;
13
+ font-weight: 600;
14
+ letter-spacing: 0.06em;
15
+ text-transform: uppercase;
16
+ }
17
+ .shortcut-group dl[data-v-d86b724b] {
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: 1px;
21
+ margin: 0;
22
+ }
23
+ .shortcut-row[data-v-d86b724b] {
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: space-between;
27
+ gap: 12px;
28
+ padding: 5px 0;
29
+ }
30
+ .shortcut-row dt[data-v-d86b724b] {
31
+ color: var(--color-ink);
32
+ font-size: 0.82rem;
33
+ min-width: 0;
34
+ }
35
+ .shortcut-row dd[data-v-d86b724b] {
36
+ display: flex;
37
+ flex-shrink: 0;
38
+ gap: 3px;
39
+ margin: 0;
40
+ }
41
+ kbd[data-v-d86b724b] {
42
+ display: inline-flex;
43
+ min-width: 20px;
44
+ align-items: center;
45
+ justify-content: center;
46
+ padding: 2px 6px;
47
+ border: 1px solid var(--color-line-strong);
48
+ border-bottom-width: 2px;
49
+ border-radius: 5px;
50
+ background: color-mix(in srgb, var(--color-ink) 6%, transparent);
51
+ color: var(--color-muted-strong);
52
+ font-family: inherit;
53
+ font-size: 0.7rem;
54
+ line-height: 1.5;
55
+ }
@@ -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-DKFdzKwV.js";
9
+ import { _ as _sfc_main$7 } from "./LpModal-CNAFRgCU.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,8 +1,8 @@
1
1
  import { defineComponent, computed, watch, openBlock, createElementBlock, createVNode, createSlots, withCtx, renderSlot, normalizeProps, guardReactiveProps, createElementVNode, normalizeClass, toDisplayString, createCommentVNode, createBlock } from "vue";
2
2
  import { _ as _sfc_main$2 } from "./LpButton-5VXXCjwF.js";
3
3
  import { _ as _sfc_main$3 } from "./LpIcon-CCnX5_2j.js";
4
- import { _ as _sfc_main$4 } from "./LpScrollArea-Du8tW8c5.js";
5
- import { _ as _sfc_main$1 } from "./LpSidebar-Bd0148dd.js";
4
+ import { _ as _sfc_main$4 } from "./LpScrollArea-D8xyKXcF.js";
5
+ import { _ as _sfc_main$1 } from "./LpSidebar-JvMaaYsy.js";
6
6
  const _hoisted_1 = { class: "flex h-dvh overflow-hidden bg-surface text-ink" };
7
7
  const _hoisted_2 = { class: "flex min-w-0 flex-1 flex-col" };
8
8
  const _hoisted_3 = { class: "flex h-16 shrink-0 items-center gap-3 border-b border-line bg-surface px-4 md:px-6" };
@@ -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-DKFdzKwV.js";
3
+ import { _ as _sfc_main$1 } from "./LpModal-CNAFRgCU.js";
4
4
  const _sfc_main = /* @__PURE__ */ defineComponent({
5
5
  __name: "LpConfirmDialog",
6
6
  props: {
@@ -3,7 +3,7 @@ import { usePointerSwipe } from "@vueuse/core";
3
3
  import { DrawerRoot, DrawerPortal, DrawerOverlay, DrawerContent, DrawerHandle, DrawerTitle, DrawerDescription, DrawerClose } from "vaul-vue";
4
4
  import { CLOSE_ICON } from "../components/dropdown.js";
5
5
  import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
6
- import { _ as _sfc_main$2 } from "./LpScrollArea-Du8tW8c5.js";
6
+ import { _ as _sfc_main$2 } from "./LpScrollArea-D8xyKXcF.js";
7
7
  const _hoisted_1 = { class: "text-base font-semibold text-ink" };
8
8
  const _hoisted_2 = { class: "flex flex-col gap-1" };
9
9
  const _hoisted_3 = ["data-vaul-no-drag"];
@@ -2,7 +2,7 @@ import { defineComponent, ref, watch, computed, openBlock, createElementBlock, F
2
2
  import { formatSize, sortNodes, computeStats, subtreeIds, ancestorIds } from "../components/fileTree.js";
3
3
  import { _ as _sfc_main$1 } from "./LpEmptyState-CrfyRJUG.js";
4
4
  import { _ as _sfc_main$3 } from "./LpFileTreeNode-DFg4PhOK.js";
5
- import { _ as _sfc_main$2 } from "./LpScrollArea-Du8tW8c5.js";
5
+ import { _ as _sfc_main$2 } from "./LpScrollArea-D8xyKXcF.js";
6
6
  const _hoisted_1 = {
7
7
  key: 0,
8
8
  class: "flex h-full w-full min-w-0 flex-col gap-1 overflow-hidden"
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, computed, ref, watch, nextTick, onMounted, onBeforeUnmount, openBlock, createElementBlock, createVNode, normalizeStyle, withCtx, createElementVNode, toDisplayString, createCommentVNode, Fragment, createBlock, resolveDynamicComponent, TransitionGroup, mergeProps, renderList, normalizeClass, createTextVNode, Transition } from "vue";
2
2
  import { _ as _sfc_main$3 } from "./LpContextMenu-D0mzXqA7.js";
3
3
  import { _ as _sfc_main$2 } from "./LpIcon-CCnX5_2j.js";
4
- import { _ as _sfc_main$1 } from "./LpScrollArea-Du8tW8c5.js";
4
+ import { _ as _sfc_main$1 } from "./LpScrollArea-D8xyKXcF.js";
5
5
  const _hoisted_1 = { class: "relative overflow-hidden rounded-card border border-line bg-surface font-mono text-xs leading-relaxed" };
6
6
  const _hoisted_2 = {
7
7
  key: 0,
@@ -2,7 +2,7 @@ import { defineComponent, computed, useSlots, ref, watch, onBeforeUnmount, openB
2
2
  import { DialogRoot, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription, DialogClose } from "reka-ui";
3
3
  import { CLOSE_ICON } from "../components/dropdown.js";
4
4
  import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
5
- import { _ as _sfc_main$2 } from "./LpScrollArea-Du8tW8c5.js";
5
+ import { _ as _sfc_main$2 } from "./LpScrollArea-D8xyKXcF.js";
6
6
  const _hoisted_1 = { class: "fixed inset-0 z-(--z-modal) flex items-center justify-center pointer-events-none" };
7
7
  const _hoisted_2 = {
8
8
  key: 0,
@@ -22,7 +22,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
22
22
  description: {},
23
23
  size: { default: "md" },
24
24
  width: {},
25
- fillBody: { type: Boolean }
25
+ fillBody: { type: Boolean },
26
+ autoFocus: { default: "auto" }
26
27
  },
27
28
  emits: ["update:open"],
28
29
  setup(__props) {
@@ -51,6 +52,37 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
51
52
  ].filter(Boolean).join(" ")
52
53
  );
53
54
  const panelRef = ref(null);
55
+ const AUTO_FOCUS_ORDER = [
56
+ "input:not([type=hidden]):not([disabled]):not([readonly])",
57
+ "textarea:not([disabled]):not([readonly])",
58
+ "select:not([disabled])",
59
+ "[data-lp-autofocus]",
60
+ "button:not([disabled]):not([data-lp-dialog-close])",
61
+ "[href]",
62
+ "[tabindex]:not([tabindex='-1'])"
63
+ ];
64
+ function onOpenAutoFocus(event) {
65
+ if (props.autoFocus === "none") return;
66
+ const panel = panelRef.value?.$el;
67
+ if (!(panel instanceof HTMLElement)) return;
68
+ const selectors = props.autoFocus === "auto" ? AUTO_FOCUS_ORDER : [props.autoFocus];
69
+ for (const selector of selectors) {
70
+ const target = panel.querySelector(selector);
71
+ if (!target || target.hasAttribute("disabled")) continue;
72
+ event.preventDefault();
73
+ target.setAttribute("data-lp-focus-ring", "");
74
+ target.addEventListener(
75
+ "blur",
76
+ () => target.removeAttribute("data-lp-focus-ring"),
77
+ { once: true }
78
+ );
79
+ target.focus();
80
+ if (target instanceof HTMLInputElement && target.type === "text") {
81
+ target.select();
82
+ }
83
+ return;
84
+ }
85
+ }
54
86
  const tweening = ref(false);
55
87
  const resizing = ref(false);
56
88
  let ro;
@@ -142,7 +174,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
142
174
  ref: panelRef,
143
175
  class: ["pointer-events-auto flex max-h-[min(90vh,calc(100dvh-2rem))] min-h-0 flex-col overflow-hidden rounded-card border border-line bg-surface-raised shadow-panel outline-none data-[state=open]:animate-[rise-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[rise-out_120ms_cubic-bezier(0.4,0,1,1)]", [widthClass.value, tweening.value ? "transition-[height] duration-fast ease-[var(--ease-emphasized)] motion-reduce:transition-none" : ""]],
144
176
  style: __props.width ? { width: __props.width } : void 0
145
- }, describedByAttrs.value), {
177
+ }, describedByAttrs.value, { onOpenAutoFocus }), {
146
178
  default: withCtx(() => [
147
179
  __props.title || _ctx.$slots.title ? (openBlock(), createElementBlock("header", _hoisted_2, [
148
180
  createElementVNode("div", _hoisted_3, [
@@ -165,6 +197,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
165
197
  })) : createCommentVNode("", true)
166
198
  ]),
167
199
  createVNode(unref(DialogClose), {
200
+ "data-lp-dialog-close": "",
168
201
  class: "group flex shrink-0 items-center rounded-md p-1 text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring",
169
202
  "aria-label": "Close"
170
203
  }, {
@@ -5,7 +5,7 @@ import { _ as _sfc_main$4 } from "./LpContextMenu-D0mzXqA7.js";
5
5
  import { _ as _sfc_main$2 } from "./LpEmptyState-CrfyRJUG.js";
6
6
  import { _ as _sfc_main$5 } from "./LpIcon-CCnX5_2j.js";
7
7
  import { _ as _sfc_main$1 } from "./LpPopover-8268UmlC.js";
8
- import { _ as _sfc_main$3 } from "./LpScrollArea-Du8tW8c5.js";
8
+ import { _ as _sfc_main$3 } from "./LpScrollArea-D8xyKXcF.js";
9
9
  const _hoisted_1 = { class: "flex items-center justify-between gap-2 px-3 py-2.5" };
10
10
  const _hoisted_2 = { class: "text-sm font-semibold" };
11
11
  const _hoisted_3 = {
@@ -31,6 +31,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
31
31
  atTop.value = el.scrollTop <= 1;
32
32
  atBottom.value = el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
33
33
  }
34
+ function syncViewportFocusable(el) {
35
+ const scrollable = el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;
36
+ if (scrollable) el.setAttribute("tabindex", "0");
37
+ else el.removeAttribute("tabindex");
38
+ }
34
39
  function onViewportScroll(event) {
35
40
  if (props.fade) measureEdges(event.target);
36
41
  emit("scroll", event);
@@ -47,8 +52,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
47
52
  [viewportEl, () => props.fade],
48
53
  ([el, enabled]) => {
49
54
  stopEdgeWatch();
50
- if (!el || !enabled) return;
51
- const remeasure = () => measureEdges(el);
55
+ if (!el) return;
56
+ const remeasure = () => {
57
+ if (enabled) measureEdges(el);
58
+ syncViewportFocusable(el);
59
+ };
52
60
  remeasure();
53
61
  if (typeof ResizeObserver !== "undefined") {
54
62
  edgeResize = new ResizeObserver(remeasure);
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, computed, useId, openBlock, createElementBlock, Fragment, createElementVNode, mergeProps, normalizeClass, renderSlot, createCommentVNode, createVNode, createSlots, withCtx, normalizeProps, guardReactiveProps, createBlock } from "vue";
2
- import { _ as _sfc_main$2 } from "./LpDrawer-B4cNj39a.js";
3
- import { _ as _sfc_main$1 } from "./LpSidebarNav-BqGpNr4S.js";
2
+ import { _ as _sfc_main$2 } from "./LpDrawer-DAJN5rGK.js";
3
+ import { _ as _sfc_main$1 } from "./LpSidebarNav-BIYzk7e_.js";
4
4
  const _hoisted_1 = {
5
5
  key: 1,
6
6
  class: "mt-2 flex shrink-0 flex-col gap-2"
@@ -4,7 +4,7 @@ import { usePillTransition } from "../composables/usePillTransition.js";
4
4
  import { _ as _sfc_main$4 } from "./LpBadge-CXzBPnwO.js";
5
5
  import { _ as _sfc_main$2 } from "./LpContextMenu-D0mzXqA7.js";
6
6
  import { _ as _sfc_main$3 } from "./LpIcon-CCnX5_2j.js";
7
- import { _ as _sfc_main$1 } from "./LpScrollArea-Du8tW8c5.js";
7
+ import { _ as _sfc_main$1 } from "./LpScrollArea-D8xyKXcF.js";
8
8
  const _hoisted_1 = {
9
9
  key: 0,
10
10
  class: "flex min-h-0 flex-1 flex-col gap-4"
@@ -1,8 +1,9 @@
1
- import { defineComponent, computed, ref, watch, onBeforeUnmount, openBlock, createBlock, withCtx, createElementVNode, normalizeClass, createElementBlock, createVNode, createCommentVNode, Fragment, renderList, normalizeStyle, createTextVNode, toDisplayString, withModifiers, renderSlot } from "vue";
1
+ import { defineComponent, computed, ref, watch, onBeforeUnmount, openBlock, createBlock, withCtx, createElementVNode, normalizeClass, createElementBlock, createVNode, createCommentVNode, Fragment, renderList, normalizeStyle, createTextVNode, toDisplayString, unref, mergeProps, withModifiers, renderSlot } from "vue";
2
2
  import { _ as _sfc_main$2 } from "./LpCheckbox-BO0zuuPh.js";
3
3
  import { _ as _sfc_main$4 } from "./LpContextMenu-D0mzXqA7.js";
4
4
  import { _ as _sfc_main$3 } from "./LpIcon-CCnX5_2j.js";
5
- import { _ as _sfc_main$1 } from "./LpScrollArea-Du8tW8c5.js";
5
+ import { _ as _sfc_main$1 } from "./LpScrollArea-D8xyKXcF.js";
6
+ import { useRovingFocus } from "../composables/useRovingFocus.js";
6
7
  const _hoisted_1 = { class: "w-full border-collapse text-sm" };
7
8
  const _hoisted_2 = { class: "border-b border-line bg-surface-soft" };
8
9
  const _hoisted_3 = {
@@ -91,6 +92,37 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
91
92
  emit("update:selected", [...next]);
92
93
  }
93
94
  const colSpan = computed(() => props.columns.length + (props.selectable ? 1 : 0));
95
+ const rovingItems = computed(
96
+ () => displayRows.value.map((row, index) => ({
97
+ id: String(keyFor(row, index)),
98
+ label: String(row[props.columns[0]?.key ?? ""] ?? "")
99
+ }))
100
+ );
101
+ const rowByKey = computed(() => {
102
+ const map = /* @__PURE__ */ new Map();
103
+ displayRows.value.forEach((row, index) => map.set(String(keyFor(row, index)), row));
104
+ return map;
105
+ });
106
+ const roving = useRovingFocus(rovingItems, {
107
+ onActivate: (id) => {
108
+ const row = rowByKey.value.get(id);
109
+ if (!row) return;
110
+ emit("rowClick", row);
111
+ }
112
+ });
113
+ function onRowKeydown(event) {
114
+ if (event.key === " " && props.selectable && roving.activeId.value) {
115
+ event.preventDefault();
116
+ const key = roving.activeId.value;
117
+ const row = rowByKey.value.get(key);
118
+ if (row) {
119
+ const rowKey = keyFor(row, displayRows.value.indexOf(row));
120
+ toggleRow(rowKey, !selectedSet.value.has(rowKey));
121
+ }
122
+ return;
123
+ }
124
+ roving.onKeydown(event);
125
+ }
94
126
  const headEl = ref(null);
95
127
  const headHeight = ref(0);
96
128
  let ro;
@@ -164,7 +196,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
164
196
  }), 128))
165
197
  ])
166
198
  ], 2),
167
- createElementVNode("tbody", null, [
199
+ createElementVNode("tbody", {
200
+ ref: (el) => unref(roving).setContainer(el)
201
+ }, [
168
202
  displayRows.value.length === 0 ? (openBlock(), createElementBlock("tr", _hoisted_6, [
169
203
  createElementVNode("td", {
170
204
  colspan: colSpan.value,
@@ -184,10 +218,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
184
218
  items: menuFor(row)
185
219
  }, {
186
220
  default: withCtx(() => [
187
- createElementVNode("tr", {
188
- class: normalizeClass(["border-b border-line/60 transition-colors last:border-0 hover:bg-surface-soft/60", selectedSet.value.has(keyFor(row, index)) ? "bg-brand-soft/40" : ""]),
189
- onClick: ($event) => emit("rowClick", row)
190
- }, [
221
+ createElementVNode("tr", mergeProps({
222
+ class: ["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" : ""]
223
+ }, { ref_for: true }, unref(roving).itemProps(String(keyFor(row, index))), {
224
+ onClick: ($event) => emit("rowClick", row),
225
+ onKeydown: onRowKeydown
226
+ }), [
191
227
  __props.selectable ? (openBlock(), createElementBlock("td", {
192
228
  key: 0,
193
229
  class: "w-px px-4 py-3",
@@ -212,12 +248,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
212
248
  ])
213
249
  ], 2);
214
250
  }), 128))
215
- ], 10, _hoisted_8)
251
+ ], 16, _hoisted_8)
216
252
  ]),
217
253
  _: 2
218
254
  }, 1032, ["items"]);
219
255
  }), 128))
220
- ])
256
+ ], 512)
221
257
  ])
222
258
  ]),
223
259
  _: 3
@@ -5,25 +5,39 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
5
5
  __name: "LpTooltip",
6
6
  props: {
7
7
  content: {},
8
- sideOffset: {}
8
+ sideOffset: {},
9
+ side: { default: "top" },
10
+ label: { type: Boolean },
11
+ delay: { default: 200 },
12
+ showOnPointerFocus: { type: Boolean }
9
13
  },
10
14
  setup(__props) {
11
15
  return (_ctx, _cache) => {
12
- return openBlock(), createBlock(unref(TooltipProvider), { "delay-duration": 200 }, {
16
+ return openBlock(), createBlock(unref(TooltipProvider), { "delay-duration": __props.delay }, {
13
17
  default: withCtx(() => [
14
- createVNode(unref(TooltipRoot), null, {
18
+ createVNode(unref(TooltipRoot), {
19
+ "ignore-non-keyboard-focus": !__props.showOnPointerFocus
20
+ }, {
15
21
  default: withCtx(() => [
16
- createVNode(unref(TooltipTrigger), { "as-child": "" }, {
22
+ createVNode(unref(TooltipTrigger), {
23
+ "as-child": "",
24
+ "aria-label": __props.label ? __props.content : void 0
25
+ }, {
17
26
  default: withCtx(() => [
18
27
  renderSlot(_ctx.$slots, "default")
19
28
  ]),
20
29
  _: 3
21
- }),
30
+ }, 8, ["aria-label"]),
22
31
  createVNode(unref(TooltipPortal), null, {
23
32
  default: withCtx(() => [
24
33
  createVNode(unref(TooltipContent), {
34
+ side: __props.side,
25
35
  "side-offset": __props.sideOffset ?? 6,
26
- class: normalizeClass([unref(PANEL_SURFACE), unref(TOOLTIP_ANIM), "z-(--z-tooltip) px-2.5 py-1.5 text-xs text-ink"])
36
+ class: normalizeClass([
37
+ unref(PANEL_SURFACE),
38
+ unref(TOOLTIP_ANIM),
39
+ "z-(--z-tooltip) max-w-[min(20rem,90vw)] px-2.5 py-1.5 text-xs text-ink"
40
+ ])
27
41
  }, {
28
42
  default: withCtx(() => [
29
43
  renderSlot(_ctx.$slots, "content", {}, () => [
@@ -31,16 +45,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
31
45
  ])
32
46
  ]),
33
47
  _: 3
34
- }, 8, ["side-offset", "class"])
48
+ }, 8, ["side", "side-offset", "class"])
35
49
  ]),
36
50
  _: 3
37
51
  })
38
52
  ]),
39
53
  _: 3
40
- })
54
+ }, 8, ["ignore-non-keyboard-focus"])
41
55
  ]),
42
56
  _: 3
43
- });
57
+ }, 8, ["delay-duration"]);
44
58
  };
45
59
  }
46
60
  });
@@ -0,0 +1,10 @@
1
+ const _export_sfc = (sfc, props) => {
2
+ const target = sfc.__vccOpts || sfc;
3
+ for (const [key, val] of props) {
4
+ target[key] = val;
5
+ }
6
+ return target;
7
+ };
8
+ export {
9
+ _export_sfc as _
10
+ };
@@ -1 +1 @@
1
- export declare const COMPONENT_NAMES: readonly ["LayoutCanvas", "LayoutNode", "LpAddressInput", "LpAlert", "LpAppShell", "LpAutocomplete", "LpAvatar", "LpBadge", "LpBreadcrumbs", "LpButton", "LpCalendar", "LpCard", "LpCheckbox", "LpCodeBlock", "LpCommandPalette", "LpConfirmDialog", "LpContextMenu", "LpDatePicker", "LpDisclosure", "LpDivider", "LpDrawer", "LpDropdownMenu", "LpEmptyState", "LpFileTree", "LpFileTreeNode", "LpFormField", "LpIcon", "LpInfraNode", "LpInput", "LpLaneNode", "LpLightbox", "LpLink", "LpLogViewer", "LpMapPicker", "LpModal", "LpNotificationBell", "LpNumberField", "LpOtpInput", "LpPagination", "LpPasswordInput", "LpPhoneInput", "LpPopover", "LpProgress", "LpRadio", "LpRadioGroup", "LpScrollArea", "LpSegmented", "LpSelect", "LpServiceNode", "LpSidebar", "LpSidebarNav", "LpSkeleton", "LpSlider", "LpStat", "LpStepper", "LpSwitch", "LpTable", "LpTableOfContents", "LpTabs", "LpTextarea", "LpThemeSwitcher", "LpTilt", "LpToaster", "LpTooltip", "LpTopologyCanvas", "LpUptimeBar"];
1
+ export declare const COMPONENT_NAMES: readonly ["LayoutCanvas", "LayoutNode", "LpAddressInput", "LpAlert", "LpAppShell", "LpAutocomplete", "LpAvatar", "LpBadge", "LpBreadcrumbs", "LpButton", "LpCalendar", "LpCard", "LpCheckbox", "LpCodeBlock", "LpCommandPalette", "LpConfirmDialog", "LpContextMenu", "LpDatePicker", "LpDisclosure", "LpDivider", "LpDrawer", "LpDropdownMenu", "LpEmptyState", "LpFileTree", "LpFileTreeNode", "LpFormField", "LpIcon", "LpInfraNode", "LpInput", "LpLaneNode", "LpLightbox", "LpLink", "LpLogViewer", "LpMapPicker", "LpModal", "LpNotificationBell", "LpNumberField", "LpOtpInput", "LpPagination", "LpPasswordInput", "LpPhoneInput", "LpPopover", "LpProgress", "LpRadio", "LpRadioGroup", "LpScrollArea", "LpSegmented", "LpSelect", "LpServiceNode", "LpShortcutsDialog", "LpSidebar", "LpSidebarNav", "LpSkeleton", "LpSlider", "LpStat", "LpStepper", "LpSwitch", "LpTable", "LpTableOfContents", "LpTabs", "LpTextarea", "LpThemeSwitcher", "LpTilt", "LpToaster", "LpTooltip", "LpTopologyCanvas", "LpUptimeBar"];
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpAddressInput-B411MOJa.js";
1
+ import { _ as _sfc_main } from "../chunks/LpAddressInput-Dah7asXy.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpAppShell-CfM7fdr3.js";
1
+ import { _ as _sfc_main } from "../chunks/LpAppShell-DGZv907S.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,8 +1,10 @@
1
- import { defineComponent, ref, computed, watch, nextTick, onMounted, onBeforeUnmount, openBlock, createBlock, unref, withCtx, createVNode, withModifiers, createTextVNode, createElementVNode, withDirectives, withKeys, vModelText, createElementBlock, toDisplayString, createCommentVNode, Fragment, renderList, normalizeClass } from "vue";
1
+ import { defineComponent, ref, computed, watch, nextTick, openBlock, createBlock, unref, withCtx, createVNode, withModifiers, createTextVNode, createElementVNode, withDirectives, withKeys, vModelText, createElementBlock, toDisplayString, createCommentVNode, Fragment, renderList, normalizeClass } from "vue";
2
2
  import { DialogRoot, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription } from "reka-ui";
3
3
  import { _ as _sfc_main$1 } from "../chunks/LpIcon-CCnX5_2j.js";
4
- import { _ as _sfc_main$2 } from "../chunks/LpScrollArea-Du8tW8c5.js";
5
- import '../assets/LpCommandPalette-C3LdDNHk.css';const _hoisted_1 = { class: "flex shrink-0 items-center gap-2.5 border-b border-line px-4" };
4
+ import { _ as _sfc_main$2 } from "../chunks/LpScrollArea-D8xyKXcF.js";
5
+ import { useHotkeys } from "../composables/useHotkeys.js";
6
+ import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
7
+ import '../assets/LpCommandPalette-CEY-pajO.css';const _hoisted_1 = { class: "flex shrink-0 items-center gap-2.5 border-b border-line px-4" };
6
8
  const _hoisted_2 = ["placeholder", "onKeydown"];
7
9
  const _hoisted_3 = {
8
10
  key: 0,
@@ -149,16 +151,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
149
151
  }
150
152
  }
151
153
  );
152
- function onHotkey(e) {
153
- if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
154
- e.preventDefault();
155
- emit("update:open", !props.open);
156
- }
157
- }
158
- onMounted(() => {
159
- if (props.hotkey) window.addEventListener("keydown", onHotkey);
160
- });
161
- onBeforeUnmount(() => window.removeEventListener("keydown", onHotkey));
154
+ useHotkeys(
155
+ () => props.hotkey ? [
156
+ {
157
+ key: "k",
158
+ code: "KeyK",
159
+ ctrl: true,
160
+ allowInInput: true,
161
+ handler: () => emit("update:open", !props.open)
162
+ }
163
+ ] : []
164
+ );
162
165
  return (_ctx, _cache) => {
163
166
  return openBlock(), createBlock(unref(DialogRoot), {
164
167
  open: __props.open,
@@ -297,14 +300,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
297
300
  };
298
301
  }
299
302
  });
300
- const _export_sfc = (sfc, props) => {
301
- const target = sfc.__vccOpts || sfc;
302
- for (const [key, val] of props) {
303
- target[key] = val;
304
- }
305
- return target;
306
- };
307
- const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-75a17488"]]);
303
+ const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-a23a2f5f"]]);
308
304
  export {
309
305
  LpCommandPalette as default
310
306
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpConfirmDialog-D8pBGPOI.js";
1
+ import { _ as _sfc_main } from "../chunks/LpConfirmDialog-CkMzeKdp.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpDrawer-B4cNj39a.js";
1
+ import { _ as _sfc_main } from "../chunks/LpDrawer-DAJN5rGK.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpFileTree-d9nXtSVo.js";
1
+ import { _ as _sfc_main } from "../chunks/LpFileTree-DWx77B1F.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpLogViewer-BXPBUV21.js";
1
+ import { _ as _sfc_main } from "../chunks/LpLogViewer-B1aLUVdz.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -15,16 +15,26 @@ type __VLS_Props = {
15
15
  * regions (e.g. multi-pane catalogues) — the panes scroll, not the modal.
16
16
  */
17
17
  fillBody?: boolean;
18
+ /**
19
+ * Where the keyboard lands when the dialog opens. Default `"auto"` picks
20
+ * the first meaningful control in the body — a field to type in, or failing
21
+ * that the primary action — instead of the close button, which is what
22
+ * happens if the DOM order is left to decide.
23
+ *
24
+ * `"none"` leaves reka's own behaviour alone; pass a CSS selector to name
25
+ * the element yourself.
26
+ */
27
+ autoFocus?: "auto" | "none" | string;
18
28
  };
19
- declare var __VLS_35: {}, __VLS_54: {}, __VLS_62: {}, __VLS_64: {};
29
+ declare var __VLS_37: {}, __VLS_56: {}, __VLS_64: {}, __VLS_66: {};
20
30
  type __VLS_Slots = {} & {
21
- title?: (props: typeof __VLS_35) => any;
31
+ title?: (props: typeof __VLS_37) => any;
22
32
  } & {
23
- default?: (props: typeof __VLS_54) => any;
33
+ default?: (props: typeof __VLS_56) => any;
24
34
  } & {
25
- default?: (props: typeof __VLS_62) => any;
35
+ default?: (props: typeof __VLS_64) => any;
26
36
  } & {
27
- footer?: (props: typeof __VLS_64) => any;
37
+ footer?: (props: typeof __VLS_66) => any;
28
38
  };
29
39
  declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
30
40
  "update:open": (value: boolean) => any;
@@ -32,6 +42,7 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {},
32
42
  "onUpdate:open"?: ((value: boolean) => any) | undefined;
33
43
  }>, {
34
44
  size: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "full";
45
+ autoFocus: "auto" | "none" | string;
35
46
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
36
47
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
37
48
  declare const _default: typeof __VLS_export;
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpModal-DKFdzKwV.js";
1
+ import { _ as _sfc_main } from "../chunks/LpModal-CNAFRgCU.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpNotificationBell-Nges4kJk.js";
1
+ import { _ as _sfc_main } from "../chunks/LpNotificationBell-HSGo1pcf.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpScrollArea-Du8tW8c5.js";
1
+ import { _ as _sfc_main } from "../chunks/LpScrollArea-D8xyKXcF.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -0,0 +1,25 @@
1
+ export interface ShortcutEntry {
2
+ /** Rendered one <kbd> per "+"-separated key, so write it the way it reads. */
3
+ combo: string;
4
+ label: string;
5
+ }
6
+ export interface ShortcutGroup {
7
+ title: string;
8
+ entries: ShortcutEntry[];
9
+ }
10
+ type __VLS_Props = {
11
+ open?: boolean;
12
+ groups: ShortcutGroup[];
13
+ title?: string;
14
+ description?: string;
15
+ };
16
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
17
+ "update:open": (value: boolean) => any;
18
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
19
+ "onUpdate:open"?: ((value: boolean) => any) | undefined;
20
+ }>, {
21
+ title: string;
22
+ open: boolean;
23
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
24
+ declare const _default: typeof __VLS_export;
25
+ export default _default;