@leavepulse/ui 0.75.0 → 0.76.1
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 +47 -0
- package/dist/assets/{LpShortcutsDialog-BUp_BX4s.css → LpShortcutsDialog-C6uzPeMf.css} +7 -7
- package/dist/assets/LpTabs-CJ0rYQbx.css +18 -0
- package/dist/chunks/{LpAddressInput-Al3HT5ey.js → LpAddressInput-De_LTYM7.js} +1 -1
- package/dist/chunks/{LpAppShell-CpSSm5WT.js → LpAppShell-Cpy_t1U_.js} +1 -1
- package/dist/chunks/{LpConfirmDialog-DY2VjDji.js → LpConfirmDialog-CphJR6Q9.js} +4 -2
- package/dist/chunks/{LpConfirmHost-DvSZTJ4N.js → LpConfirmHost-QSJ0zl63.js} +1 -1
- package/dist/chunks/{LpDrawer-RRamxbLV.js → LpDrawer-DQZixOqJ.js} +13 -0
- package/dist/chunks/{LpModal-BnjZ2iem.js → LpModal-C0tGg_D_.js} +13 -0
- package/dist/chunks/{LpModalNav-DQpV2kdn.js → LpModalNav-iDDtT9c1.js} +2 -2
- package/dist/chunks/{LpSidebar-BoNLKgh-.js → LpSidebar-D6zO8vLm.js} +1 -1
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpConfirmDialog.vue.d.ts +4 -0
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.js +1 -1
- package/dist/components/LpDrawer.vue.d.ts +16 -0
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpModal.vue.d.ts +9 -0
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpShortcutsDialog.vue.d.ts +4 -0
- package/dist/components/LpShortcutsDialog.vue.js +6 -4
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +9 -0
- package/dist/components/LpTabs.vue.js +18 -4
- package/dist/composables/overlayHistory.d.ts +33 -0
- package/dist/composables/overlayHistory.js +250 -0
- package/dist/composables/useOverlayHistory.d.ts +45 -0
- package/dist/composables/useOverlayHistory.js +84 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +12 -8
- package/package.json +2 -1
- package/src/components/LpConfirmDialog.vue +5 -1
- package/src/components/LpDrawer.vue +21 -0
- package/src/components/LpModal.vue +21 -1
- package/src/components/LpShortcutsDialog.vue +5 -1
- package/src/components/LpTabs.vue +26 -2
- package/src/composables/overlayHistory.ts +403 -0
- package/src/composables/useOverlayHistory.ts +173 -0
- package/src/index.ts +3 -0
- package/dist/assets/LpTabs-CDchzoRL.css +0 -18
package/README.md
CHANGED
|
@@ -83,6 +83,53 @@ app.use(lpConfig({
|
|
|
83
83
|
|
|
84
84
|
A component's own `labels` prop wins over the configuration.
|
|
85
85
|
|
|
86
|
+
### Back and Forward for overlays
|
|
87
|
+
|
|
88
|
+
`provideOverlayHistory()` (at the app root, like `provideGlass()`) makes the
|
|
89
|
+
browser's Back button close overlays instead of leaving the page:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { provideOverlayHistory } from "@leavepulse/ui"
|
|
93
|
+
|
|
94
|
+
// in App.vue's setup; pass the router so a Back that only closes a dialog is not a navigation
|
|
95
|
+
provideOverlayHistory(true, { router })
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- Opening an `LpModal` or `LpDrawer` (and what is built on them:
|
|
99
|
+
`LpConfirmDialog`, `LpShortcutsDialog`) adds one history entry. Back closes
|
|
100
|
+
the topmost overlay; nested ones close one per press, top first.
|
|
101
|
+
- Closing through the UI (close button, Escape, the scrim, the app setting
|
|
102
|
+
`open` to false) takes the entry back out, so Back is never spent on a step
|
|
103
|
+
that shows nothing. A `guard` that keeps the overlay open on Back keeps its
|
|
104
|
+
entry too.
|
|
105
|
+
- `LpTabs` inside an open overlay record each switch: Back returns to the
|
|
106
|
+
previous tab before it closes the overlay. Page-level tabs stay out (an app
|
|
107
|
+
keeps those in its URL); `history` on `LpTabs` opts out inside an overlay or
|
|
108
|
+
in on a page without a router.
|
|
109
|
+
- Forward after Back does nothing by default: the step is undone at once, so
|
|
110
|
+
no dead entry is left. The kit only sees a boolean `open`, and what the app
|
|
111
|
+
put into the overlay may be gone by then. `history="reopen"` (or
|
|
112
|
+
`provideOverlayHistory("reopen")`) re-opens it on Forward by emitting
|
|
113
|
+
`update:open` true while the overlay is still mounted.
|
|
114
|
+
- `history` on a single overlay wins over the app-wide mode: `false` keeps an
|
|
115
|
+
overlay out of history, for one the app already opens from its route query
|
|
116
|
+
(it would otherwise take two entries for one dialog). An overlay the app
|
|
117
|
+
writes into the query with `router.replace` needs nothing: when it closes,
|
|
118
|
+
the address the app left is kept, and the overlay does not open again from
|
|
119
|
+
the entry under it.
|
|
120
|
+
- A real navigation (a link, `router.push` to another path) closes the open
|
|
121
|
+
overlays, and the entries they leave under the new page are skipped, so Back
|
|
122
|
+
from it lands on the page in one press. A push that keeps the path (a query
|
|
123
|
+
or hash, such as an overlay driven by the route query) leaves them open.
|
|
124
|
+
|
|
125
|
+
The URL never changes and the router's own `history.state` data is copied into
|
|
126
|
+
each entry. The `router` option is vue-router's instance (anything with a
|
|
127
|
+
`listening` switch works): without it the router sees each Back that closes an
|
|
128
|
+
overlay as a visit to the page it is already on (guards and `afterEach` run
|
|
129
|
+
again, nothing remounts). A Forward onto a kit entry still reaches it that
|
|
130
|
+
way, because the entry it starts from belongs to the router. Plain
|
|
131
|
+
`pushState` and `popstate` only, so WebKit (Safari, WebKitGTK) works too.
|
|
132
|
+
|
|
86
133
|
### Nuxt
|
|
87
134
|
|
|
88
135
|
```ts
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
/* Two columns where there is room: the list is long enough that one column
|
|
3
3
|
pushes the last group off a laptop screen. */
|
|
4
|
-
.shortcut-groups[data-v-
|
|
4
|
+
.shortcut-groups[data-v-f948ed00] {
|
|
5
5
|
display: grid;
|
|
6
6
|
gap: 18px;
|
|
7
7
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
8
8
|
}
|
|
9
|
-
.shortcut-group h3[data-v-
|
|
9
|
+
.shortcut-group h3[data-v-f948ed00] {
|
|
10
10
|
margin: 0 0 6px;
|
|
11
11
|
color: var(--color-muted);
|
|
12
12
|
font-size: 0.7rem;
|
|
@@ -14,25 +14,25 @@
|
|
|
14
14
|
letter-spacing: 0.06em;
|
|
15
15
|
text-transform: uppercase;
|
|
16
16
|
}
|
|
17
|
-
.shortcut-group dl[data-v-
|
|
17
|
+
.shortcut-group dl[data-v-f948ed00] {
|
|
18
18
|
display: flex;
|
|
19
19
|
flex-direction: column;
|
|
20
20
|
gap: 1px;
|
|
21
21
|
margin: 0;
|
|
22
22
|
}
|
|
23
|
-
.shortcut-row[data-v-
|
|
23
|
+
.shortcut-row[data-v-f948ed00] {
|
|
24
24
|
display: flex;
|
|
25
25
|
align-items: center;
|
|
26
26
|
justify-content: space-between;
|
|
27
27
|
gap: 12px;
|
|
28
28
|
padding: 5px 0;
|
|
29
29
|
}
|
|
30
|
-
.shortcut-row dt[data-v-
|
|
30
|
+
.shortcut-row dt[data-v-f948ed00] {
|
|
31
31
|
color: var(--color-ink);
|
|
32
32
|
font-size: 0.82rem;
|
|
33
33
|
min-width: 0;
|
|
34
34
|
}
|
|
35
|
-
.shortcut-conflict[data-v-
|
|
35
|
+
.shortcut-conflict[data-v-f948ed00] {
|
|
36
36
|
display: inline-flex;
|
|
37
37
|
width: 14px;
|
|
38
38
|
height: 14px;
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
vertical-align: middle;
|
|
48
48
|
cursor: help;
|
|
49
49
|
}
|
|
50
|
-
.shortcut-row dd[data-v-
|
|
50
|
+
.shortcut-row dd[data-v-f948ed00] {
|
|
51
51
|
display: flex;
|
|
52
52
|
flex-shrink: 0;
|
|
53
53
|
gap: 3px;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
.lp-tab-badge-enter-active[data-v-1d673b52],
|
|
3
|
+
.lp-tab-badge-leave-active[data-v-1d673b52] {
|
|
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-1d673b52],
|
|
9
|
+
.lp-tab-badge-leave-to[data-v-1d673b52] {
|
|
10
|
+
opacity: 0;
|
|
11
|
+
transform: scale(0.6);
|
|
12
|
+
}
|
|
13
|
+
@media (prefers-reduced-motion: reduce) {
|
|
14
|
+
.lp-tab-badge-enter-active[data-v-1d673b52],
|
|
15
|
+
.lp-tab-badge-leave-active[data-v-1d673b52] {
|
|
16
|
+
transition: none;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -7,7 +7,7 @@ import { _ as _sfc_main$3 } from "./LpButton-CFb44IjC.js";
|
|
|
7
7
|
import { _ as _sfc_main$1 } from "./LpFormField-Ch69Jd-X.js";
|
|
8
8
|
import { _ as _sfc_main$4 } from "./LpIcon--5WSb3jJ.js";
|
|
9
9
|
import { _ as _sfc_main$5 } from "./LpInput-Tw-yxT4I.js";
|
|
10
|
-
import { _ as _sfc_main$7 } from "./LpModal-
|
|
10
|
+
import { _ as _sfc_main$7 } from "./LpModal-C0tGg_D_.js";
|
|
11
11
|
import { _ as _sfc_main$6 } from "./LpSelect-Cxq4yBGd.js";
|
|
12
12
|
import { useFieldControl } from "../composables/useField.js";
|
|
13
13
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
@@ -7,7 +7,7 @@ import { _ as _sfc_main$3 } from "./LpButton-CFb44IjC.js";
|
|
|
7
7
|
import { _ as _sfc_main$4 } from "./LpIcon--5WSb3jJ.js";
|
|
8
8
|
import { _ as _sfc_main$6 } from "./LpScrollArea-Hz3-JWUG.js";
|
|
9
9
|
import { _ as _sfc_main$5 } from "./LpShift-CCq7dofl.js";
|
|
10
|
-
import { _ as _sfc_main$1 } from "./LpSidebar-
|
|
10
|
+
import { _ as _sfc_main$1 } from "./LpSidebar-D6zO8vLm.js";
|
|
11
11
|
import { useMergedAttrs, mergeClass } from "../composables/useMergedClass.js";
|
|
12
12
|
const _hoisted_1 = ["href"];
|
|
13
13
|
const _hoisted_2 = { class: "flex min-w-0 flex-1 flex-col" };
|
|
@@ -2,7 +2,7 @@ import { defineComponent, computed, ref, watch, openBlock, createBlock, createSl
|
|
|
2
2
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
3
3
|
import { _ as _sfc_main$2 } from "./LpButton-CFb44IjC.js";
|
|
4
4
|
import { _ as _sfc_main$3 } from "./LpIcon--5WSb3jJ.js";
|
|
5
|
-
import { _ as _sfc_main$1 } from "./LpModal-
|
|
5
|
+
import { _ as _sfc_main$1 } from "./LpModal-C0tGg_D_.js";
|
|
6
6
|
const _hoisted_1 = { class: "inline-flex items-center gap-2.5" };
|
|
7
7
|
const _hoisted_2 = {
|
|
8
8
|
key: 0,
|
|
@@ -23,6 +23,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
23
23
|
loadingLabel: {},
|
|
24
24
|
action: {},
|
|
25
25
|
glass: { type: Boolean, default: void 0 },
|
|
26
|
+
history: { type: [Boolean, String], default: void 0 },
|
|
26
27
|
labels: {}
|
|
27
28
|
},
|
|
28
29
|
emits: ["update:open", "confirm", "cancel"],
|
|
@@ -76,6 +77,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
76
77
|
return (_ctx, _cache) => {
|
|
77
78
|
return openBlock(), createBlock(_sfc_main$1, {
|
|
78
79
|
glass: __props.glass,
|
|
80
|
+
history: __props.history,
|
|
79
81
|
open: __props.open,
|
|
80
82
|
title: __props.title,
|
|
81
83
|
description: __props.description,
|
|
@@ -130,7 +132,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
130
132
|
]),
|
|
131
133
|
key: "0"
|
|
132
134
|
} : void 0
|
|
133
|
-
]), 1032, ["glass", "open", "title", "description"]);
|
|
135
|
+
]), 1032, ["glass", "history", "open", "title", "description"]);
|
|
134
136
|
};
|
|
135
137
|
}
|
|
136
138
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineComponent, computed, ref, watch, openBlock, createBlock, createCommentVNode } from "vue";
|
|
2
2
|
import { confirmQueue, settleConfirm } from "../components/confirm.js";
|
|
3
|
-
import { _ as _sfc_main$1 } from "./LpConfirmDialog-
|
|
3
|
+
import { _ as _sfc_main$1 } from "./LpConfirmDialog-CphJR6Q9.js";
|
|
4
4
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
5
5
|
__name: "LpConfirmHost",
|
|
6
6
|
props: {
|
|
@@ -4,6 +4,7 @@ import { CLOSE_ICON } from "../components/dropdown.js";
|
|
|
4
4
|
import { prefersReducedMotion } from "../composables/easing.js";
|
|
5
5
|
import { useCloseGuard } from "../composables/useCloseGuard.js";
|
|
6
6
|
import { useGlass } from "../composables/useGlass.js";
|
|
7
|
+
import { useOverlayHistory } from "../composables/useOverlayHistory.js";
|
|
7
8
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
8
9
|
import { usePersisted } from "../composables/usePersisted.js";
|
|
9
10
|
import { _ as _sfc_main$1 } from "./LpIcon--5WSb3jJ.js";
|
|
@@ -48,6 +49,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
48
49
|
guard: { type: [Boolean, Function] },
|
|
49
50
|
glass: { type: Boolean, default: void 0 },
|
|
50
51
|
ariaLabel: {},
|
|
52
|
+
history: { type: [Boolean, String], default: void 0 },
|
|
51
53
|
labels: {}
|
|
52
54
|
},
|
|
53
55
|
emits: ["update:open"],
|
|
@@ -87,6 +89,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
87
89
|
if (await allowClose()) emit("update:open", false);
|
|
88
90
|
}
|
|
89
91
|
__expose({ close: requestClose });
|
|
92
|
+
useOverlayHistory({
|
|
93
|
+
mode: () => props.history,
|
|
94
|
+
open: () => !!props.open,
|
|
95
|
+
close: async () => {
|
|
96
|
+
if (!await allowClose()) return false;
|
|
97
|
+
emit("update:open", false);
|
|
98
|
+
return true;
|
|
99
|
+
},
|
|
100
|
+
reopen: () => emit("update:open", true),
|
|
101
|
+
navigated: () => emit("update:open", false)
|
|
102
|
+
});
|
|
90
103
|
function guardClose(event) {
|
|
91
104
|
if (!armed()) return;
|
|
92
105
|
event.preventDefault();
|
|
@@ -2,6 +2,7 @@ import { defineComponent, ref, computed, useSlots, watch, onBeforeUnmount, openB
|
|
|
2
2
|
import { DialogRoot, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription, DialogClose } from "reka-ui";
|
|
3
3
|
import { useCloseGuard } from "../composables/useCloseGuard.js";
|
|
4
4
|
import { useGlass } from "../composables/useGlass.js";
|
|
5
|
+
import { useOverlayHistory } from "../composables/useOverlayHistory.js";
|
|
5
6
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
6
7
|
import { useShift } from "../composables/useShift.js";
|
|
7
8
|
import { useModalLayer } from "../components/modalDepth.js";
|
|
@@ -47,6 +48,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
47
48
|
role: {},
|
|
48
49
|
dismissible: { type: Boolean, default: true },
|
|
49
50
|
guard: { type: [Boolean, Function], default: void 0 },
|
|
51
|
+
history: { type: [Boolean, String], default: void 0 },
|
|
50
52
|
labels: {}
|
|
51
53
|
},
|
|
52
54
|
emits: ["update:open"],
|
|
@@ -64,6 +66,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
64
66
|
function close() {
|
|
65
67
|
void onOpenChange(false);
|
|
66
68
|
}
|
|
69
|
+
useOverlayHistory({
|
|
70
|
+
mode: () => props.history,
|
|
71
|
+
open: () => !!props.open,
|
|
72
|
+
close: async () => {
|
|
73
|
+
if (!await allowClose()) return false;
|
|
74
|
+
emit("update:open", false);
|
|
75
|
+
return true;
|
|
76
|
+
},
|
|
77
|
+
reopen: () => emit("update:open", true),
|
|
78
|
+
navigated: () => emit("update:open", false)
|
|
79
|
+
});
|
|
67
80
|
__expose({ close });
|
|
68
81
|
function onEscape(event) {
|
|
69
82
|
guardOutside(event);
|
|
@@ -3,8 +3,8 @@ import { useGlass } from "../composables/useGlass.js";
|
|
|
3
3
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
4
4
|
import { _ as _sfc_main$2 } from "./LpButton-CFb44IjC.js";
|
|
5
5
|
import { _ as _sfc_main$3 } from "./LpIcon--5WSb3jJ.js";
|
|
6
|
-
import { _ as _sfc_main$1 } from "./LpModal-
|
|
7
|
-
import { _ as _sfc_main$4 } from "./LpSidebar-
|
|
6
|
+
import { _ as _sfc_main$1 } from "./LpModal-C0tGg_D_.js";
|
|
7
|
+
import { _ as _sfc_main$4 } from "./LpSidebar-D6zO8vLm.js";
|
|
8
8
|
const _hoisted_1 = { class: "flex items-center gap-2" };
|
|
9
9
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
10
10
|
__name: "LpModalNav",
|
|
@@ -2,7 +2,7 @@ import { defineComponent, computed, ref, useId, openBlock, createElementBlock, F
|
|
|
2
2
|
import { useHotkeys, parseCombo } from "../composables/useHotkeys.js";
|
|
3
3
|
import { usePersisted } from "../composables/usePersisted.js";
|
|
4
4
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
5
|
-
import { _ as _sfc_main$5 } from "./LpDrawer-
|
|
5
|
+
import { _ as _sfc_main$5 } from "./LpDrawer-DQZixOqJ.js";
|
|
6
6
|
import { _ as _sfc_main$2 } from "./LpIcon--5WSb3jJ.js";
|
|
7
7
|
import { _ as _sfc_main$3 } from "./LpInput-Tw-yxT4I.js";
|
|
8
8
|
import { _ as _sfc_main$1 } from "./LpTooltip-BcBvIx4z.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OverlayHistoryMode } from "../composables/useOverlayHistory";
|
|
1
2
|
export type ConfirmLabels = {
|
|
2
3
|
confirm: string;
|
|
3
4
|
cancel: string;
|
|
@@ -44,6 +45,8 @@ type __VLS_Props = {
|
|
|
44
45
|
action?: () => unknown;
|
|
45
46
|
/** Frosted glass panel, passed to LpModal. Follows `provideGlass` when unset. */
|
|
46
47
|
glass?: boolean;
|
|
48
|
+
/** Browser history for the dialog, passed to LpModal. Follows `provideOverlayHistory` when unset. */
|
|
49
|
+
history?: OverlayHistoryMode;
|
|
47
50
|
labels?: Partial<ConfirmLabels>;
|
|
48
51
|
};
|
|
49
52
|
declare var __VLS_16: {};
|
|
@@ -59,6 +62,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
59
62
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
60
63
|
onConfirm?: (() => any) | undefined;
|
|
61
64
|
}>, {
|
|
65
|
+
history: OverlayHistoryMode;
|
|
62
66
|
glass: boolean;
|
|
63
67
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
64
68
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CloseGuard } from "../composables/useCloseGuard";
|
|
2
|
+
import { type OverlayHistoryMode } from "../composables/useOverlayHistory";
|
|
2
3
|
declare const _default: typeof __VLS_export;
|
|
3
4
|
export default _default;
|
|
4
5
|
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
@@ -86,6 +87,13 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
|
86
87
|
glass?: boolean;
|
|
87
88
|
/** Accessible name for a drawer without a visible `title`. */
|
|
88
89
|
ariaLabel?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Browser Back closes it, and opening it adds a history entry. Unset
|
|
92
|
+
* follows `provideOverlayHistory` (off without one); `"reopen"` also
|
|
93
|
+
* opens it again on Forward; `false` keeps it out of history, for an
|
|
94
|
+
* overlay the app already drives from its route.
|
|
95
|
+
*/
|
|
96
|
+
history?: OverlayHistoryMode;
|
|
89
97
|
labels?: Partial<{
|
|
90
98
|
close: string;
|
|
91
99
|
}>;
|
|
@@ -178,12 +186,20 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
|
178
186
|
glass?: boolean;
|
|
179
187
|
/** Accessible name for a drawer without a visible `title`. */
|
|
180
188
|
ariaLabel?: string;
|
|
189
|
+
/**
|
|
190
|
+
* Browser Back closes it, and opening it adds a history entry. Unset
|
|
191
|
+
* follows `provideOverlayHistory` (off without one); `"reopen"` also
|
|
192
|
+
* opens it again on Forward; `false` keeps it out of history, for an
|
|
193
|
+
* overlay the app already drives from its route.
|
|
194
|
+
*/
|
|
195
|
+
history?: OverlayHistoryMode;
|
|
181
196
|
labels?: Partial<{
|
|
182
197
|
close: string;
|
|
183
198
|
}>;
|
|
184
199
|
}> & Readonly<{
|
|
185
200
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
186
201
|
}>, {
|
|
202
|
+
history: OverlayHistoryMode;
|
|
187
203
|
size: "sm" | "md" | "lg" | "xl";
|
|
188
204
|
side: "left" | "right";
|
|
189
205
|
glass: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CloseGuard } from "../composables/useCloseGuard";
|
|
2
|
+
import { type OverlayHistoryMode } from "../composables/useOverlayHistory";
|
|
2
3
|
type __VLS_Props = {
|
|
3
4
|
open?: boolean;
|
|
4
5
|
title?: string;
|
|
@@ -52,6 +53,13 @@ type __VLS_Props = {
|
|
|
52
53
|
* form's state, `:guard="form.dirty"`. See `useCloseGuard`.
|
|
53
54
|
*/
|
|
54
55
|
guard?: CloseGuard;
|
|
56
|
+
/**
|
|
57
|
+
* Browser Back closes it, and opening it adds a history entry. Unset
|
|
58
|
+
* follows `provideOverlayHistory` (off without one); `"reopen"` also
|
|
59
|
+
* opens it again on Forward; `false` keeps it out of history, for an
|
|
60
|
+
* overlay the app already drives from its route.
|
|
61
|
+
*/
|
|
62
|
+
history?: OverlayHistoryMode;
|
|
55
63
|
labels?: Partial<{
|
|
56
64
|
close: string;
|
|
57
65
|
}>;
|
|
@@ -91,6 +99,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
91
99
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
92
100
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
93
101
|
}>, {
|
|
102
|
+
history: OverlayHistoryMode;
|
|
94
103
|
size: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "full";
|
|
95
104
|
autoFocus: "auto" | "none" | string;
|
|
96
105
|
glass: boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OverlayHistoryMode } from "../composables/useOverlayHistory";
|
|
1
2
|
import { type ShortcutGroup } from "../composables/useHotkeys";
|
|
2
3
|
type __VLS_Props = {
|
|
3
4
|
open?: boolean;
|
|
@@ -8,6 +9,8 @@ type __VLS_Props = {
|
|
|
8
9
|
description?: string;
|
|
9
10
|
/** Frosted glass panel, passed to LpModal. Follows `provideGlass` when unset. */
|
|
10
11
|
glass?: boolean;
|
|
12
|
+
/** Browser history for the dialog, passed to LpModal. Follows `provideOverlayHistory` when unset. */
|
|
13
|
+
history?: OverlayHistoryMode;
|
|
11
14
|
/**
|
|
12
15
|
* A key that toggles the reference, e.g. "F1". Bound only while the dialog
|
|
13
16
|
* is mounted, also inside inputs and over other overlays, and the browser's
|
|
@@ -20,6 +23,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
20
23
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
21
24
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
22
25
|
}>, {
|
|
26
|
+
history: OverlayHistoryMode;
|
|
23
27
|
title: string;
|
|
24
28
|
open: boolean;
|
|
25
29
|
glass: boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineComponent, computed, openBlock, createBlock, unref, withCtx, createElementVNode, createElementBlock, Fragment, renderList, toDisplayString, createTextVNode, createCommentVNode, createVNode } from "vue";
|
|
2
2
|
import LpKeys from "./LpKeys.vue.js";
|
|
3
|
-
import { _ as _sfc_main$1 } from "../chunks/LpModal-
|
|
3
|
+
import { _ as _sfc_main$1 } from "../chunks/LpModal-C0tGg_D_.js";
|
|
4
4
|
import { mergeShortcutGroups, activeShortcuts, useHotkeys } from "../composables/useHotkeys.js";
|
|
5
5
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
6
6
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
7
|
-
import '../assets/LpShortcutsDialog-
|
|
7
|
+
import '../assets/LpShortcutsDialog-C6uzPeMf.css';const _hoisted_1 = { class: "shortcut-groups" };
|
|
8
8
|
const _hoisted_2 = ["aria-label", "title"];
|
|
9
9
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
10
10
|
__name: "LpShortcutsDialog",
|
|
@@ -15,6 +15,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
15
15
|
title: { default: void 0 },
|
|
16
16
|
description: {},
|
|
17
17
|
glass: { type: Boolean, default: void 0 },
|
|
18
|
+
history: { type: [Boolean, String], default: void 0 },
|
|
18
19
|
hotkey: {}
|
|
19
20
|
},
|
|
20
21
|
emits: ["update:open"],
|
|
@@ -42,6 +43,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
42
43
|
return (_ctx, _cache) => {
|
|
43
44
|
return openBlock(), createBlock(_sfc_main$1, {
|
|
44
45
|
glass: props.glass,
|
|
46
|
+
history: props.history,
|
|
45
47
|
open: props.open,
|
|
46
48
|
size: "lg",
|
|
47
49
|
title: props.title ?? unref(text).title,
|
|
@@ -85,11 +87,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
85
87
|
])
|
|
86
88
|
]),
|
|
87
89
|
_: 1
|
|
88
|
-
}, 8, ["glass", "open", "title", "description"]);
|
|
90
|
+
}, 8, ["glass", "history", "open", "title", "description"]);
|
|
89
91
|
};
|
|
90
92
|
}
|
|
91
93
|
});
|
|
92
|
-
const LpShortcutsDialog = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
94
|
+
const LpShortcutsDialog = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f948ed00"]]);
|
|
93
95
|
export {
|
|
94
96
|
LpShortcutsDialog as default
|
|
95
97
|
};
|
|
@@ -52,6 +52,14 @@ type __VLS_Props = {
|
|
|
52
52
|
* icon keep their label.
|
|
53
53
|
*/
|
|
54
54
|
compact?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Record each switch as a browser history entry, so Back returns to the
|
|
57
|
+
* previous tab. Unset follows the overlay the tabs sit in (a modal or a
|
|
58
|
+
* drawer with history on, see `provideOverlayHistory`) and is off
|
|
59
|
+
* elsewhere: a page's own tabs belong in its URL. `false` opts out inside
|
|
60
|
+
* an overlay, `true` opts in on a page that keeps no URL of its own.
|
|
61
|
+
*/
|
|
62
|
+
history?: boolean;
|
|
55
63
|
};
|
|
56
64
|
declare var __VLS_67: {
|
|
57
65
|
value: string;
|
|
@@ -66,6 +74,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
66
74
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
67
75
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
68
76
|
}>, {
|
|
77
|
+
history: boolean;
|
|
69
78
|
block: boolean;
|
|
70
79
|
variant: "contained" | "plain" | "underline" | "bottom";
|
|
71
80
|
accent: boolean;
|
|
@@ -3,13 +3,14 @@ import { usePaletteScope, usePaletteCommands } from "../composables/usePaletteCo
|
|
|
3
3
|
import { Motion } from "motion-v";
|
|
4
4
|
import { TabsRoot, TabsList, TabsTrigger, TabsContent } from "reka-ui";
|
|
5
5
|
import { usePillTransition } from "../composables/usePillTransition.js";
|
|
6
|
+
import { useStepHistory } from "../composables/useOverlayHistory.js";
|
|
6
7
|
import { prefersReducedMotion } from "../composables/easing.js";
|
|
7
8
|
import { _ as _sfc_main$1 } from "../chunks/LpContextMenu-rx2tCjwk.js";
|
|
8
9
|
import { _ as _sfc_main$3 } from "../chunks/LpSkeleton-BB6XIV-w.js";
|
|
9
10
|
import { _ as _sfc_main$2 } from "../chunks/LpTabFace-DPCwKkH2.js";
|
|
10
11
|
import { pickTab, BOTTOM_BAR, BOTTOM_ITEM, BOTTOM_MARKER } from "./tabs.js";
|
|
11
12
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
12
|
-
import '../assets/LpTabs-
|
|
13
|
+
import '../assets/LpTabs-CJ0rYQbx.css';const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
13
14
|
__name: "LpTabs",
|
|
14
15
|
props: {
|
|
15
16
|
modelValue: {},
|
|
@@ -20,7 +21,8 @@ import '../assets/LpTabs-CDchzoRL.css';const _sfc_main = /* @__PURE__ */ defineC
|
|
|
20
21
|
block: { type: Boolean, default: false },
|
|
21
22
|
label: {},
|
|
22
23
|
hoverFollow: { type: Boolean, default: true },
|
|
23
|
-
compact: { type: Boolean, default: false }
|
|
24
|
+
compact: { type: Boolean, default: false },
|
|
25
|
+
history: { type: Boolean, default: void 0 }
|
|
24
26
|
},
|
|
25
27
|
emits: ["update:modelValue"],
|
|
26
28
|
setup(__props, { emit: __emit }) {
|
|
@@ -54,10 +56,22 @@ import '../assets/LpTabs-CDchzoRL.css';const _sfc_main = /* @__PURE__ */ defineC
|
|
|
54
56
|
row.scrollTo({ left, behavior: prefersReducedMotion() ? "auto" : "smooth" });
|
|
55
57
|
});
|
|
56
58
|
});
|
|
57
|
-
function
|
|
59
|
+
function show(value) {
|
|
58
60
|
if (props.modelValue === void 0) current.value = value;
|
|
59
61
|
emit("update:modelValue", value);
|
|
60
62
|
}
|
|
63
|
+
const { record } = useStepHistory({
|
|
64
|
+
mode: () => props.history,
|
|
65
|
+
set: show,
|
|
66
|
+
has: (value) => props.items.some((item) => item.value === value && !item.disabled)
|
|
67
|
+
});
|
|
68
|
+
function select(value) {
|
|
69
|
+
const from = current.value;
|
|
70
|
+
show(value);
|
|
71
|
+
void nextTick(() => {
|
|
72
|
+
if (from !== void 0 && current.value === value) record(from, value);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
61
75
|
const pillId = `lp-tab-indicator-${useId()}`;
|
|
62
76
|
const hovered = ref(null);
|
|
63
77
|
const pillTransition = usePillTransition();
|
|
@@ -195,7 +209,7 @@ import '../assets/LpTabs-CDchzoRL.css';const _sfc_main = /* @__PURE__ */ defineC
|
|
|
195
209
|
};
|
|
196
210
|
}
|
|
197
211
|
});
|
|
198
|
-
const LpTabs = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
212
|
+
const LpTabs = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-1d673b52"]]);
|
|
199
213
|
export {
|
|
200
214
|
LpTabs as default
|
|
201
215
|
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface HistoryEntry {
|
|
2
|
+
/** Back left this entry: undo what it recorded (close the overlay, restore the tab). */
|
|
3
|
+
back: () => void;
|
|
4
|
+
/** Forward came back to it: redo it, and say whether that happened. */
|
|
5
|
+
forward?: () => boolean;
|
|
6
|
+
/** The page moved on to another path while this entry was live. */
|
|
7
|
+
navigated?: () => void;
|
|
8
|
+
/** The component that pushed it is still mounted. */
|
|
9
|
+
alive: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* What the kit needs of a router: vue-router's `listening` switch, or the same
|
|
13
|
+
* flag on any router that skips its popstate handling while it is false.
|
|
14
|
+
*/
|
|
15
|
+
export interface HistoryRouter {
|
|
16
|
+
listening: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** The app's router, told not to listen while a step only concerns the kit. */
|
|
19
|
+
export declare function setHistoryRouter(router: HistoryRouter | null): void;
|
|
20
|
+
/** Record an entry on top of the history, under the current address. */
|
|
21
|
+
export declare function pushEntry(entry: HistoryEntry): void;
|
|
22
|
+
/**
|
|
23
|
+
* The thing behind an entry ended without Back (a close button, Escape, the
|
|
24
|
+
* app setting `open` to false, an unmount): take the entry and everything
|
|
25
|
+
* pushed above it out of history, so Back is never spent on a dead step.
|
|
26
|
+
* When the page is not sitting on the kit's entries (another push came on top),
|
|
27
|
+
* the entry stays in place and is skipped when Back or Forward lands on it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function dropEntry(entry: HistoryEntry): void;
|
|
30
|
+
/** Whether the entry is live: pushed and not yet popped or dropped. */
|
|
31
|
+
export declare function isLive(entry: HistoryEntry): boolean;
|
|
32
|
+
/** Live entries, bottom first. For tests and devtools. */
|
|
33
|
+
export declare function liveEntries(): number;
|