@leavepulse/ui 0.93.2 → 0.94.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/README.md +53 -3
- package/dist/assets/LpTabs-D7EyG21l.css +18 -0
- package/dist/assets/LpVideoTrim-D8JDg9Qn.css +8 -0
- package/dist/chunks/AppShellContextNav-BoH4ffnC.js +54 -0
- package/dist/chunks/{LpAppShell-BWaVRsDB.js → LpAppShell-xEBmGV78.js} +12 -5
- package/dist/chunks/{LpDateRangePicker-CAn2yGbn.js → LpDateRangePicker-DRBB8z6t.js} +1 -1
- package/dist/chunks/{LpDrawer-iRHwJOGn.js → LpDrawer-BkWjFdV0.js} +81 -42
- package/dist/chunks/{LpLightbox-a24V_0Wk.js → LpLightbox-DPgz7IsT.js} +62 -49
- package/dist/chunks/{LpMapPicker-DVfiy3rR.js → LpMapPicker-V0Lybi10.js} +19 -52
- package/dist/chunks/{LpMediaGallery-B7DOV_aL.js → LpMediaGallery-CTejKF2-.js} +36 -15
- package/dist/chunks/{LpModalNav-DivqT1NV.js → LpModalNav-DVXAF-DG.js} +1 -1
- package/dist/chunks/{LpRangeCalendar-C9gkNMYw.js → LpRangeCalendar-9BvaLZji.js} +3 -4
- package/dist/chunks/LpScrollStrip-D4tsOfAQ.js +78 -0
- package/dist/chunks/{LpSidebar-DQtCYlT4.js → LpSidebar-BIhusppV.js} +1 -1
- package/dist/component-names.d.ts +1 -1
- package/dist/components/AppShellContextNav.vue.js +1 -1
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpChart.vue.js +3 -3
- package/dist/components/LpDateRangePicker.vue.js +1 -1
- package/dist/components/LpDrawer.vue.d.ts +10 -2
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropzone.vue.d.ts +1 -1
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMediaGallery.vue.d.ts +2 -0
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpRangeCalendar.vue.js +1 -1
- package/dist/components/LpRevealOnScroll.vue.d.ts +1 -1
- package/dist/components/LpScrollStrip.vue.d.ts +48 -0
- package/dist/components/LpScrollStrip.vue.js +4 -0
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +4 -4
- package/dist/components/LpTabs.vue.js +104 -90
- package/dist/components/LpVideoTrim.vue.js +41 -54
- package/dist/composables/gesture.d.ts +141 -0
- package/dist/composables/gesture.js +176 -0
- package/dist/composables/scroll.d.ts +5 -1
- package/dist/composables/scroll.js +16 -9
- package/dist/composables/useAppUpdate.d.ts +26 -0
- package/dist/composables/useAppUpdate.js +91 -0
- package/dist/composables/useGesture.d.ts +107 -0
- package/dist/composables/useGesture.js +281 -0
- package/dist/composables/usePaintSelect.js +3 -4
- package/dist/composables/useScrollStrip.d.ts +27 -0
- package/dist/composables/useScrollStrip.js +194 -0
- package/dist/composables/useTouchHold.d.ts +3 -1
- package/dist/composables/useTouchHold.js +9 -51
- package/dist/composables/useZoomPan.js +4 -6
- package/dist/index.d.ts +9 -0
- package/dist/index.js +180 -152
- package/package.json +1 -1
- package/src/component-names.ts +1 -0
- package/src/components/AppShellContextNav.vue +3 -2
- package/src/components/LpAppShell.vue +10 -1
- package/src/components/LpChart.vue +2 -2
- package/src/components/LpDrawer.vue +121 -54
- package/src/components/LpLightbox.vue +33 -20
- package/src/components/LpMapPicker.vue +22 -64
- package/src/components/LpMediaGallery.vue +44 -11
- package/src/components/LpRangeCalendar.vue +4 -5
- package/src/components/LpScrollStrip.vue +96 -0
- package/src/components/LpSidebar.vue +2 -2
- package/src/components/LpTabs.vue +36 -17
- package/src/components/LpVideoTrim.vue +35 -46
- package/src/composables/gesture.ts +314 -0
- package/src/composables/scroll.ts +20 -9
- package/src/composables/useAppUpdate.ts +156 -0
- package/src/composables/useGesture.ts +451 -0
- package/src/composables/usePaintSelect.ts +4 -5
- package/src/composables/useScrollStrip.ts +249 -0
- package/src/composables/useTouchHold.ts +15 -73
- package/src/composables/useZoomPan.ts +6 -9
- package/src/index.ts +27 -0
- package/src/tokens/effects.css +40 -0
- package/dist/assets/LpTabs-Bh7a-Bdl.css +0 -18
- package/dist/assets/LpVideoTrim-CMoUw3dJ.css +0 -8
- package/dist/chunks/AppShellContextNav-C6Ho2mof.js +0 -49
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ JSON token sets), and a composable block-layout canvas.
|
|
|
9
9
|
- [Install](#install) and [Usage](#usage)
|
|
10
10
|
- [Configuration](#configuration): theme, labels and languages, icons, Nuxt, overlays and Back, prop check, WebKitGTK glass, scrollbars
|
|
11
11
|
- [Components](#components): every component by group, with what it is for
|
|
12
|
-
- [Guides](#guides): linked views, workspaces, forms, tables, clipboard, video, command palette
|
|
12
|
+
- [Guides](#guides): linked views, workspaces, forms, tables, clipboard, video, gestures and sideways rows, command palette
|
|
13
13
|
- [Develop](#develop) and [Releasing](#releasing)
|
|
14
14
|
|
|
15
15
|
## Install
|
|
@@ -289,7 +289,7 @@ from the comment that opens the component.
|
|
|
289
289
|
|
|
290
290
|
<!-- catalogue:start -->
|
|
291
291
|
|
|
292
|
-
|
|
292
|
+
143 components. The preview (`bun run dev`) shows each one live, with its props, events and slots.
|
|
293
293
|
|
|
294
294
|
<details>
|
|
295
295
|
<summary><b>Basics</b> (24)</summary>
|
|
@@ -389,7 +389,7 @@ from the comment that opens the component.
|
|
|
389
389
|
</details>
|
|
390
390
|
|
|
391
391
|
<details>
|
|
392
|
-
<summary><b>Navigation</b> (
|
|
392
|
+
<summary><b>Navigation</b> (16)</summary>
|
|
393
393
|
|
|
394
394
|
- `LpActionBar`: A bar that rises from the bottom of the window to ask for one decision, then leaves.
|
|
395
395
|
- `LpBreadcrumbs`: Where the page sits in the app, as a trail of links.
|
|
@@ -402,6 +402,7 @@ from the comment that opens the component.
|
|
|
402
402
|
- `LpPalettePreview`: The body of LpCommandPalette's `#preview` slot.
|
|
403
403
|
- `LpPaletteStats`: A few figures in a palette preview, as tiles: mods and worlds in an instance, downloads and follows of a project, members online.
|
|
404
404
|
- `LpPaletteSwatches`: A theme's colours as a strip of swatches on its own surface, for a palette preview of a theme picker: the row says the name, this shows what picking it would look like.
|
|
405
|
+
- `LpScrollStrip`: A row that scrolls sideways and can be reached with any input: tabs, chips, branch pills, a filmstrip.
|
|
405
406
|
- `LpSidebar`: App-shell side navigation.
|
|
406
407
|
- `LpStepper`: The steps of a flow, with where the person is and which are done.
|
|
407
408
|
- `LpTableOfContents`: On-this-page table of contents with scroll-spy.
|
|
@@ -621,6 +622,55 @@ if (await canTranscodeVideo()) {
|
|
|
621
622
|
Re-encoding never raises the bitrate above the source's, and the sound is kept
|
|
622
623
|
(AAC, or Opus where the browser has no AAC encoder).
|
|
623
624
|
|
|
625
|
+
### Gestures and sideways rows
|
|
626
|
+
|
|
627
|
+
Every drag, swipe, pinch and long press in the kit runs on one engine, so they
|
|
628
|
+
draw the line in the same place: a press becomes a drag past the slop (8 px for
|
|
629
|
+
a finger, 4 for a mouse), nothing is captured or prevented before that (a click
|
|
630
|
+
on what is under it still lands), a drag swallows the click it ends with,
|
|
631
|
+
velocity is read over the last 100 ms, and a pointer the browser takes back, a
|
|
632
|
+
second finger or Escape ends it as `cancelled`.
|
|
633
|
+
|
|
634
|
+
```ts
|
|
635
|
+
import { useGesture, shouldDismiss } from "@leavepulse/ui"
|
|
636
|
+
|
|
637
|
+
const card = ref<HTMLElement | null>(null)
|
|
638
|
+
const x = ref(0)
|
|
639
|
+
useGesture(card, {
|
|
640
|
+
axis: "x", // a press that starts vertical is let go, so the page scrolls
|
|
641
|
+
onDrag: ({ movement }) => (x.value = movement.x),
|
|
642
|
+
onDragEnd: ({ movement, velocity, cancelled }) => {
|
|
643
|
+
const away = !cancelled && shouldDismiss({ offset: movement.x, velocity: velocity.x, size: 320 })
|
|
644
|
+
x.value = away ? 400 : 0
|
|
645
|
+
},
|
|
646
|
+
})
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
- `createGesture(options)` returns the handlers to bind yourself, for an element
|
|
650
|
+
that composes them with others. `onPinch`, `longPress`, `onTap` and `onSwipe`
|
|
651
|
+
sit beside the drag callbacks.
|
|
652
|
+
- `pageAfterSwipe` and `rubberClamp` make "swipe between items", `glide` coasts
|
|
653
|
+
after a fling, and `createDragSession` makes the same decisions from touch
|
|
654
|
+
events where pointer events cannot be used (a pull from the screen edge must
|
|
655
|
+
stop the page scrolling mid-gesture).
|
|
656
|
+
- An element dragged by finger needs `touch-action` that leaves it the gesture
|
|
657
|
+
(`touch-pan-y` for a sideways one inside a page that scrolls), or the browser
|
|
658
|
+
takes the touch and the drag ends cancelled.
|
|
659
|
+
- Side drawers use it both ways: a pull from within `edgeSize` (72 px) of the
|
|
660
|
+
edge opens one, with the panel's edge under the finger; a swipe on the panel or
|
|
661
|
+
on the scrim closes it. Both complete past a share of the panel or on a flick
|
|
662
|
+
and spring back otherwise.
|
|
663
|
+
|
|
664
|
+
`LpScrollStrip` is the row that scrolls sideways (tabs, chips, branch pills, a
|
|
665
|
+
filmstrip) with its scrollbar hidden and still reachable with a mouse: a
|
|
666
|
+
vertical wheel scrolls it while it can move that way and hands back to the page
|
|
667
|
+
at either end, a mouse or pen drags it, the clipped edges fade, a hover shows
|
|
668
|
+
previous and next buttons, and the focused item is scrolled into view within
|
|
669
|
+
the row only. Touch keeps native scrolling and scroll snap. `useScrollStrip(el)`
|
|
670
|
+
gives an existing scroller the same behaviour. LpTabs uses it for a row wider
|
|
671
|
+
than its box; a mouse there picks a tab on click rather than on press, so a
|
|
672
|
+
drag across the row does not pick the tab it started on.
|
|
673
|
+
|
|
624
674
|
### Contextual command palette
|
|
625
675
|
|
|
626
676
|
Wrap the application (or a page and its palette) in `LpCommandScope`. Nested
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
.lp-tab-badge-enter-active[data-v-43a45129],
|
|
3
|
+
.lp-tab-badge-leave-active[data-v-43a45129] {
|
|
4
|
+
transition:
|
|
5
|
+
opacity var(--duration-fast) var(--ease-emphasized),
|
|
6
|
+
transform var(--duration-fast) var(--ease-emphasized);
|
|
7
|
+
}
|
|
8
|
+
.lp-tab-badge-enter-from[data-v-43a45129],
|
|
9
|
+
.lp-tab-badge-leave-to[data-v-43a45129] {
|
|
10
|
+
opacity: 0;
|
|
11
|
+
transform: scale(0.6);
|
|
12
|
+
}
|
|
13
|
+
@media (prefers-reduced-motion: reduce) {
|
|
14
|
+
.lp-tab-badge-enter-active[data-v-43a45129],
|
|
15
|
+
.lp-tab-badge-leave-active[data-v-43a45129] {
|
|
16
|
+
transition: none;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { defineComponent, openBlock, createBlock, withCtx, createElementBlock, Fragment, renderList, resolveDynamicComponent, mergeProps, createTextVNode, toDisplayString } from "vue";
|
|
2
|
+
import { useLinkComponent } from "../composables/useLpConfig.js";
|
|
3
|
+
import { resolveLink } from "../components/link.js";
|
|
4
|
+
import { _ as _sfc_main$1 } from "./LpScrollStrip-D4tsOfAQ.js";
|
|
5
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
6
|
+
__name: "AppShellContextNav",
|
|
7
|
+
props: {
|
|
8
|
+
items: {},
|
|
9
|
+
isActive: { type: Function },
|
|
10
|
+
label: {}
|
|
11
|
+
},
|
|
12
|
+
emits: ["select"],
|
|
13
|
+
setup(__props, { emit: __emit }) {
|
|
14
|
+
const props = __props;
|
|
15
|
+
const emit = __emit;
|
|
16
|
+
const linkComponent = useLinkComponent();
|
|
17
|
+
function rowOf(item) {
|
|
18
|
+
const link = item.disabled ? null : resolveLink(linkComponent.value, { to: item.to, href: item.href });
|
|
19
|
+
return link ?? { is: "button", props: { type: "button", disabled: item.disabled || void 0 } };
|
|
20
|
+
}
|
|
21
|
+
return (_ctx, _cache) => {
|
|
22
|
+
return openBlock(), createBlock(_sfc_main$1, {
|
|
23
|
+
as: "nav",
|
|
24
|
+
"aria-label": props.label,
|
|
25
|
+
class: "shrink-0 border-b border-line bg-surface",
|
|
26
|
+
"content-class": "gap-1 px-4 py-1.5"
|
|
27
|
+
}, {
|
|
28
|
+
default: withCtx(() => [
|
|
29
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item) => {
|
|
30
|
+
return openBlock(), createBlock(resolveDynamicComponent(rowOf(item).is), mergeProps({
|
|
31
|
+
key: item.id
|
|
32
|
+
}, { ref_for: true }, rowOf(item).props, {
|
|
33
|
+
"aria-current": __props.isActive(item) ? "page" : void 0,
|
|
34
|
+
class: [
|
|
35
|
+
"shrink-0 rounded-control px-2.5 py-1 text-sm font-medium outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring",
|
|
36
|
+
item.disabled ? "cursor-not-allowed opacity-45" : __props.isActive(item) ? "bg-surface-soft text-ink" : "text-muted hover:text-ink"
|
|
37
|
+
],
|
|
38
|
+
onClick: ($event) => emit("select", item)
|
|
39
|
+
}), {
|
|
40
|
+
default: withCtx(() => [
|
|
41
|
+
createTextVNode(toDisplayString(item.label), 1)
|
|
42
|
+
]),
|
|
43
|
+
_: 2
|
|
44
|
+
}, 1040, ["aria-current", "class", "onClick"]);
|
|
45
|
+
}), 128))
|
|
46
|
+
]),
|
|
47
|
+
_: 1
|
|
48
|
+
}, 8, ["aria-label"]);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
export {
|
|
53
|
+
_sfc_main as _
|
|
54
|
+
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { defineComponent, computed, useModel,
|
|
1
|
+
import { defineComponent, ref, computed, useModel, useId, onMounted, watch, nextTick, onBeforeUnmount, useSlots, openBlock, createElementBlock, mergeProps, unref, createElementVNode, withModifiers, toDisplayString, normalizeClass, createVNode, createSlots, withCtx, renderSlot, normalizeProps, guardReactiveProps, normalizeStyle, createCommentVNode, withDirectives, vShow, createBlock, Teleport, mergeModels } from "vue";
|
|
2
2
|
import { prefersReducedMotion, easingToken, durationToken } from "../composables/easing.js";
|
|
3
3
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
4
4
|
import { useResizeObserver } from "../composables/useResizeObserver.js";
|
|
5
5
|
import { useScrollMemory } from "../composables/scrollMemory.js";
|
|
6
|
+
import { useScrollStrip } from "../composables/useScrollStrip.js";
|
|
6
7
|
import { useView, viewWindow } from "../composables/useView.js";
|
|
7
|
-
import { _ as _sfc_main$6 } from "./AppShellContextNav-
|
|
8
|
+
import { _ as _sfc_main$6 } from "./AppShellContextNav-BoH4ffnC.js";
|
|
8
9
|
import { DENSITY_CLASS, resolveNavMode, NAV_BREAKPOINT_PX, contextNavItems, headerCollapsedAfter } from "../components/appShell.js";
|
|
9
10
|
import { _ as _sfc_main$9 } from "./LpBottomNav-9AqvZlRW.js";
|
|
10
11
|
import { _ as _sfc_main$2 } from "./LpContextSwitcher-COw6GHPW.js";
|
|
@@ -13,7 +14,7 @@ import { _ as _sfc_main$4 } from "./LpIcon-CxHFPwKt.js";
|
|
|
13
14
|
import { _ as _sfc_main$8 } from "./LpPageScrollbar-C9sTeU-2.js";
|
|
14
15
|
import { _ as _sfc_main$7 } from "./LpScrollArea-CqvwfZs2.js";
|
|
15
16
|
import { _ as _sfc_main$5 } from "./LpShift-DAgS_d2x.js";
|
|
16
|
-
import { _ as _sfc_main$1 } from "./LpSidebar-
|
|
17
|
+
import { _ as _sfc_main$1 } from "./LpSidebar-BIhusppV.js";
|
|
17
18
|
import { mergeClass, useMergedAttrs } from "../composables/useMergedClass.js";
|
|
18
19
|
import { nodeWindow, isHTMLElement } from "../composables/realm.js";
|
|
19
20
|
const _hoisted_1 = ["href"];
|
|
@@ -69,6 +70,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
69
70
|
emits: /* @__PURE__ */ mergeModels(["update:modelValue", "update:collapsed", "select", "update:compact", "update:pinned", "update:context", "nav-mode"], ["update:open"]),
|
|
70
71
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
71
72
|
const BACK_TO_TOP_AFTER_PX = 600;
|
|
73
|
+
const headerActions = ref(null);
|
|
74
|
+
const actionStrip = useScrollStrip(() => headerActions.value?.$el);
|
|
72
75
|
const props = __props;
|
|
73
76
|
const emit = __emit;
|
|
74
77
|
const switching = computed(() => (props.contexts?.length ?? 0) > 1);
|
|
@@ -478,16 +481,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
478
481
|
_: 3
|
|
479
482
|
}),
|
|
480
483
|
createVNode(_sfc_main$5, {
|
|
484
|
+
ref_key: "headerActions",
|
|
485
|
+
ref: headerActions,
|
|
481
486
|
axis: "width",
|
|
482
487
|
anchor: "end",
|
|
483
488
|
presence: "",
|
|
484
|
-
class: "ml-auto flex max-w-[66%] shrink items-center gap-2 overflow-x-auto lp-scrollbar-none md:max-w-none md:shrink-0 md:overflow-visible"
|
|
489
|
+
class: "lp-strip-fade ml-auto flex max-w-[66%] shrink items-center gap-2 overflow-x-auto lp-scrollbar-none md:max-w-none md:shrink-0 md:overflow-visible",
|
|
490
|
+
"data-lp-more-start": unref(actionStrip).overflowing.value && !unref(actionStrip).atStart.value ? "" : void 0,
|
|
491
|
+
"data-lp-more-end": unref(actionStrip).overflowing.value && !unref(actionStrip).atEnd.value ? "" : void 0
|
|
485
492
|
}, {
|
|
486
493
|
default: withCtx(() => [
|
|
487
494
|
renderSlot(_ctx.$slots, "header-actions")
|
|
488
495
|
]),
|
|
489
496
|
_: 3
|
|
490
|
-
})
|
|
497
|
+
}, 8, ["data-lp-more-start", "data-lp-more-end"])
|
|
491
498
|
], 38),
|
|
492
499
|
contextVisible.value ? renderSlot(_ctx.$slots, "context-nav", {
|
|
493
500
|
key: 0,
|
|
@@ -6,7 +6,7 @@ import { useLabels } from "../composables/useLpConfig.js";
|
|
|
6
6
|
import { useMediaQuery } from "../composables/useMediaQuery.js";
|
|
7
7
|
import { normalizeRange, formatRange, defaultRangePresets, sameRange, allowedRange } from "../components/dateRange.js";
|
|
8
8
|
import { _ as _sfc_main$2 } from "./PickerField-DzF3UVnX.js";
|
|
9
|
-
import { _ as _sfc_main$3 } from "./LpRangeCalendar-
|
|
9
|
+
import { _ as _sfc_main$3 } from "./LpRangeCalendar-9BvaLZji.js";
|
|
10
10
|
const __default__ = { inheritAttrs: false };
|
|
11
11
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
12
12
|
...__default__,
|
|
@@ -11,6 +11,8 @@ import { _ as _sfc_main$1 } from "./LpIcon-CxHFPwKt.js";
|
|
|
11
11
|
import { _ as _sfc_main$2 } from "./LpScrollArea-CqvwfZs2.js";
|
|
12
12
|
import { useModalLayer, anyModalOpen } from "../components/modalDepth.js";
|
|
13
13
|
import { startPointerDrag } from "../composables/pointerDrag.js";
|
|
14
|
+
import { createDragSession, TOUCH_SLOP, shouldDismiss, rubberBand } from "../composables/gesture.js";
|
|
15
|
+
import { createGesture } from "../composables/useGesture.js";
|
|
14
16
|
import { useView, viewDocument, usePortalTarget, useOutsideGuard, viewWindow } from "../composables/useView.js";
|
|
15
17
|
import { clamp } from "../composables/clamp.js";
|
|
16
18
|
import { nodeWindow, isElement } from "../composables/realm.js";
|
|
@@ -43,7 +45,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
43
45
|
noDragContent: { type: Boolean },
|
|
44
46
|
edgeOpen: { type: Boolean },
|
|
45
47
|
edgeBreakpoint: {},
|
|
46
|
-
edgeSize: { default:
|
|
48
|
+
edgeSize: { default: 72 },
|
|
47
49
|
edgeOpenThreshold: { default: 0.3 },
|
|
48
50
|
resizable: { type: Boolean },
|
|
49
51
|
minSize: { default: "22rem" },
|
|
@@ -168,10 +170,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
168
170
|
mounted: tagNoDrag,
|
|
169
171
|
updated: tagNoDrag
|
|
170
172
|
};
|
|
171
|
-
const EDGE_SLOP = 10;
|
|
172
|
-
const FLICK_SPEED = 0.45;
|
|
173
173
|
const BREAKPOINT_PX = { sm: 640, md: 768, lg: 1024, xl: 1280 };
|
|
174
|
-
const EDGE_IGNORE = "input, textarea, select, [contenteditable=''], [contenteditable='true'], [data-vaul-no-drag], [data-lp-no-edge-pull]";
|
|
174
|
+
const EDGE_IGNORE = "input, textarea, select, [contenteditable=''], [contenteditable='true'], div[data-vaul-no-drag], [data-lp-no-edge-pull]";
|
|
175
175
|
const peek = ref(0);
|
|
176
176
|
const peeking = ref(false);
|
|
177
177
|
const handingOff = ref(false);
|
|
@@ -179,7 +179,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
179
179
|
watch(
|
|
180
180
|
() => props.open,
|
|
181
181
|
(open) => {
|
|
182
|
-
if (open)
|
|
182
|
+
if (open) {
|
|
183
|
+
shut.value = 0;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
183
186
|
skipOpenSlide.value = false;
|
|
184
187
|
endResize?.();
|
|
185
188
|
}
|
|
@@ -200,16 +203,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
200
203
|
}
|
|
201
204
|
let track = null;
|
|
202
205
|
const owner = /* @__PURE__ */ Symbol("edge-pull");
|
|
203
|
-
function scrollsWithPull(target) {
|
|
206
|
+
function scrollsWithPull(target, towardOpen) {
|
|
204
207
|
let el = isElement(target) ? target : null;
|
|
205
|
-
const
|
|
208
|
+
const right = dir.value === "left" === towardOpen;
|
|
206
209
|
const body = el?.ownerDocument.body;
|
|
207
210
|
while (el && el !== body) {
|
|
208
211
|
if (el.closest(EDGE_IGNORE) === el) return true;
|
|
209
212
|
if (el.scrollWidth > el.clientWidth) {
|
|
210
213
|
const overflow = nodeWindow(el).getComputedStyle(el).overflowX;
|
|
211
214
|
if (overflow === "auto" || overflow === "scroll") {
|
|
212
|
-
if (
|
|
215
|
+
if (right ? el.scrollLeft > 0 : el.scrollLeft + el.clientWidth < el.scrollWidth) return true;
|
|
213
216
|
}
|
|
214
217
|
}
|
|
215
218
|
el = el.parentElement;
|
|
@@ -219,26 +222,25 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
219
222
|
function inward(x) {
|
|
220
223
|
return dir.value === "right" ? edgeWindow().innerWidth - x : x;
|
|
221
224
|
}
|
|
225
|
+
const opening = (x) => dir.value === "right" ? -x : x;
|
|
222
226
|
function onTouchStart(e) {
|
|
223
227
|
if (track) dropTrack();
|
|
224
228
|
if (e.touches.length !== 1 || !edgeEnabled() || anyModalOpen() || edgeOwner.value) return;
|
|
225
229
|
const t = e.touches[0];
|
|
226
|
-
if (inward(t.clientX) > props.edgeSize || scrollsWithPull(e.target)) return;
|
|
227
|
-
track = { id: t.identifier, x: t.clientX, y: t.clientY,
|
|
230
|
+
if (inward(t.clientX) > props.edgeSize || scrollsWithPull(e.target, true)) return;
|
|
231
|
+
track = { id: t.identifier, session: createDragSession({ x: t.clientX, y: t.clientY }, e.timeStamp, { slop: TOUCH_SLOP, axis: "x" }) };
|
|
228
232
|
}
|
|
229
233
|
function onTouchMove(e) {
|
|
230
234
|
if (!track) return;
|
|
231
235
|
const t = Array.from(e.changedTouches).find((x) => x.identifier === track.id);
|
|
232
236
|
if (!t) return;
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
if (dx < EDGE_SLOP || Math.abs(dx) < Math.abs(dy)) return;
|
|
237
|
+
const frame = track.session.move({ x: t.clientX, y: t.clientY }, e.timeStamp);
|
|
238
|
+
if (frame.phase === "rejected" || frame.first && opening(frame.movement.x) <= 0) {
|
|
239
|
+
dropTrack();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (frame.phase !== "drag") return;
|
|
243
|
+
if (frame.first) {
|
|
242
244
|
if (edgeOwner.value && edgeOwner.value !== owner) {
|
|
243
245
|
track = null;
|
|
244
246
|
return;
|
|
@@ -247,10 +249,6 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
247
249
|
peeking.value = true;
|
|
248
250
|
}
|
|
249
251
|
if (e.cancelable) e.preventDefault();
|
|
250
|
-
const dt = e.timeStamp - track.lastT;
|
|
251
|
-
if (dt > 0) track.speed = (t.clientX - track.lastX) * sign / dt * 0.6 + track.speed * 0.4;
|
|
252
|
-
track.lastX = t.clientX;
|
|
253
|
-
track.lastT = e.timeStamp;
|
|
254
252
|
peek.value = clamp(inward(t.clientX) / panelPx(), 0, 1);
|
|
255
253
|
}
|
|
256
254
|
function dropTrack() {
|
|
@@ -263,12 +261,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
263
261
|
peeking.value = false;
|
|
264
262
|
peek.value = 0;
|
|
265
263
|
}
|
|
266
|
-
function settle() {
|
|
267
|
-
const
|
|
264
|
+
function settle(e) {
|
|
265
|
+
const t = track && Array.from(e.changedTouches).find((x) => x.identifier === track.id);
|
|
266
|
+
const end = track && t ? track.session.end({ x: t.clientX, y: t.clientY }, e.timeStamp) : null;
|
|
268
267
|
dropTrack();
|
|
269
268
|
if (!peeking.value) return;
|
|
270
269
|
peeking.value = false;
|
|
271
|
-
|
|
270
|
+
const size = panelPx();
|
|
271
|
+
const opens = !!end && shouldDismiss({ offset: peek.value * size, velocity: opening(end.velocity.x), size, ratio: props.edgeOpenThreshold });
|
|
272
|
+
if (opens) {
|
|
272
273
|
peek.value = 1;
|
|
273
274
|
handingOff.value = true;
|
|
274
275
|
skipOpenSlide.value = true;
|
|
@@ -287,6 +288,44 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
287
288
|
peek.value = 0;
|
|
288
289
|
}
|
|
289
290
|
}
|
|
291
|
+
const shut = ref(0);
|
|
292
|
+
const shutting = ref(false);
|
|
293
|
+
const closeSwipe = {
|
|
294
|
+
pointerTypes: ["touch", "pen"],
|
|
295
|
+
axis: "x",
|
|
296
|
+
ignore: EDGE_IGNORE,
|
|
297
|
+
enabled: () => !!props.open && isHorizontal.value && props.dismissible && !guarded.value && !handingOff.value,
|
|
298
|
+
onPress: (e) => !scrollsWithPull(e.target, false),
|
|
299
|
+
onDragStart: () => shutting.value = true,
|
|
300
|
+
onDrag: ({ movement }) => {
|
|
301
|
+
const toward = -opening(movement.x);
|
|
302
|
+
shut.value = toward >= 0 ? toward : rubberBand(toward, panelPx(), 0.2);
|
|
303
|
+
},
|
|
304
|
+
onDragEnd: ({ velocity, cancelled }) => {
|
|
305
|
+
shutting.value = false;
|
|
306
|
+
const size = panelPx();
|
|
307
|
+
if (!cancelled && shouldDismiss({ offset: shut.value, velocity: -opening(velocity.x), size, ratio: props.closeThreshold ?? 0.25 })) {
|
|
308
|
+
emit("update:open", false);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
shut.value = 0;
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
const panelSwipe = createGesture(closeSwipe);
|
|
315
|
+
const scrimSwipe = createGesture(closeSwipe);
|
|
316
|
+
onBeforeUnmount(() => {
|
|
317
|
+
panelSwipe.dispose();
|
|
318
|
+
scrimSwipe.dispose();
|
|
319
|
+
});
|
|
320
|
+
const shutStyle = computed(() => {
|
|
321
|
+
if (!shut.value && !shutting.value) return void 0;
|
|
322
|
+
const px = dir.value === "right" ? shut.value : -shut.value;
|
|
323
|
+
return { transform: `translate3d(${px}px, 0, 0)`, transition: shutting.value ? "none" : void 0 };
|
|
324
|
+
});
|
|
325
|
+
const scrimStyle = computed(() => {
|
|
326
|
+
if (!shut.value && !shutting.value) return void 0;
|
|
327
|
+
return { opacity: clamp(1 - shut.value / Math.max(1, panelPx()), 0, 1), transition: shutting.value ? "none" : "opacity 0.5s cubic-bezier(0.32, 0.72, 0, 1)" };
|
|
328
|
+
});
|
|
290
329
|
const timers = [];
|
|
291
330
|
onBeforeUnmount(() => {
|
|
292
331
|
for (const id of timers) window.clearTimeout(id);
|
|
@@ -294,7 +333,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
294
333
|
});
|
|
295
334
|
function onTouchEnd(e) {
|
|
296
335
|
if (track && !Array.from(e.changedTouches).some((x) => x.identifier === track.id)) return;
|
|
297
|
-
settle();
|
|
336
|
+
settle(e);
|
|
298
337
|
}
|
|
299
338
|
if (typeof document !== "undefined") {
|
|
300
339
|
watch(
|
|
@@ -302,16 +341,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
302
341
|
(on, _, onCleanup) => {
|
|
303
342
|
if (!on) return;
|
|
304
343
|
const doc = viewDocument(view.value);
|
|
305
|
-
const passive = { passive: true };
|
|
344
|
+
const passive = { passive: true, capture: true };
|
|
306
345
|
doc.addEventListener("touchstart", onTouchStart, passive);
|
|
307
|
-
doc.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
346
|
+
doc.addEventListener("touchmove", onTouchMove, { passive: false, capture: true });
|
|
308
347
|
doc.addEventListener("touchend", onTouchEnd, passive);
|
|
309
348
|
doc.addEventListener("touchcancel", cancelPull, passive);
|
|
310
349
|
onCleanup(() => {
|
|
311
|
-
doc.removeEventListener("touchstart", onTouchStart);
|
|
312
|
-
doc.removeEventListener("touchmove", onTouchMove);
|
|
313
|
-
doc.removeEventListener("touchend", onTouchEnd);
|
|
314
|
-
doc.removeEventListener("touchcancel", cancelPull);
|
|
350
|
+
doc.removeEventListener("touchstart", onTouchStart, true);
|
|
351
|
+
doc.removeEventListener("touchmove", onTouchMove, true);
|
|
352
|
+
doc.removeEventListener("touchend", onTouchEnd, true);
|
|
353
|
+
doc.removeEventListener("touchcancel", cancelPull, true);
|
|
315
354
|
cancelPull();
|
|
316
355
|
});
|
|
317
356
|
},
|
|
@@ -365,7 +404,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
365
404
|
direction: dir.value,
|
|
366
405
|
dismissible: __props.dismissible && !guarded.value,
|
|
367
406
|
"snap-points": __props.snapPoints,
|
|
368
|
-
"handle-only": __props.handleOnly,
|
|
407
|
+
"handle-only": __props.handleOnly || isHorizontal.value,
|
|
369
408
|
"should-scale-background": __props.scaleBackground,
|
|
370
409
|
"close-threshold": __props.closeThreshold,
|
|
371
410
|
"onUpdate:open": _cache[1] || (_cache[1] = (v) => emit("update:open", v))
|
|
@@ -373,19 +412,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
373
412
|
default: withCtx(() => [
|
|
374
413
|
createVNode(unref(DrawerPortal), { to: unref(portalTo) }, {
|
|
375
414
|
default: withCtx(() => [
|
|
376
|
-
createVNode(unref(DrawerOverlay), {
|
|
377
|
-
style:
|
|
415
|
+
createVNode(unref(DrawerOverlay), mergeProps(unref(scrimSwipe).handlers, {
|
|
416
|
+
style: [{ zIndex: unref(layer).scrim }, scrimStyle.value],
|
|
378
417
|
onClick: _cache[0] || (_cache[0] = ($event) => guarded.value && requestClose()),
|
|
379
|
-
class:
|
|
380
|
-
}, null,
|
|
418
|
+
class: ["lp-scrim fixed inset-0 z-(--z-overlay) touch-none data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]", { "lp-scrim--light": unref(frosted), "lp-scrim--nested": unref(layer).nested, "lp-scrim--covered": unref(layer).covered }]
|
|
419
|
+
}), null, 16, ["style", "class"]),
|
|
381
420
|
createVNode(unref(DrawerContent), mergeProps({
|
|
382
421
|
onInteractOutside: unref(guardOutside),
|
|
383
422
|
onEscapeKeyDown: unref(guardOutside),
|
|
384
423
|
ref_key: "contentRef",
|
|
385
424
|
ref: contentRef
|
|
386
|
-
}, __props.description ? {} : { "aria-describedby": void 0 }, {
|
|
425
|
+
}, { ...__props.description ? {} : { "aria-describedby": void 0 }, ...unref(panelSwipe).handlers }, {
|
|
387
426
|
class: contentClass.value,
|
|
388
|
-
style: [sizeStyle.value, { zIndex: unref(layer).panel }],
|
|
427
|
+
style: [sizeStyle.value, { zIndex: unref(layer).panel }, shutStyle.value],
|
|
389
428
|
"data-vaul-animate": handingOff.value || skipOpenSlide.value ? "false" : void 0,
|
|
390
429
|
onKeydown: withKeys(guardEscape, ["escape"])
|
|
391
430
|
}), {
|
|
@@ -452,7 +491,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
452
491
|
}, 8, ["aria-label"])
|
|
453
492
|
], 2)) : createCommentVNode("", true),
|
|
454
493
|
withDirectives((openBlock(), createElementBlock("div", {
|
|
455
|
-
class: "flex min-h-0 min-w-0 flex-1 flex-col [-webkit-user-select:text]! [user-select:text]!",
|
|
494
|
+
class: normalizeClass(["flex min-h-0 min-w-0 flex-1 flex-col [-webkit-user-select:text]! [user-select:text]!", isHorizontal.value ? "[&_[data-reka-scroll-area-viewport]]:touch-pan-y" : void 0]),
|
|
456
495
|
"data-vaul-no-drag": __props.noDragContent ? "" : void 0
|
|
457
496
|
}, [
|
|
458
497
|
createVNode(_sfc_main$2, {
|
|
@@ -464,7 +503,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
464
503
|
]),
|
|
465
504
|
_: 3
|
|
466
505
|
}, 8, ["content-class"])
|
|
467
|
-
],
|
|
506
|
+
], 10, _hoisted_3)), [
|
|
468
507
|
[vNoDragControls, __props.noDragControls]
|
|
469
508
|
]),
|
|
470
509
|
_ctx.$slots.footer ? (openBlock(), createElementBlock("footer", _hoisted_4, [
|