@leavepulse/ui 0.22.21 → 0.23.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.
- package/dist/chunks/{LpAddressInput-CxKwIG6T.js → LpAddressInput-BTqnUXZG.js} +3 -3
- package/dist/chunks/{LpAppShell-D8CAP9oF.js → LpAppShell-CaQYQKZV.js} +25 -14
- package/dist/chunks/{LpAvatar-B1Ez0ZAx.js → LpAvatar-D-jHoHR7.js} +15 -5
- package/dist/chunks/{LpConfirmDialog-CmgeAdCh.js → LpConfirmDialog-CObRah9c.js} +11 -6
- package/dist/chunks/{LpFileTree-Cw50eG_y.js → LpFileTree-CN0IOIY7.js} +1 -1
- package/dist/chunks/{LpFileTreeNode-DFg4PhOK.js → LpFileTreeNode-D7WgUPcJ.js} +23 -21
- package/dist/chunks/{LpFormField-Bn-ZwC6z.js → LpFormField-CesaPWPO.js} +12 -6
- package/dist/chunks/{LpInput-BkomKdqQ.js → LpInput-jwqXlAy0.js} +6 -3
- package/dist/chunks/{LpLink-DHwOEp4e.js → LpLink-DU9kkKGW.js} +25 -10
- package/dist/chunks/{LpModal-CNNSf5pv.js → LpModal-D_o-56To.js} +13 -76
- package/dist/chunks/{LpNotificationBell-DWDEkmdA.js → LpNotificationBell-a08cl0yY.js} +67 -61
- package/dist/chunks/{LpPasswordInput-DgUC2Ur7.js → LpPasswordInput-Bmo6q9Kd.js} +11 -3
- package/dist/chunks/LpShift-DXNsauQZ.js +40 -0
- package/dist/chunks/{LpTextarea-CRAkhemZ.js → LpTextarea-1ENb3ZAO.js} +7 -4
- package/dist/chunks/{LpThemeSwitcher-B_kj0T2b.js → LpThemeSwitcher-BgpJgrnP.js} +27 -0
- package/dist/component-names.d.ts +1 -1
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAppShell.vue.d.ts +6 -6
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAvatar.vue.d.ts +10 -0
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpConfirmDialog.vue.d.ts +8 -0
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpInput.vue.d.ts +12 -0
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpLink.vue.d.ts +20 -2
- package/dist/components/LpLink.vue.js +1 -1
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpPasswordInput.vue.d.ts +8 -0
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpShift.vue.d.ts +36 -0
- package/dist/components/LpShift.vue.js +4 -0
- package/dist/components/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpTextarea.vue.d.ts +5 -0
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/composables/useShift.d.ts +35 -0
- package/dist/composables/useShift.js +112 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +48 -44
- package/dist/theme/tokens.d.ts +3 -0
- package/package.json +1 -1
- package/src/component-names.ts +1 -0
- package/src/components/LpAppShell.vue +27 -7
- package/src/components/LpAvatar.vue +17 -5
- package/src/components/LpConfirmDialog.vue +21 -6
- package/src/components/LpFileTreeNode.vue +11 -2
- package/src/components/LpFormField.vue +19 -2
- package/src/components/LpInput.vue +8 -0
- package/src/components/LpLink.vue +40 -8
- package/src/components/LpModal.vue +20 -128
- package/src/components/LpNotificationBell.vue +48 -42
- package/src/components/LpPasswordInput.vue +16 -1
- package/src/components/LpShift.vue +90 -0
- package/src/components/LpTextarea.vue +7 -0
- package/src/composables/useShift.ts +236 -0
- package/src/index.ts +3 -0
- package/src/theme/presets.ts +24 -0
- package/src/theme/tokens.ts +6 -0
- package/src/tokens/tokens.css +3 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ShiftAxis } from '../composables/useShift';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
/**
|
|
4
|
+
* Which dimension eases. `"width"` for a row that gains/loses controls,
|
|
5
|
+
* `"height"` for a stack whose content grows, `"both"` when either can.
|
|
6
|
+
*/
|
|
7
|
+
axis?: ShiftAxis;
|
|
8
|
+
/** Tween length in ms. Defaults to the kit's `--duration-fast`. */
|
|
9
|
+
duration?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Turn the easing off entirely — the wrapper stays, the box resizes
|
|
12
|
+
* instantly. For a box that is being driven by something else (a drag, a
|
|
13
|
+
* canvas), where a tween would fight the thing already animating it.
|
|
14
|
+
*/
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
};
|
|
17
|
+
declare var __VLS_1: {
|
|
18
|
+
resizing: boolean;
|
|
19
|
+
};
|
|
20
|
+
type __VLS_Slots = {} & {
|
|
21
|
+
default?: (props: typeof __VLS_1) => any;
|
|
22
|
+
};
|
|
23
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
|
|
24
|
+
resizing: import('vue').Ref<boolean, boolean>;
|
|
25
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
26
|
+
disabled: boolean;
|
|
27
|
+
axis: ShiftAxis;
|
|
28
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
29
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
32
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
33
|
+
new (): {
|
|
34
|
+
$slots: S;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -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-
|
|
2
|
+
import { _ as _sfc_main$1 } from "../chunks/LpModal-D_o-56To.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" };
|
|
@@ -7,6 +7,11 @@ type __VLS_Props = {
|
|
|
7
7
|
label?: string;
|
|
8
8
|
hint?: string;
|
|
9
9
|
error?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Marks the label with the required indicator; the attribute still reaches
|
|
12
|
+
* the <textarea> for native validation.
|
|
13
|
+
*/
|
|
14
|
+
required?: boolean;
|
|
10
15
|
};
|
|
11
16
|
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
12
17
|
"update:modelValue": (value: string) => any;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MaybeRefOrGetter, Ref } from 'vue';
|
|
2
|
+
export type ShiftAxis = "height" | "width" | "both";
|
|
3
|
+
export interface UseShiftOptions {
|
|
4
|
+
/** Which dimension is content-derived. Default `"height"`. */
|
|
5
|
+
axis?: MaybeRefOrGetter<ShiftAxis | undefined>;
|
|
6
|
+
/** Tween length. Defaults to the kit's `--duration-fast` (160ms). */
|
|
7
|
+
duration?: MaybeRefOrGetter<number | undefined>;
|
|
8
|
+
/**
|
|
9
|
+
* Gate: while falsy the element is left entirely alone — no observers, no
|
|
10
|
+
* pinning. Use it for a box that only exists while something is open, so a
|
|
11
|
+
* remounted element starts measuring from scratch rather than easing in from
|
|
12
|
+
* a size it held in a previous life. Default: always active.
|
|
13
|
+
*/
|
|
14
|
+
enabled?: MaybeRefOrGetter<unknown>;
|
|
15
|
+
}
|
|
16
|
+
export interface UseShift {
|
|
17
|
+
/** Attach to the element whose content-derived size should ease. */
|
|
18
|
+
el: Ref<HTMLElement | null>;
|
|
19
|
+
/**
|
|
20
|
+
* True while a tween owns the size. Bind the transition utilities off this,
|
|
21
|
+
* so the element is only transition-enabled once it has a size to ease FROM
|
|
22
|
+
* (otherwise the very first pin animates in from zero).
|
|
23
|
+
*/
|
|
24
|
+
tweening: Ref<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* True while the element is still catching up to its new size. During the
|
|
27
|
+
* tween the box is briefly smaller than the content it already holds, so any
|
|
28
|
+
* scroll region inside it would raise a bar for an overflow that resolves
|
|
29
|
+
* itself as the tween lands — hide the bar (not the scrolling) on this.
|
|
30
|
+
*/
|
|
31
|
+
resizing: Ref<boolean>;
|
|
32
|
+
/** Re-measure and ease to the current natural size. Rarely needed by hand. */
|
|
33
|
+
retune: () => void;
|
|
34
|
+
}
|
|
35
|
+
export declare function useShift(options?: UseShiftOptions): UseShift;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ref, watch, toValue, onBeforeUnmount } from "vue";
|
|
2
|
+
const TWEEN_MS = 160;
|
|
3
|
+
function useShift(options = {}) {
|
|
4
|
+
const el = ref(null);
|
|
5
|
+
const tweening = ref(false);
|
|
6
|
+
const resizing = ref(false);
|
|
7
|
+
let ro;
|
|
8
|
+
let mo;
|
|
9
|
+
let raf = 0;
|
|
10
|
+
let settleTimer;
|
|
11
|
+
let lastHeight = 0;
|
|
12
|
+
let lastWidth = 0;
|
|
13
|
+
let inFlight = false;
|
|
14
|
+
const axisOf = () => toValue(options.axis) ?? "height";
|
|
15
|
+
const wantsHeight = () => axisOf() !== "width";
|
|
16
|
+
const wantsWidth = () => axisOf() !== "height";
|
|
17
|
+
function reducedMotion() {
|
|
18
|
+
return typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
19
|
+
}
|
|
20
|
+
function retune() {
|
|
21
|
+
const node = el.value;
|
|
22
|
+
if (!node) return;
|
|
23
|
+
if (inFlight) return;
|
|
24
|
+
const fromHeight = lastHeight;
|
|
25
|
+
const fromWidth = lastWidth;
|
|
26
|
+
if (wantsHeight()) {
|
|
27
|
+
node.style.height = "";
|
|
28
|
+
node.style.maxHeight = "none";
|
|
29
|
+
}
|
|
30
|
+
if (wantsWidth()) {
|
|
31
|
+
node.style.width = "";
|
|
32
|
+
node.style.maxWidth = "none";
|
|
33
|
+
}
|
|
34
|
+
const toHeight = wantsHeight() ? node.offsetHeight : 0;
|
|
35
|
+
const toWidth = wantsWidth() ? node.offsetWidth : 0;
|
|
36
|
+
if (wantsHeight()) node.style.maxHeight = "";
|
|
37
|
+
if (wantsWidth()) node.style.maxWidth = "";
|
|
38
|
+
lastHeight = toHeight;
|
|
39
|
+
lastWidth = toWidth;
|
|
40
|
+
const movesHeight = wantsHeight() && fromHeight !== 0 && toHeight !== fromHeight;
|
|
41
|
+
const movesWidth = wantsWidth() && fromWidth !== 0 && toWidth !== fromWidth;
|
|
42
|
+
if (!movesHeight && !movesWidth) return;
|
|
43
|
+
if (movesHeight) node.style.height = `${fromHeight}px`;
|
|
44
|
+
if (movesWidth) node.style.width = `${fromWidth}px`;
|
|
45
|
+
void node.offsetHeight;
|
|
46
|
+
if (movesHeight) node.style.height = `${toHeight}px`;
|
|
47
|
+
if (movesWidth) node.style.width = `${toWidth}px`;
|
|
48
|
+
inFlight = true;
|
|
49
|
+
resizing.value = true;
|
|
50
|
+
clearTimeout(settleTimer);
|
|
51
|
+
const wait = reducedMotion() ? 0 : toValue(options.duration) ?? TWEEN_MS;
|
|
52
|
+
settleTimer = setTimeout(() => {
|
|
53
|
+
inFlight = false;
|
|
54
|
+
resizing.value = false;
|
|
55
|
+
node.style.height = "";
|
|
56
|
+
node.style.width = "";
|
|
57
|
+
lastHeight = node.offsetHeight;
|
|
58
|
+
lastWidth = node.offsetWidth;
|
|
59
|
+
}, wait);
|
|
60
|
+
}
|
|
61
|
+
function teardown() {
|
|
62
|
+
ro?.disconnect();
|
|
63
|
+
mo?.disconnect();
|
|
64
|
+
ro = void 0;
|
|
65
|
+
mo = void 0;
|
|
66
|
+
cancelAnimationFrame(raf);
|
|
67
|
+
clearTimeout(settleTimer);
|
|
68
|
+
tweening.value = false;
|
|
69
|
+
resizing.value = false;
|
|
70
|
+
lastHeight = 0;
|
|
71
|
+
lastWidth = 0;
|
|
72
|
+
inFlight = false;
|
|
73
|
+
}
|
|
74
|
+
watch(
|
|
75
|
+
[el, () => toValue(options.enabled) ?? true],
|
|
76
|
+
([node, enabled]) => {
|
|
77
|
+
teardown();
|
|
78
|
+
if (!enabled || !node) return;
|
|
79
|
+
lastHeight = node.offsetHeight;
|
|
80
|
+
lastWidth = node.offsetWidth;
|
|
81
|
+
if (wantsHeight()) node.style.height = `${lastHeight}px`;
|
|
82
|
+
if (wantsWidth()) node.style.width = `${lastWidth}px`;
|
|
83
|
+
raf = requestAnimationFrame(() => {
|
|
84
|
+
tweening.value = true;
|
|
85
|
+
node.style.height = "";
|
|
86
|
+
node.style.width = "";
|
|
87
|
+
});
|
|
88
|
+
const watchChildren = () => {
|
|
89
|
+
if (!ro) return;
|
|
90
|
+
ro.disconnect();
|
|
91
|
+
for (const child of Array.from(node.children)) ro.observe(child);
|
|
92
|
+
};
|
|
93
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
94
|
+
ro = new ResizeObserver(() => retune());
|
|
95
|
+
watchChildren();
|
|
96
|
+
}
|
|
97
|
+
if (typeof MutationObserver !== "undefined") {
|
|
98
|
+
mo = new MutationObserver(() => {
|
|
99
|
+
watchChildren();
|
|
100
|
+
retune();
|
|
101
|
+
});
|
|
102
|
+
mo.observe(node, { childList: true, subtree: true, characterData: true });
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{ flush: "post" }
|
|
106
|
+
);
|
|
107
|
+
onBeforeUnmount(teardown);
|
|
108
|
+
return { el, tweening, resizing, retune };
|
|
109
|
+
}
|
|
110
|
+
export {
|
|
111
|
+
useShift
|
|
112
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -67,6 +67,7 @@ export { default as LpSelect } from './components/LpSelect.vue';
|
|
|
67
67
|
export type { SelectOption, SelectValue } from './components/LpSelect.vue';
|
|
68
68
|
export { default as LpServiceNode } from './components/LpServiceNode.vue';
|
|
69
69
|
export type { ServiceNodeData } from './components/LpServiceNode.vue';
|
|
70
|
+
export { default as LpShift } from './components/LpShift.vue';
|
|
70
71
|
export { default as LpShortcutsDialog } from './components/LpShortcutsDialog.vue';
|
|
71
72
|
export type { ShortcutEntry, ShortcutGroup } from './components/LpShortcutsDialog.vue';
|
|
72
73
|
export { default as LpSidebar } from './components/LpSidebar.vue';
|
|
@@ -117,6 +118,8 @@ export { useRovingFocus } from './composables/useRovingFocus';
|
|
|
117
118
|
export type { RovingItem, UseRovingFocusOptions } from './composables/useRovingFocus';
|
|
118
119
|
export { useSettled } from './composables/useSettled';
|
|
119
120
|
export type { UseSettledOptions } from './composables/useSettled';
|
|
121
|
+
export { useShift } from './composables/useShift';
|
|
122
|
+
export type { ShiftAxis, UseShift, UseShiftOptions } from './composables/useShift';
|
|
120
123
|
export { useTilt } from './composables/useTilt';
|
|
121
124
|
export type { UseTilt, UseTiltOptions } from './composables/useTilt';
|
|
122
125
|
export { useZoomPan } from './composables/useZoomPan';
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { _ } from "./chunks/LayoutCanvas-Dd20boUG.js";
|
|
2
|
-
import { _ as _2 } from "./chunks/LpAddressInput-
|
|
2
|
+
import { _ as _2 } from "./chunks/LpAddressInput-BTqnUXZG.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";
|
|
6
|
-
import { _ as _5 } from "./chunks/LpAppShell-
|
|
6
|
+
import { _ as _5 } from "./chunks/LpAppShell-CaQYQKZV.js";
|
|
7
7
|
import { _ as _6 } from "./chunks/LpAutocomplete-DExlIZe_.js";
|
|
8
|
-
import { _ as _7 } from "./chunks/LpAvatar-
|
|
8
|
+
import { _ as _7 } from "./chunks/LpAvatar-D-jHoHR7.js";
|
|
9
9
|
import { _ as _8 } from "./chunks/LpBadge-BPodVcJa.js";
|
|
10
10
|
import { _ as _9 } from "./chunks/LpBreadcrumbs-B7Aqatzw.js";
|
|
11
11
|
import { _ as _10 } from "./chunks/LpButton-5VXXCjwF.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-
|
|
17
|
+
import { _ as _15 } from "./chunks/LpConfirmDialog-CObRah9c.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";
|
|
@@ -22,22 +22,22 @@ import { _ as _19 } from "./chunks/LpDivider-CUX46KR0.js";
|
|
|
22
22
|
import { _ as _20 } from "./chunks/LpDrawer-DAJN5rGK.js";
|
|
23
23
|
import { _ as _21 } from "./chunks/LpDropdownMenu-DJpoqRCb.js";
|
|
24
24
|
import { _ as _22 } from "./chunks/LpEmptyState-CrfyRJUG.js";
|
|
25
|
-
import { _ as _23 } from "./chunks/LpFileTree-
|
|
25
|
+
import { _ as _23 } from "./chunks/LpFileTree-CN0IOIY7.js";
|
|
26
26
|
import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
|
|
27
|
-
import { _ as _24 } from "./chunks/LpFormField-
|
|
27
|
+
import { _ as _24 } from "./chunks/LpFormField-CesaPWPO.js";
|
|
28
28
|
import { _ as _25 } from "./chunks/LpIcon-CCnX5_2j.js";
|
|
29
29
|
import { _ as _26 } from "./chunks/LpInfraNode-qIL3l7IO.js";
|
|
30
|
-
import { _ as _27 } from "./chunks/LpInput-
|
|
30
|
+
import { _ as _27 } from "./chunks/LpInput-jwqXlAy0.js";
|
|
31
31
|
import { _ as _28 } from "./chunks/LpLightbox-Ci35Y_xP.js";
|
|
32
32
|
import { fileNameOf } from "./components/lightbox.js";
|
|
33
|
-
import { _ as _29 } from "./chunks/LpLink-
|
|
33
|
+
import { _ as _29 } from "./chunks/LpLink-DU9kkKGW.js";
|
|
34
34
|
import { _ as _30 } from "./chunks/LpLogViewer-B1aLUVdz.js";
|
|
35
|
-
import { _ as _31 } from "./chunks/LpModal-
|
|
36
|
-
import { _ as _32 } from "./chunks/LpNotificationBell-
|
|
35
|
+
import { _ as _31 } from "./chunks/LpModal-D_o-56To.js";
|
|
36
|
+
import { _ as _32 } from "./chunks/LpNotificationBell-a08cl0yY.js";
|
|
37
37
|
import { _ as _33 } from "./chunks/LpNumberField-B3JuQFol.js";
|
|
38
38
|
import { _ as _34 } from "./chunks/LpOtpInput-DqaT0Z75.js";
|
|
39
39
|
import { _ as _35 } from "./chunks/LpPagination-CeGuNe_q.js";
|
|
40
|
-
import { _ as _36 } from "./chunks/LpPasswordInput-
|
|
40
|
+
import { _ as _36 } from "./chunks/LpPasswordInput-Bmo6q9Kd.js";
|
|
41
41
|
import { _ as _37 } from "./chunks/LpPhoneInput-NXXjciJJ.js";
|
|
42
42
|
import { flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
|
|
43
43
|
import { _ as _38 } from "./chunks/LpPopover-8268UmlC.js";
|
|
@@ -48,24 +48,25 @@ import { _ as _42 } from "./chunks/LpScrollArea-D8xyKXcF.js";
|
|
|
48
48
|
import { _ as _43 } from "./chunks/LpSegmented-BmpanyAo.js";
|
|
49
49
|
import { _ as _44 } from "./chunks/LpSelect-Cw8-gL5F.js";
|
|
50
50
|
import { _ as _45 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
51
|
+
import { _ as _46 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
51
52
|
import { default as default3 } from "./components/LpShortcutsDialog.vue.js";
|
|
52
|
-
import { _ as
|
|
53
|
-
import { _ as
|
|
54
|
-
import { _ as
|
|
55
|
-
import { _ as
|
|
56
|
-
import { _ as
|
|
57
|
-
import { _ as
|
|
58
|
-
import { _ as
|
|
59
|
-
import { _ as
|
|
60
|
-
import { _ as
|
|
61
|
-
import { _ as
|
|
62
|
-
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/LpThemeSwitcher-
|
|
63
|
-
import { D, _ as
|
|
64
|
-
import { _ as
|
|
65
|
-
import { _ as
|
|
66
|
-
import { _ as
|
|
67
|
-
import { _ as
|
|
68
|
-
import { _ as
|
|
53
|
+
import { _ as _47 } from "./chunks/LpSidebar-D3GGLSE7.js";
|
|
54
|
+
import { _ as _48 } from "./chunks/LpSkeleton-eSFIo4kD.js";
|
|
55
|
+
import { _ as _49 } from "./chunks/LpSlider-B1SF3pRV.js";
|
|
56
|
+
import { _ as _50 } from "./chunks/LpStat-CdbEFOvn.js";
|
|
57
|
+
import { _ as _51 } from "./chunks/LpStepper-5dFTrW21.js";
|
|
58
|
+
import { _ as _52 } from "./chunks/LpSwitch-v6fnccSM.js";
|
|
59
|
+
import { _ as _53 } from "./chunks/LpTable-DTj52qlg.js";
|
|
60
|
+
import { _ as _54 } from "./chunks/LpTableOfContents-CjvxPMpU.js";
|
|
61
|
+
import { _ as _55 } from "./chunks/LpTabs-Cefe_lys.js";
|
|
62
|
+
import { _ as _56 } from "./chunks/LpTextarea-1ENb3ZAO.js";
|
|
63
|
+
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/LpThemeSwitcher-BgpJgrnP.js";
|
|
64
|
+
import { D, _ as _57, N, T, b, c, d, e, f, g, i, l, h, j, n, r, t, k, m, u, v } from "./chunks/LpThemeSwitcher-BgpJgrnP.js";
|
|
65
|
+
import { _ as _58 } from "./chunks/LpTilt-DuyKbpkA.js";
|
|
66
|
+
import { _ as _59 } from "./chunks/LpToaster-gDB1EaU3.js";
|
|
67
|
+
import { _ as _60 } from "./chunks/LpTooltip-D1hbjQWG.js";
|
|
68
|
+
import { _ as _61 } from "./chunks/LpTopologyCanvas-ebP67CLx.js";
|
|
69
|
+
import { _ as _62 } from "./chunks/LpUptimeBar-CB366k0O.js";
|
|
69
70
|
import { deserializeLayout, serializeLayout } from "./layout/tree.js";
|
|
70
71
|
import { addLeaf, addTab, countBlocks, countLeaves, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, setActiveTab } from "./layout/tree.js";
|
|
71
72
|
import { blockTitle, defineBlocks } from "./layout/registry.js";
|
|
@@ -74,6 +75,7 @@ import { appleModifierLabel, isAppleKeyboard, useHotkeys } from "./composables/u
|
|
|
74
75
|
import { useInputFilter } from "./composables/useInputFilter.js";
|
|
75
76
|
import { useRovingFocus } from "./composables/useRovingFocus.js";
|
|
76
77
|
import { useSettled } from "./composables/useSettled.js";
|
|
78
|
+
import { useShift } from "./composables/useShift.js";
|
|
77
79
|
import { useTilt } from "./composables/useTilt.js";
|
|
78
80
|
import { useZoomPan } from "./composables/useZoomPan.js";
|
|
79
81
|
import { useToast } from "./composables/useToast.js";
|
|
@@ -155,23 +157,24 @@ export {
|
|
|
155
157
|
_43 as LpSegmented,
|
|
156
158
|
_44 as LpSelect,
|
|
157
159
|
_45 as LpServiceNode,
|
|
160
|
+
_46 as LpShift,
|
|
158
161
|
default3 as LpShortcutsDialog,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
_47 as LpSidebar,
|
|
163
|
+
_48 as LpSkeleton,
|
|
164
|
+
_49 as LpSlider,
|
|
165
|
+
_50 as LpStat,
|
|
166
|
+
_51 as LpStepper,
|
|
167
|
+
_52 as LpSwitch,
|
|
168
|
+
_53 as LpTable,
|
|
169
|
+
_54 as LpTableOfContents,
|
|
170
|
+
_55 as LpTabs,
|
|
171
|
+
_56 as LpTextarea,
|
|
172
|
+
_57 as LpThemeSwitcher,
|
|
173
|
+
_58 as LpTilt,
|
|
174
|
+
_59 as LpToaster,
|
|
175
|
+
_60 as LpTooltip,
|
|
176
|
+
_61 as LpTopologyCanvas,
|
|
177
|
+
_62 as LpUptimeBar,
|
|
175
178
|
N as NO_BACKDROP_ATTR,
|
|
176
179
|
OSM_TILES,
|
|
177
180
|
T as THEME_COOKIE,
|
|
@@ -239,6 +242,7 @@ export {
|
|
|
239
242
|
useLayout,
|
|
240
243
|
useRovingFocus,
|
|
241
244
|
useSettled,
|
|
245
|
+
useShift,
|
|
242
246
|
u as useTheme,
|
|
243
247
|
useTilt,
|
|
244
248
|
useToast,
|
package/dist/theme/tokens.d.ts
CHANGED
package/package.json
CHANGED
package/src/component-names.ts
CHANGED
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
* - a default `isActive` (path prefix-match) and a default page title derived
|
|
12
12
|
* from the nav items, so the header title and the active pill never drift.
|
|
13
13
|
*
|
|
14
|
+
* The header bar's two content-driven regions — the title block and the actions
|
|
15
|
+
* cluster — ease between sizes rather than snapping (LpShift). Those regions
|
|
16
|
+
* change constantly in normal use: actions teleport in per route or per section
|
|
17
|
+
* tab, and every label is translated, so their measurements move under the
|
|
18
|
+
* user. Without the easing each change re-lays the bar in a single frame.
|
|
19
|
+
*
|
|
14
20
|
* Everything product-specific goes through slots: #logo (brand in the rail
|
|
15
21
|
* header), #sidebar-actions / #sidebar-footer (pass-through to LpSidebar),
|
|
16
22
|
* #header-actions (right side of the top bar — bell, search, theme switch),
|
|
@@ -18,10 +24,11 @@
|
|
|
18
24
|
* Overlays that aren't part of the frame (command palette, toaster) live in the
|
|
19
25
|
* host next to <LpAppShell>.
|
|
20
26
|
*/
|
|
21
|
-
import { computed,
|
|
27
|
+
import { computed, watch } from "vue"
|
|
22
28
|
import LpButton from "./LpButton.vue"
|
|
23
29
|
import LpIcon from "./LpIcon.vue"
|
|
24
30
|
import LpScrollArea from "./LpScrollArea.vue"
|
|
31
|
+
import LpShift from "./LpShift.vue"
|
|
25
32
|
import LpSidebar from "./LpSidebar.vue"
|
|
26
33
|
import type { SidebarItem, SidebarSection } from "./sidebar"
|
|
27
34
|
|
|
@@ -195,13 +202,26 @@ defineExpose({ openDrawer: _openDrawer })
|
|
|
195
202
|
<LpIcon name="lucide:menu" :size="18" />
|
|
196
203
|
</LpButton>
|
|
197
204
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
<
|
|
205
|
+
<!-- The title block eases its height: a page that adds a subtitle, or a
|
|
206
|
+
translation that wraps a long title onto a second line, otherwise
|
|
207
|
+
re-lays the whole bar in one frame. Width is left free so the
|
|
208
|
+
truncation still resolves against the space actually available. -->
|
|
209
|
+
<LpShift axis="height" class="flex min-w-0 flex-1 items-center">
|
|
210
|
+
<slot name="header-title">
|
|
211
|
+
<h1 class="truncate text-lg font-semibold">{{ pageTitle }}</h1>
|
|
212
|
+
</slot>
|
|
213
|
+
</LpShift>
|
|
214
|
+
|
|
215
|
+
<!-- Actions ease their WIDTH. This is the bar's worst offender: page
|
|
216
|
+
actions arrive by teleport, so a button appears or disappears with
|
|
217
|
+
the route or the section tab, and a translation swaps a short label
|
|
218
|
+
for a long one — each snapping every control to its left sideways.
|
|
219
|
+
Kept mounted regardless of the slot, so a page that only teleports
|
|
220
|
+
into it still gets the easing (an empty box measures zero wide and
|
|
221
|
+
costs nothing). -->
|
|
222
|
+
<LpShift axis="width" class="ml-auto flex shrink-0 items-center gap-2">
|
|
203
223
|
<slot name="header-actions" />
|
|
204
|
-
</
|
|
224
|
+
</LpShift>
|
|
205
225
|
</header>
|
|
206
226
|
|
|
207
227
|
<!-- full-bleed: page owns the whole region (canvas/map); otherwise the
|
|
@@ -12,15 +12,23 @@ import { computed, onMounted, ref } from "vue"
|
|
|
12
12
|
import LpContextMenu, { type ContextMenuItemDef } from "./LpContextMenu.vue"
|
|
13
13
|
|
|
14
14
|
const avatar = tv({
|
|
15
|
-
base: "inline-flex shrink-0 select-none items-center justify-center overflow-hidden
|
|
15
|
+
base: "inline-flex shrink-0 select-none items-center justify-center overflow-hidden bg-surface-soft font-medium text-muted-strong",
|
|
16
16
|
variants: {
|
|
17
17
|
size: {
|
|
18
18
|
sm: "size-7 text-xs",
|
|
19
19
|
md: "size-9 text-sm",
|
|
20
20
|
lg: "size-12 text-base",
|
|
21
21
|
},
|
|
22
|
+
// People read as circles; things (servers, projects, orgs) read as
|
|
23
|
+
// rounded squares — the same distinction platform icons make.
|
|
24
|
+
shape: {
|
|
25
|
+
circle: "rounded-pill",
|
|
26
|
+
soft: "rounded-card",
|
|
27
|
+
square: "rounded-control",
|
|
28
|
+
},
|
|
29
|
+
ring: { true: "ring-2 ring-line", false: "" },
|
|
22
30
|
},
|
|
23
|
-
defaultVariants: { size: "md" },
|
|
31
|
+
defaultVariants: { size: "md", shape: "circle", ring: false },
|
|
24
32
|
})
|
|
25
33
|
|
|
26
34
|
type AvatarVariants = VariantProps<typeof avatar>
|
|
@@ -31,10 +39,14 @@ const props = withDefaults(
|
|
|
31
39
|
alt?: string
|
|
32
40
|
fallback?: string
|
|
33
41
|
size?: AvatarVariants["size"]
|
|
42
|
+
/** Silhouette: circle for people, soft/square for servers and projects. */
|
|
43
|
+
shape?: AvatarVariants["shape"]
|
|
44
|
+
/** Draws a hairline ring, for avatars laid over imagery or other avatars. */
|
|
45
|
+
ring?: boolean
|
|
34
46
|
/** Right-click menu (e.g. account quick actions). Consumer-supplied. */
|
|
35
47
|
menuItems?: ContextMenuItemDef[]
|
|
36
48
|
}>(),
|
|
37
|
-
{ size: "md" },
|
|
49
|
+
{ size: "md", shape: "circle", ring: false },
|
|
38
50
|
)
|
|
39
51
|
|
|
40
52
|
const initials = computed(
|
|
@@ -55,12 +67,12 @@ onMounted(() => {
|
|
|
55
67
|
|
|
56
68
|
<template>
|
|
57
69
|
<LpContextMenu v-if="menuItems?.length" :items="menuItems">
|
|
58
|
-
<AvatarRoot :class="avatar({ size })" v-bind="$attrs">
|
|
70
|
+
<AvatarRoot :class="avatar({ size, shape, ring })" v-bind="$attrs">
|
|
59
71
|
<AvatarImage v-if="src && mounted" :src="src" :alt="alt" class="size-full object-cover" />
|
|
60
72
|
<AvatarFallback>{{ initials }}</AvatarFallback>
|
|
61
73
|
</AvatarRoot>
|
|
62
74
|
</LpContextMenu>
|
|
63
|
-
<AvatarRoot v-else :class="avatar({ size })" v-bind="$attrs">
|
|
75
|
+
<AvatarRoot v-else :class="avatar({ size, shape, ring })" v-bind="$attrs">
|
|
64
76
|
<AvatarImage v-if="src" :src="src" :alt="alt" class="size-full object-cover" />
|
|
65
77
|
<AvatarFallback>{{ initials }}</AvatarFallback>
|
|
66
78
|
</AvatarRoot>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import LpButton from "./LpButton.vue"
|
|
4
4
|
import LpModal from "./LpModal.vue"
|
|
5
5
|
|
|
6
|
-
withDefaults(
|
|
6
|
+
const props = withDefaults(
|
|
7
7
|
defineProps<{
|
|
8
8
|
open?: boolean
|
|
9
9
|
title?: string
|
|
@@ -11,8 +11,15 @@ withDefaults(
|
|
|
11
11
|
confirmLabel?: string
|
|
12
12
|
cancelLabel?: string
|
|
13
13
|
danger?: boolean
|
|
14
|
+
/**
|
|
15
|
+
* The confirm action is in flight: the button disables and swaps to
|
|
16
|
+
* `loadingLabel`, and confirming no longer closes the dialog — the owner
|
|
17
|
+
* closes it once the work settles, so a failure can stay on screen.
|
|
18
|
+
*/
|
|
19
|
+
loading?: boolean
|
|
20
|
+
loadingLabel?: string
|
|
14
21
|
}>(),
|
|
15
|
-
{ confirmLabel: "Confirm", cancelLabel: "Cancel" },
|
|
22
|
+
{ confirmLabel: "Confirm", cancelLabel: "Cancel", loadingLabel: "Working…" },
|
|
16
23
|
)
|
|
17
24
|
|
|
18
25
|
const emit = defineEmits<{
|
|
@@ -23,7 +30,9 @@ const emit = defineEmits<{
|
|
|
23
30
|
|
|
24
31
|
function confirm() {
|
|
25
32
|
emit("confirm")
|
|
26
|
-
|
|
33
|
+
// An async confirm owns its own dismissal; closing here would tear the
|
|
34
|
+
// dialog down before the caller knows whether the action succeeded.
|
|
35
|
+
if (!props.loading) emit("update:open", false)
|
|
27
36
|
}
|
|
28
37
|
function cancel() {
|
|
29
38
|
emit("cancel")
|
|
@@ -40,9 +49,15 @@ function cancel() {
|
|
|
40
49
|
>
|
|
41
50
|
<slot />
|
|
42
51
|
<template #footer>
|
|
43
|
-
<LpButton variant="ghost" @click="cancel">
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
<LpButton variant="ghost" :disabled="loading" @click="cancel">
|
|
53
|
+
{{ cancelLabel }}
|
|
54
|
+
</LpButton>
|
|
55
|
+
<LpButton
|
|
56
|
+
:variant="danger ? 'danger' : 'solid'"
|
|
57
|
+
:disabled="loading"
|
|
58
|
+
@click="confirm"
|
|
59
|
+
>
|
|
60
|
+
{{ loading ? loadingLabel : confirmLabel }}
|
|
46
61
|
</LpButton>
|
|
47
62
|
</template>
|
|
48
63
|
</LpModal>
|
|
@@ -178,8 +178,17 @@ function onActivate() {
|
|
|
178
178
|
@click.stop="onActivate"
|
|
179
179
|
>
|
|
180
180
|
<!-- Chevron sits in a fixed-width slot so names line up whether or not
|
|
181
|
-
the row can expand. Leaves get the same gutter, left empty.
|
|
182
|
-
|
|
181
|
+
the row can expand. Leaves get the same gutter, left empty.
|
|
182
|
+
|
|
183
|
+
It is its own hit target, like the checkbox: opening a folder to
|
|
184
|
+
see what is in it is a different intent from selecting it, and on
|
|
185
|
+
a tree that drives a details pane the two must not be the same
|
|
186
|
+
click. The row as a whole still does both. -->
|
|
187
|
+
<span
|
|
188
|
+
class="flex size-4 shrink-0 items-center justify-center"
|
|
189
|
+
:class="canExpand ? 'cursor-pointer rounded-sm hover:bg-line' : ''"
|
|
190
|
+
@click.stop="canExpand && !node.disabled ? emit('toggle', node) : undefined"
|
|
191
|
+
>
|
|
183
192
|
<LpIcon
|
|
184
193
|
v-if="isLoading"
|
|
185
194
|
name="lucide:loader-circle"
|