@leavepulse/ui 0.80.1 → 0.81.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/assets/{LpCommandPalette-C1LRFzbN.css → LpCommandPalette-DCZB4EAf.css} +19 -19
- package/dist/chunks/{LpAppShell-InIK01Nn.js → LpAppShell-BBINfN1v.js} +1 -1
- package/dist/chunks/{LpPageScrollbar-D2O0xhJw.js → LpPageScrollbar-C9sTeU-2.js} +3 -8
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +4 -3
- package/dist/components/LpPageScrollbar.vue.js +1 -1
- package/dist/composables/overlayHistory.js +16 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/src/components/LpCommandPalette.vue +5 -0
- package/src/components/LpPageScrollbar.vue +13 -11
- package/src/composables/overlayHistory.ts +29 -2
|
@@ -5,34 +5,34 @@
|
|
|
5
5
|
* pane from its right edge as it grows. Animating the columns themselves made
|
|
6
6
|
* every line of the list and the pane re-wrap on every frame.
|
|
7
7
|
*/
|
|
8
|
-
.lp-cmd-dialog[data-v-
|
|
8
|
+
.lp-cmd-dialog[data-v-b72dc3e1] {
|
|
9
9
|
--lp-cmd-list: min(92vw, 40rem);
|
|
10
10
|
--lp-cmd-pane: max(0px, min(26rem, 96vw - var(--lp-cmd-list)));
|
|
11
11
|
width: var(--lp-cmd-list);
|
|
12
12
|
}
|
|
13
|
-
.lp-cmd-split[data-v-
|
|
13
|
+
.lp-cmd-split[data-v-b72dc3e1] {
|
|
14
14
|
transition:
|
|
15
15
|
width 300ms var(--ease-emphasized, ease),
|
|
16
16
|
min-height 300ms var(--ease-emphasized, ease);
|
|
17
17
|
}
|
|
18
18
|
@media (min-width: 768px) {
|
|
19
|
-
.lp-cmd-split .lp-cmd-list[data-v-
|
|
19
|
+
.lp-cmd-split .lp-cmd-list[data-v-b72dc3e1] {
|
|
20
20
|
flex: 0 0 auto;
|
|
21
21
|
/* the dialog's 1px border on each side */
|
|
22
22
|
width: calc(var(--lp-cmd-list) - 2px);
|
|
23
23
|
}
|
|
24
|
-
.lp-cmd-dialog[data-pane="open"][data-v-
|
|
24
|
+
.lp-cmd-dialog[data-pane="open"][data-v-b72dc3e1] {
|
|
25
25
|
width: calc(var(--lp-cmd-list) + var(--lp-cmd-pane));
|
|
26
26
|
min-height: min(76vh, 36rem);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
.lp-cmd-pane[data-v-
|
|
29
|
+
.lp-cmd-pane[data-v-b72dc3e1] {
|
|
30
30
|
width: var(--lp-cmd-pane);
|
|
31
31
|
}
|
|
32
|
-
.lp-cmd-dialog[data-editing] .lp-cmd-pane[data-v-
|
|
32
|
+
.lp-cmd-dialog[data-editing] .lp-cmd-pane[data-v-b72dc3e1] {
|
|
33
33
|
width: 100%;
|
|
34
34
|
}
|
|
35
|
-
.lp-cmd-dialog[data-editing][data-v-
|
|
35
|
+
.lp-cmd-dialog[data-editing][data-v-b72dc3e1] {
|
|
36
36
|
width: var(--lp-cmd-list);
|
|
37
37
|
min-height: 0;
|
|
38
38
|
}
|
|
@@ -40,43 +40,43 @@
|
|
|
40
40
|
* The pane rides in from the right edge while the dialog opens up to it, and
|
|
41
41
|
* leaves the same way, for as long as the dialog takes to close over it.
|
|
42
42
|
*/
|
|
43
|
-
.lp-cmd-pane-enter-active[data-v-
|
|
44
|
-
.lp-cmd-pane-leave-active[data-v-
|
|
43
|
+
.lp-cmd-pane-enter-active[data-v-b72dc3e1],
|
|
44
|
+
.lp-cmd-pane-leave-active[data-v-b72dc3e1] {
|
|
45
45
|
transition:
|
|
46
46
|
transform 300ms var(--ease-emphasized, ease),
|
|
47
47
|
opacity 300ms ease;
|
|
48
48
|
}
|
|
49
|
-
.lp-cmd-pane-enter-from[data-v-
|
|
50
|
-
.lp-cmd-pane-leave-to[data-v-
|
|
49
|
+
.lp-cmd-pane-enter-from[data-v-b72dc3e1],
|
|
50
|
+
.lp-cmd-pane-leave-to[data-v-b72dc3e1] {
|
|
51
51
|
opacity: 0;
|
|
52
52
|
transform: translateX(40%);
|
|
53
53
|
}
|
|
54
|
-
.lp-cmd-para[data-v-
|
|
54
|
+
.lp-cmd-para[data-v-b72dc3e1] {
|
|
55
55
|
--rise: 4px;
|
|
56
56
|
animation: rise-in 260ms ease-out both;
|
|
57
57
|
}
|
|
58
58
|
@media (prefers-reduced-motion: reduce) {
|
|
59
|
-
.lp-cmd-split[data-v-
|
|
60
|
-
.lp-cmd-pane-enter-active[data-v-
|
|
61
|
-
.lp-cmd-pane-leave-active[data-v-
|
|
59
|
+
.lp-cmd-split[data-v-b72dc3e1],
|
|
60
|
+
.lp-cmd-pane-enter-active[data-v-b72dc3e1],
|
|
61
|
+
.lp-cmd-pane-leave-active[data-v-b72dc3e1] {
|
|
62
62
|
transition: none;
|
|
63
63
|
}
|
|
64
|
-
.lp-cmd-para[data-v-
|
|
64
|
+
.lp-cmd-para[data-v-b72dc3e1] {
|
|
65
65
|
animation: none;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
.lp-cmd-excerpt[data-v-
|
|
68
|
+
.lp-cmd-excerpt[data-v-b72dc3e1] {
|
|
69
69
|
display: -webkit-box;
|
|
70
70
|
-webkit-box-orient: vertical;
|
|
71
71
|
overflow: hidden;
|
|
72
72
|
}
|
|
73
73
|
/* Each result eases in; honours reduced motion. */
|
|
74
|
-
.lp-cmd-item[data-v-
|
|
74
|
+
.lp-cmd-item[data-v-b72dc3e1] {
|
|
75
75
|
--rise: 3px;
|
|
76
76
|
animation: rise-in 140ms ease-out both;
|
|
77
77
|
}
|
|
78
78
|
@media (prefers-reduced-motion: reduce) {
|
|
79
|
-
.lp-cmd-item[data-v-
|
|
79
|
+
.lp-cmd-item[data-v-b72dc3e1] {
|
|
80
80
|
animation: none;
|
|
81
81
|
}
|
|
82
82
|
}
|
|
@@ -10,7 +10,7 @@ import { _ as _sfc_main$9 } from "./LpBottomNav-4I89sPDZ.js";
|
|
|
10
10
|
import { _ as _sfc_main$2 } from "./LpContextSwitcher-CGr6ZAuq.js";
|
|
11
11
|
import { _ as _sfc_main$3 } from "./LpButton-DSHioIfD.js";
|
|
12
12
|
import { _ as _sfc_main$4 } from "./LpIcon-BCQLuHSP.js";
|
|
13
|
-
import { _ as _sfc_main$8 } from "./LpPageScrollbar-
|
|
13
|
+
import { _ as _sfc_main$8 } from "./LpPageScrollbar-C9sTeU-2.js";
|
|
14
14
|
import { _ as _sfc_main$7 } from "./LpScrollArea-CqvwfZs2.js";
|
|
15
15
|
import { _ as _sfc_main$5 } from "./LpShift-DAgS_d2x.js";
|
|
16
16
|
import { _ as _sfc_main$1 } from "./LpSidebar-D3S8rYFf.js";
|
|
@@ -29,13 +29,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
29
29
|
function scroller() {
|
|
30
30
|
return doc?.scrollingElement ?? null;
|
|
31
31
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
probe.style.cssText = "position:absolute;top:-9999px;width:100px;height:100px;overflow:scroll";
|
|
35
|
-
d.body.append(probe);
|
|
36
|
-
const width = probe.offsetWidth - probe.clientWidth;
|
|
37
|
-
probe.remove();
|
|
38
|
-
return width;
|
|
32
|
+
function finePointer(d) {
|
|
33
|
+
return nodeWindow(d).matchMedia?.("(pointer: fine)").matches ?? false;
|
|
39
34
|
}
|
|
40
35
|
function measure() {
|
|
41
36
|
frame = 0;
|
|
@@ -107,7 +102,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
107
102
|
onMounted(() => {
|
|
108
103
|
const host = barEl.value ?? void 0;
|
|
109
104
|
doc = host?.ownerDocument;
|
|
110
|
-
if (!doc ||
|
|
105
|
+
if (!doc || !finePointer(doc)) return;
|
|
111
106
|
active.value = true;
|
|
112
107
|
releaseNative = hideNativeBar(doc);
|
|
113
108
|
const win = nodeWindow(doc);
|
|
@@ -26,7 +26,7 @@ import { parsePaletteQuery, parseCommandQuery, searchCommandItems, applyQueryFil
|
|
|
26
26
|
import { PALETTE_MODES, modeChipLabel, settleFetched, fallbackRows, readRecent, resolveRecentItems, recentVisible, commandHasPreview, matchModePrefix, isSafeHref, absoluteHref, commandKey, recentKey, pushRecent, moreRowId, toRecentItem } from "./commandPalette.js";
|
|
27
27
|
import { useView, usePortalTarget, useOutsideGuard, viewWindow } from "../composables/useView.js";
|
|
28
28
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
29
|
-
import '../assets/LpCommandPalette-
|
|
29
|
+
import '../assets/LpCommandPalette-DCZB4EAf.css';const _hoisted_1 = { class: "relative flex shrink-0 items-center gap-2.5 border-b border-line px-4" };
|
|
30
30
|
const _hoisted_2 = ["title", "onClick"];
|
|
31
31
|
const _hoisted_3 = ["readonly", "aria-label", "aria-expanded", "aria-controls", "aria-activedescendant", "placeholder", "onKeydown"];
|
|
32
32
|
const _hoisted_4 = { class: "shrink-0 rounded-small border border-line px-1.5 py-0.5 text-[10px] text-muted" };
|
|
@@ -1091,6 +1091,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1091
1091
|
type: linkOf(c) ? void 0 : "button",
|
|
1092
1092
|
role: "option",
|
|
1093
1093
|
tabindex: "-1",
|
|
1094
|
+
"aria-label": c.description ? `${c.label} ${c.description}` : c.label,
|
|
1094
1095
|
"aria-selected": flatIndexOf(c) === selectedIndex.value,
|
|
1095
1096
|
"aria-disabled": c.disabled || void 0,
|
|
1096
1097
|
"data-cmd-index": flatIndexOf(c),
|
|
@@ -1169,7 +1170,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1169
1170
|
})) : createCommentVNode("", true)
|
|
1170
1171
|
]),
|
|
1171
1172
|
_: 2
|
|
1172
|
-
}, 1064, ["id", "href", "type", "aria-selected", "aria-disabled", "data-cmd-index", "disabled", "class", "onClick", "onPointerenter"]);
|
|
1173
|
+
}, 1064, ["id", "href", "type", "aria-label", "aria-selected", "aria-disabled", "data-cmd-index", "disabled", "class", "onClick", "onPointerenter"]);
|
|
1173
1174
|
}), 128))
|
|
1174
1175
|
], 8, _hoisted_12);
|
|
1175
1176
|
}), 128))
|
|
@@ -1363,7 +1364,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1363
1364
|
};
|
|
1364
1365
|
}
|
|
1365
1366
|
});
|
|
1366
|
-
const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
1367
|
+
const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-b72dc3e1"]]);
|
|
1367
1368
|
export {
|
|
1368
1369
|
LpCommandPalette as default
|
|
1369
1370
|
};
|
|
@@ -205,7 +205,7 @@ function install() {
|
|
|
205
205
|
window.addEventListener("popstate", afterPop);
|
|
206
206
|
const push = history.pushState.bind(history);
|
|
207
207
|
const replace = history.replaceState.bind(history);
|
|
208
|
-
|
|
208
|
+
const pushed = (data, unused, url) => {
|
|
209
209
|
const before = location.href;
|
|
210
210
|
push(data, unused, url);
|
|
211
211
|
s.href = location.href;
|
|
@@ -214,12 +214,26 @@ function install() {
|
|
|
214
214
|
if (pathOf(before) !== pathOf(location.href)) leavePage();
|
|
215
215
|
mute();
|
|
216
216
|
};
|
|
217
|
-
|
|
217
|
+
const replaced = (data, unused, url) => {
|
|
218
218
|
const mark = s.internal ? null : current();
|
|
219
219
|
const keep = mark && data && typeof data === "object" && !markOf(data) ? { ...data, [KEY]: mark } : data;
|
|
220
220
|
replace(keep, unused, url);
|
|
221
221
|
s.href = location.href;
|
|
222
222
|
};
|
|
223
|
+
history.pushState = function(data, unused, url) {
|
|
224
|
+
if (!s.internal && s.silent > 0) s.waiting.push(() => pushed(unmarked(data), unused, url));
|
|
225
|
+
else pushed(data, unused, url);
|
|
226
|
+
};
|
|
227
|
+
history.replaceState = function(data, unused, url) {
|
|
228
|
+
if (!s.internal && s.silent > 0) s.waiting.push(() => replaced(unmarked(data), unused, url));
|
|
229
|
+
else replaced(data, unused, url);
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function unmarked(data) {
|
|
233
|
+
if (!markOf(data)) return data;
|
|
234
|
+
const copy = { ...data };
|
|
235
|
+
delete copy[KEY];
|
|
236
|
+
return copy;
|
|
223
237
|
}
|
|
224
238
|
function pushEntry(entry) {
|
|
225
239
|
if (typeof window === "undefined") return;
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { _ as _3 } from "./chunks/LpMapPicker-DW2EnrCJ.js";
|
|
|
4
4
|
import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
|
|
5
5
|
import { _ as _4 } from "./chunks/LpActionBar-C7g52Cyo.js";
|
|
6
6
|
import { _ as _5 } from "./chunks/LpAlert-DWFeR82L.js";
|
|
7
|
-
import { _ as _6 } from "./chunks/LpAppShell-
|
|
7
|
+
import { _ as _6 } from "./chunks/LpAppShell-BBINfN1v.js";
|
|
8
8
|
import { _ as _7 } from "./chunks/LpAutocomplete-DY3LvpB9.js";
|
|
9
9
|
import { _ as _8 } from "./chunks/LpAvatar-CEZmMcGh.js";
|
|
10
10
|
import { _ as _9 } from "./chunks/LpBadge-C_VqLHtg.js";
|
|
@@ -83,7 +83,7 @@ import { _ as _54 } from "./chunks/LpRadio-CWA5Eb3M.js";
|
|
|
83
83
|
import { _ as _55 } from "./chunks/LpRadioGroup-E3SP6j9h.js";
|
|
84
84
|
import { _ as _56 } from "./chunks/LpRollingText-B54Pje7P.js";
|
|
85
85
|
import { _ as _57 } from "./chunks/LpScrollArea-CqvwfZs2.js";
|
|
86
|
-
import { _ as _58 } from "./chunks/LpPageScrollbar-
|
|
86
|
+
import { _ as _58 } from "./chunks/LpPageScrollbar-C9sTeU-2.js";
|
|
87
87
|
import { _ as _59 } from "./chunks/LpSegmented-DjvrHL_G.js";
|
|
88
88
|
import { _ as _60 } from "./chunks/LpSection-CghNNxIv.js";
|
|
89
89
|
import { _ as _61 } from "./chunks/LpSelect-DYPimzAZ.js";
|
package/package.json
CHANGED
|
@@ -1696,6 +1696,7 @@ const guardOutside = useOutsideGuard()
|
|
|
1696
1696
|
:type="linkOf(c) ? undefined : 'button'"
|
|
1697
1697
|
role="option"
|
|
1698
1698
|
tabindex="-1"
|
|
1699
|
+
:aria-label="c.description ? `${c.label} ${c.description}` : c.label"
|
|
1699
1700
|
:aria-selected="flatIndexOf(c) === selectedIndex"
|
|
1700
1701
|
:aria-disabled="c.disabled || undefined"
|
|
1701
1702
|
:data-cmd-index="flatIndexOf(c)"
|
|
@@ -1713,6 +1714,10 @@ const guardOutside = useOutsideGuard()
|
|
|
1713
1714
|
@pointerenter="onPointerEnter(c)"
|
|
1714
1715
|
@pointerleave="onPointerLeave"
|
|
1715
1716
|
>
|
|
1717
|
+
<!-- Named from label and description, not from content: split
|
|
1718
|
+
into <mark> parts, a row's text was not always read as its
|
|
1719
|
+
name (BotEco's palette showed nameless options), and the
|
|
1720
|
+
shortcut or prefix kbd is not part of what the row is. -->
|
|
1716
1721
|
<!-- A picture takes the icon's slot at the icon's footprint, with
|
|
1717
1722
|
a negative margin so a 20px avatar does not make its row
|
|
1718
1723
|
taller than its neighbours. -->
|
|
@@ -13,8 +13,10 @@
|
|
|
13
13
|
* (the bar is not printed, and at rest it is not drawn). What the kit adds is
|
|
14
14
|
* the drawing, a thumb that drags, and a press beside it that pages.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* With a mouse or touchpad it draws the bar, also where the browser's bars
|
|
17
|
+
* float over the content (macOS, GTK on Linux, Windows 11's overlay setting).
|
|
18
|
+
* With a finger as the main pointer (phones, tablets) it draws nothing and
|
|
19
|
+
* leaves the browser's.
|
|
18
20
|
*
|
|
19
21
|
* `top` and `bottom` keep the bar clear of what covers the window's edges: a
|
|
20
22
|
* sticky header, a bottom bar. Any CSS length, a variable included, and a
|
|
@@ -51,14 +53,14 @@ function scroller(): HTMLElement | null {
|
|
|
51
53
|
return (doc?.scrollingElement as HTMLElement | null) ?? null
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
/*
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return
|
|
56
|
+
/*
|
|
57
|
+
* Decided by the input, not by the browser's bar: desktop bars float over the
|
|
58
|
+
* content too (GTK's overlay bars on Linux, Windows 11's setting), and there the
|
|
59
|
+
* kit's bar is wanted beside the rest of the kit. A finger has no use for a thumb
|
|
60
|
+
* to drag, so a touch screen keeps the browser's.
|
|
61
|
+
*/
|
|
62
|
+
function finePointer(d: Document): boolean {
|
|
63
|
+
return nodeWindow(d).matchMedia?.("(pointer: fine)").matches ?? false
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
function measure() {
|
|
@@ -138,7 +140,7 @@ function onThumbPointerDown(event: PointerEvent) {
|
|
|
138
140
|
onMounted(() => {
|
|
139
141
|
const host = barEl.value ?? undefined
|
|
140
142
|
doc = host?.ownerDocument
|
|
141
|
-
if (!doc ||
|
|
143
|
+
if (!doc || !finePointer(doc)) return
|
|
142
144
|
active.value = true
|
|
143
145
|
releaseNative = hideNativeBar(doc)
|
|
144
146
|
const win = nodeWindow(doc)
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
* entries keep working once Back returns past it.
|
|
32
32
|
* - Someone else's `replaceState` on a kit entry keeps the kit's key, so a
|
|
33
33
|
* router saving its scroll position does not orphan the entry.
|
|
34
|
+
* - Someone else's `pushState` or `replaceState` while a step the kit started
|
|
35
|
+
* is on its way (closing an overlay and following a link in it in one tick)
|
|
36
|
+
* is held until the step lands, then applied there: the address changes a
|
|
37
|
+
* traversal later than the router's own route does.
|
|
34
38
|
* - An app that keeps an overlay in its query through `replace` rewrites the
|
|
35
39
|
* address of the kit's entry when the overlay closes, and the entry under it
|
|
36
40
|
* still holds the old one. Taking the entry out lands there, so the address
|
|
@@ -362,7 +366,7 @@ function install() {
|
|
|
362
366
|
|
|
363
367
|
const push = history.pushState.bind(history)
|
|
364
368
|
const replace = history.replaceState.bind(history)
|
|
365
|
-
|
|
369
|
+
const pushed = (data: unknown, unused: string, url?: string | URL | null) => {
|
|
366
370
|
const before = location.href
|
|
367
371
|
push(data, unused, url)
|
|
368
372
|
s.href = location.href
|
|
@@ -371,12 +375,35 @@ function install() {
|
|
|
371
375
|
if (pathOf(before) !== pathOf(location.href)) leavePage()
|
|
372
376
|
mute()
|
|
373
377
|
}
|
|
374
|
-
|
|
378
|
+
const replaced = (data: unknown, unused: string, url?: string | URL | null) => {
|
|
375
379
|
const mark = s.internal ? null : current()
|
|
376
380
|
const keep = mark && data && typeof data === "object" && !markOf(data) ? { ...(data as object), [KEY]: mark } : data
|
|
377
381
|
replace(keep, unused, url)
|
|
378
382
|
s.href = location.href
|
|
379
383
|
}
|
|
384
|
+
history.pushState = function (data: unknown, unused: string, url?: string | URL | null) {
|
|
385
|
+
if (!s.internal && s.silent > 0) s.waiting.push(() => pushed(unmarked(data), unused, url))
|
|
386
|
+
else pushed(data, unused, url)
|
|
387
|
+
}
|
|
388
|
+
history.replaceState = function (data: unknown, unused: string, url?: string | URL | null) {
|
|
389
|
+
if (!s.internal && s.silent > 0) s.waiting.push(() => replaced(unmarked(data), unused, url))
|
|
390
|
+
else replaced(data, unused, url)
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/*
|
|
395
|
+
* A change written while a step the kit started is on its way (an overlay
|
|
396
|
+
* closed and a link inside it navigated in the same tick) waits for the step to
|
|
397
|
+
* land. Applied at once, the step would then go back from the new entry, and
|
|
398
|
+
* the page would end on the old path. A router builds its state from the entry
|
|
399
|
+
* it sat on, the kit's, so the kit's key is taken off: the entry it lands on is
|
|
400
|
+
* not the kit's any more.
|
|
401
|
+
*/
|
|
402
|
+
function unmarked(data: unknown): unknown {
|
|
403
|
+
if (!markOf(data)) return data
|
|
404
|
+
const copy = { ...(data as Record<string, unknown>) }
|
|
405
|
+
delete copy[KEY]
|
|
406
|
+
return copy
|
|
380
407
|
}
|
|
381
408
|
|
|
382
409
|
/** Record an entry on top of the history, under the current address. */
|