@leavepulse/ui 0.45.0 → 0.45.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/dist/assets/{LpCommandPalette-nGNnzXqQ.css → LpCommandPalette-HzAA4gri.css} +21 -21
- package/dist/chunks/{LpAddressInput-BwX8uo4_.js → LpAddressInput-CJOYGZlI.js} +1 -1
- package/dist/chunks/{LpAppShell-C53_RaGF.js → LpAppShell-B07Lf48e.js} +1 -1
- package/dist/chunks/{LpConfirmDialog-DCw5jR1t.js → LpConfirmDialog-BTVAR4tF.js} +1 -1
- package/dist/chunks/{LpConfirmHost-CbywMpMP.js → LpConfirmHost-Ci_uCHgQ.js} +1 -1
- package/dist/chunks/{LpDatePicker-DuusgT69.js → LpDatePicker-BrdFtSTy.js} +3 -1
- package/dist/chunks/{LpDateRangePicker-DHeuznfC.js → LpDateRangePicker-Drd7EbIz.js} +4 -2
- package/dist/chunks/{LpDrawer-Dt4aB4Fr.js → LpDrawer-CfRhHwmE.js} +1 -1
- package/dist/chunks/{LpModal-DMMDQHAu.js → LpModal-BzTVeNqe.js} +1 -1
- package/dist/chunks/{LpModalNav-BVPDyIup.js → LpModalNav-CjABSGCu.js} +12 -6
- package/dist/chunks/{LpSidebar-CQNB0-yU.js → LpSidebar-Bwws_X29.js} +1 -1
- package/dist/chunks/{LpToaster-DpJvoCOh.js → LpToaster-DTtWuKvq.js} +39 -6
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +3 -3
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.js +1 -1
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.js +1 -1
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpToaster.vue.d.ts +2 -0
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/composables/useLocale.d.ts +2 -0
- package/dist/composables/useLocale.js +9 -0
- package/dist/index.js +11 -11
- package/package.json +1 -1
- package/src/components/LpCommandPalette.vue +1 -1
- package/src/components/LpDatePicker.vue +3 -1
- package/src/components/LpDateRangePicker.vue +3 -1
- package/src/components/LpDrawer.vue +1 -1
- package/src/components/LpModal.vue +1 -1
- package/src/components/LpModalNav.vue +13 -2
- package/src/components/LpToaster.vue +42 -4
- package/src/composables/useLocale.ts +14 -0
- package/src/tokens/tokens.css +7 -4
|
@@ -5,81 +5,81 @@
|
|
|
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-bb9a3f4c] {
|
|
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-bb9a3f4c] {
|
|
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-bb9a3f4c] {
|
|
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-bb9a3f4c] {
|
|
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-bb9a3f4c] {
|
|
30
30
|
width: var(--lp-cmd-pane);
|
|
31
31
|
}
|
|
32
32
|
/*
|
|
33
33
|
* The pane rides in from the right edge while the dialog opens up to it, and
|
|
34
34
|
* leaves the same way, for as long as the dialog takes to close over it.
|
|
35
35
|
*/
|
|
36
|
-
.lp-cmd-pane-enter-active[data-v-
|
|
37
|
-
.lp-cmd-pane-leave-active[data-v-
|
|
36
|
+
.lp-cmd-pane-enter-active[data-v-bb9a3f4c],
|
|
37
|
+
.lp-cmd-pane-leave-active[data-v-bb9a3f4c] {
|
|
38
38
|
transition:
|
|
39
39
|
transform 300ms var(--ease-emphasized, ease),
|
|
40
40
|
opacity 300ms ease;
|
|
41
41
|
}
|
|
42
|
-
.lp-cmd-pane-enter-from[data-v-
|
|
43
|
-
.lp-cmd-pane-leave-to[data-v-
|
|
42
|
+
.lp-cmd-pane-enter-from[data-v-bb9a3f4c],
|
|
43
|
+
.lp-cmd-pane-leave-to[data-v-bb9a3f4c] {
|
|
44
44
|
opacity: 0;
|
|
45
45
|
transform: translateX(40%);
|
|
46
46
|
}
|
|
47
|
-
.lp-cmd-para[data-v-
|
|
48
|
-
animation: lp-cmd-para-in-
|
|
47
|
+
.lp-cmd-para[data-v-bb9a3f4c] {
|
|
48
|
+
animation: lp-cmd-para-in-bb9a3f4c 260ms ease-out both;
|
|
49
49
|
}
|
|
50
|
-
@keyframes lp-cmd-para-in-
|
|
50
|
+
@keyframes lp-cmd-para-in-bb9a3f4c {
|
|
51
51
|
from {
|
|
52
52
|
opacity: 0;
|
|
53
53
|
transform: translateY(4px);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
@media (prefers-reduced-motion: reduce) {
|
|
57
|
-
.lp-cmd-split[data-v-
|
|
58
|
-
.lp-cmd-pane-enter-active[data-v-
|
|
59
|
-
.lp-cmd-pane-leave-active[data-v-
|
|
57
|
+
.lp-cmd-split[data-v-bb9a3f4c],
|
|
58
|
+
.lp-cmd-pane-enter-active[data-v-bb9a3f4c],
|
|
59
|
+
.lp-cmd-pane-leave-active[data-v-bb9a3f4c] {
|
|
60
60
|
transition: none;
|
|
61
61
|
}
|
|
62
|
-
.lp-cmd-para[data-v-
|
|
62
|
+
.lp-cmd-para[data-v-bb9a3f4c] {
|
|
63
63
|
animation: none;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
.lp-cmd-excerpt[data-v-
|
|
66
|
+
.lp-cmd-excerpt[data-v-bb9a3f4c] {
|
|
67
67
|
display: -webkit-box;
|
|
68
68
|
-webkit-box-orient: vertical;
|
|
69
69
|
overflow: hidden;
|
|
70
70
|
}
|
|
71
71
|
/* Each result eases in; honours reduced motion. */
|
|
72
|
-
.lp-cmd-item[data-v-
|
|
73
|
-
animation: lp-cmd-in-
|
|
72
|
+
.lp-cmd-item[data-v-bb9a3f4c] {
|
|
73
|
+
animation: lp-cmd-in-bb9a3f4c 140ms ease-out both;
|
|
74
74
|
}
|
|
75
|
-
@keyframes lp-cmd-in-
|
|
75
|
+
@keyframes lp-cmd-in-bb9a3f4c {
|
|
76
76
|
from {
|
|
77
77
|
opacity: 0;
|
|
78
78
|
transform: translateY(3px);
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
@media (prefers-reduced-motion: reduce) {
|
|
82
|
-
.lp-cmd-item[data-v-
|
|
82
|
+
.lp-cmd-item[data-v-bb9a3f4c] {
|
|
83
83
|
animation: none;
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -7,7 +7,7 @@ import { _ as _sfc_main$3 } from "./LpButton-CKSwC6Mu.js";
|
|
|
7
7
|
import { _ as _sfc_main$1 } from "./LpFormField-CtVYj6tO.js";
|
|
8
8
|
import { _ as _sfc_main$4 } from "./LpIcon-DYtaid0K.js";
|
|
9
9
|
import { _ as _sfc_main$5 } from "./LpInput-D-YGQbEv.js";
|
|
10
|
-
import { _ as _sfc_main$7 } from "./LpModal-
|
|
10
|
+
import { _ as _sfc_main$7 } from "./LpModal-BzTVeNqe.js";
|
|
11
11
|
import { _ as _sfc_main$6 } from "./LpSelect-DNIL6MB9.js";
|
|
12
12
|
import { useMergedAttrs } from "../composables/useMergedClass.js";
|
|
13
13
|
const _hoisted_1 = { class: "flex items-stretch gap-2" };
|
|
@@ -4,7 +4,7 @@ import { _ as _sfc_main$2 } from "./LpButton-CKSwC6Mu.js";
|
|
|
4
4
|
import { _ as _sfc_main$3 } from "./LpIcon-DYtaid0K.js";
|
|
5
5
|
import { _ as _sfc_main$5 } from "./LpScrollArea-Bry1fdOM.js";
|
|
6
6
|
import { _ as _sfc_main$4 } from "./LpShift-DXNsauQZ.js";
|
|
7
|
-
import { _ as _sfc_main$1 } from "./LpSidebar-
|
|
7
|
+
import { _ as _sfc_main$1 } from "./LpSidebar-Bwws_X29.js";
|
|
8
8
|
import { useMergedAttrs } from "../composables/useMergedClass.js";
|
|
9
9
|
const _hoisted_1 = ["href"];
|
|
10
10
|
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-CKSwC6Mu.js";
|
|
4
4
|
import { _ as _sfc_main$3 } from "./LpIcon-DYtaid0K.js";
|
|
5
|
-
import { _ as _sfc_main$1 } from "./LpModal-
|
|
5
|
+
import { _ as _sfc_main$1 } from "./LpModal-BzTVeNqe.js";
|
|
6
6
|
const _hoisted_1 = { class: "inline-flex items-center gap-2.5" };
|
|
7
7
|
const _hoisted_2 = {
|
|
8
8
|
key: 0,
|
|
@@ -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-BTVAR4tF.js";
|
|
4
4
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
5
5
|
__name: "LpConfirmHost",
|
|
6
6
|
props: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineComponent, ref, computed, useAttrs, openBlock, createElementBlock, normalizeStyle, unref, normalizeClass, createVNode, withCtx, createElementVNode, mergeProps, createCommentVNode, toDisplayString } from "vue";
|
|
2
2
|
import { PopoverRoot, PopoverTrigger, PopoverPortal, PopoverContent } from "reka-ui";
|
|
3
3
|
import { useFieldControl } from "../composables/useField.js";
|
|
4
|
+
import { useLocale } from "../composables/useLocale.js";
|
|
4
5
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
5
6
|
import { mergeClass } from "../composables/useMergedClass.js";
|
|
6
7
|
import { POPOVER_PANEL } from "../components/dropdown.js";
|
|
@@ -48,11 +49,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
48
49
|
const at = (props.modelValue || "").slice(11, 16);
|
|
49
50
|
return /^\d{2}:\d{2}$/.test(at) ? at : "";
|
|
50
51
|
});
|
|
52
|
+
const locale = useLocale();
|
|
51
53
|
const display = computed(() => {
|
|
52
54
|
if (!props.modelValue) return "";
|
|
53
55
|
const [y, m, d] = day.value.split("-").map(Number);
|
|
54
56
|
if (!y || !m || !d) return props.modelValue;
|
|
55
|
-
const shown = new Intl.DateTimeFormat(
|
|
57
|
+
const shown = new Intl.DateTimeFormat(locale.value, props.format).format(new Date(y, m - 1, d));
|
|
56
58
|
return props.time && minute.value ? `${shown}, ${minute.value}` : shown;
|
|
57
59
|
});
|
|
58
60
|
const shellSize = {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineComponent, ref, computed, onMounted, onBeforeUnmount, useAttrs, openBlock, createElementBlock, normalizeStyle, unref, normalizeClass, createVNode, withCtx, createElementVNode, mergeProps, createCommentVNode, Fragment, renderList, toDisplayString } from "vue";
|
|
2
2
|
import { PopoverRoot, PopoverTrigger, PopoverPortal, PopoverContent } from "reka-ui";
|
|
3
3
|
import { useFieldControl } from "../composables/useField.js";
|
|
4
|
+
import { useLocale } from "../composables/useLocale.js";
|
|
4
5
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
5
6
|
import { mergeClass } from "../composables/useMergedClass.js";
|
|
6
7
|
import { normalizeRange, formatRange, defaultRangePresets, sameRange, clampRange } from "../components/dateRange.js";
|
|
@@ -58,7 +59,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
58
59
|
);
|
|
59
60
|
const open = ref(false);
|
|
60
61
|
const value = computed(() => normalizeRange(props.modelValue));
|
|
61
|
-
const
|
|
62
|
+
const locale = useLocale(() => props.locale);
|
|
63
|
+
const display = computed(() => value.value ? formatRange(value.value, locale.value, props.format) : "");
|
|
62
64
|
const presetList = computed(() => {
|
|
63
65
|
return props.presets ?? defaultRangePresets(text.value);
|
|
64
66
|
});
|
|
@@ -174,7 +176,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
174
176
|
"is-date-unavailable": __props.isDateUnavailable,
|
|
175
177
|
"maximum-days": __props.maximumDays,
|
|
176
178
|
months: wide.value ? 2 : 1,
|
|
177
|
-
locale:
|
|
179
|
+
locale: unref(locale),
|
|
178
180
|
class: "border-0 bg-transparent",
|
|
179
181
|
"onUpdate:modelValue": pick
|
|
180
182
|
}, null, 8, ["model-value", "min", "max", "is-disabled", "is-date-unavailable", "maximum-days", "months", "locale"])
|
|
@@ -60,7 +60,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
60
60
|
watch(() => props.open, (open) => open ? claim() : release(), { immediate: true });
|
|
61
61
|
onBeforeUnmount(release);
|
|
62
62
|
const contentClass = computed(() => {
|
|
63
|
-
const surface = frosted.value ? layer.value.nested ? "lp-glass-overlay--nested" : "lp-glass-overlay" : "bg-surface-raised";
|
|
63
|
+
const surface = frosted.value ? layer.value.nested ? "lp-glass-overlay lp-glass-overlay--nested" : "lp-glass-overlay" : "bg-surface-raised";
|
|
64
64
|
const base = `fixed z-(--z-modal) flex flex-col border-line ${surface} shadow-panel outline-none`;
|
|
65
65
|
const map = {
|
|
66
66
|
left: "inset-y-0 left-0 border-r rounded-r-card",
|
|
@@ -162,7 +162,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
162
162
|
createElementVNode("div", {
|
|
163
163
|
ref_key: "panelRef",
|
|
164
164
|
ref: panelRef,
|
|
165
|
-
class: normalizeClass(["relative flex max-h-[min(90vh,calc(100dvh-2rem))] min-h-0 flex-col overflow-hidden rounded-card border border-line shadow-panel", [unref(frosted) ? unref(layer).nested ? "lp-glass-overlay--nested" : "lp-glass-overlay" : "bg-surface-raised", widthClass.value, unref(tweening) ? "transition-[height] duration-fast ease-[var(--ease-emphasized)] motion-reduce:transition-none" : ""]]),
|
|
165
|
+
class: normalizeClass(["relative flex max-h-[min(90vh,calc(100dvh-2rem))] min-h-0 flex-col overflow-hidden rounded-card border border-line shadow-panel", [unref(frosted) ? unref(layer).nested ? "lp-glass-overlay lp-glass-overlay--nested" : "lp-glass-overlay" : "bg-surface-raised", widthClass.value, unref(tweening) ? "transition-[height] duration-fast ease-[var(--ease-emphasized)] motion-reduce:transition-none" : ""]]),
|
|
166
166
|
style: normalizeStyle({ ...__props.width ? { width: __props.width } : {}, ...hasAside.value ? { alignSelf: "stretch" } : {} })
|
|
167
167
|
}, [
|
|
168
168
|
!(__props.title || _ctx.$slots.title) && __props.ariaLabel ? (openBlock(), createBlock(unref(DialogTitle), {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { defineComponent, computed, ref, openBlock, createBlock, createSlots, withCtx, renderSlot, createElementVNode, normalizeClass, createVNode, createCommentVNode, createTextVNode, toDisplayString } from "vue";
|
|
2
|
+
import { useGlass } from "../composables/useGlass.js";
|
|
2
3
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
3
4
|
import { _ as _sfc_main$2 } from "./LpButton-CKSwC6Mu.js";
|
|
4
5
|
import { _ as _sfc_main$3 } from "./LpIcon-DYtaid0K.js";
|
|
5
|
-
import { _ as _sfc_main$1 } from "./LpModal-
|
|
6
|
-
import { _ as _sfc_main$4 } from "./LpSidebar-
|
|
6
|
+
import { _ as _sfc_main$1 } from "./LpModal-BzTVeNqe.js";
|
|
7
|
+
import { _ as _sfc_main$4 } from "./LpSidebar-Bwws_X29.js";
|
|
7
8
|
const _hoisted_1 = { class: "flex items-center gap-2" };
|
|
8
9
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
9
10
|
__name: "LpModalNav",
|
|
@@ -61,6 +62,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
61
62
|
);
|
|
62
63
|
const triggerClass = computed(() => TRIGGER_VISIBILITY[props.mobileBreakpoint]);
|
|
63
64
|
const railStyle = { maxHeight: "min(90vh, calc(100dvh - 2rem))" };
|
|
65
|
+
const frosted = useGlass(() => props.glass);
|
|
66
|
+
const railPanel = computed(() => [
|
|
67
|
+
"rounded-card border border-line p-2 shadow-panel",
|
|
68
|
+
frosted.value ? "lp-glass-overlay" : "bg-surface-raised"
|
|
69
|
+
]);
|
|
64
70
|
return (_ctx, _cache) => {
|
|
65
71
|
return openBlock(), createBlock(_sfc_main$1, {
|
|
66
72
|
glass: __props.glass,
|
|
@@ -122,8 +128,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
122
128
|
responsive: "",
|
|
123
129
|
"mobile-breakpoint": __props.mobileBreakpoint,
|
|
124
130
|
style: railStyle,
|
|
125
|
-
class:
|
|
126
|
-
}, null, 8, ["modelValue", "open", "items", "sections", "width", "searchable", "search-placeholder", "loading", "mobile-breakpoint"])
|
|
131
|
+
class: normalizeClass(railPanel.value)
|
|
132
|
+
}, null, 8, ["modelValue", "open", "items", "sections", "width", "searchable", "search-placeholder", "loading", "mobile-breakpoint", "class"])
|
|
127
133
|
], 2)
|
|
128
134
|
]),
|
|
129
135
|
key: "0"
|
|
@@ -149,8 +155,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
149
155
|
responsive: "",
|
|
150
156
|
"mobile-breakpoint": __props.mobileBreakpoint,
|
|
151
157
|
style: railStyle,
|
|
152
|
-
class:
|
|
153
|
-
}, null, 8, ["modelValue", "open", "items", "sections", "width", "searchable", "search-placeholder", "loading", "mobile-breakpoint"])
|
|
158
|
+
class: normalizeClass(railPanel.value)
|
|
159
|
+
}, null, 8, ["modelValue", "open", "items", "sections", "width", "searchable", "search-placeholder", "loading", "mobile-breakpoint", "class"])
|
|
154
160
|
], 2)
|
|
155
161
|
]),
|
|
156
162
|
key: "1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineComponent, computed, ref, useId, openBlock, createElementBlock, Fragment, createElementVNode, mergeProps, unref, normalizeClass, renderSlot, createCommentVNode, createBlock, createVNode, createSlots, withCtx, normalizeProps, guardReactiveProps } from "vue";
|
|
2
2
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
3
|
-
import { _ as _sfc_main$3 } from "./LpDrawer-
|
|
3
|
+
import { _ as _sfc_main$3 } from "./LpDrawer-CfRhHwmE.js";
|
|
4
4
|
import { _ as _sfc_main$1 } from "./LpInput-D-YGQbEv.js";
|
|
5
5
|
import { _ as _sfc_main$2 } from "./LpSidebarNav-kx-LdqNU.js";
|
|
6
6
|
const _hoisted_1 = ["aria-label"];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineComponent, useId, onMounted, nextTick, onBeforeUnmount, ref, watch, openBlock, createBlock, unref, withCtx, createElementBlock, Fragment, renderList, normalizeClass, createElementVNode, createVNode, createTextVNode, toDisplayString, createCommentVNode, withModifiers, normalizeStyle, Teleport } from "vue";
|
|
2
2
|
import { ToastProvider, ToastRoot, ToastTitle, ToastDescription, ToastViewport } from "reka-ui";
|
|
3
3
|
import { prefersReducedMotion } from "../composables/easing.js";
|
|
4
|
+
import { useClipboard } from "../composables/useClipboard.js";
|
|
4
5
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
5
6
|
import { useToast } from "../composables/useToast.js";
|
|
6
7
|
import { CLOSE_ICON } from "../components/dropdown.js";
|
|
@@ -8,7 +9,8 @@ import { _ as _sfc_main$1 } from "./LpIcon-DYtaid0K.js";
|
|
|
8
9
|
const _hoisted_1 = { class: "flex items-start gap-3 p-3.5" };
|
|
9
10
|
const _hoisted_2 = { class: "flex min-w-0 flex-1 flex-col gap-0.5" };
|
|
10
11
|
const _hoisted_3 = ["disabled", "aria-busy", "onClick"];
|
|
11
|
-
const _hoisted_4 = ["aria-label", "onClick"];
|
|
12
|
+
const _hoisted_4 = ["aria-label", "title", "onClick"];
|
|
13
|
+
const _hoisted_5 = ["aria-label", "onClick"];
|
|
12
14
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
13
15
|
__name: "LpToaster",
|
|
14
16
|
props: {
|
|
@@ -16,7 +18,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
16
18
|
},
|
|
17
19
|
setup(__props) {
|
|
18
20
|
const props = __props;
|
|
19
|
-
const text = useLabels("toast", { dismiss: "Dismiss" }, () => props.labels);
|
|
21
|
+
const text = useLabels("toast", { dismiss: "Dismiss", copy: "Copy message", copied: "Copied" }, () => props.labels);
|
|
20
22
|
const { queue, dismiss } = useToast();
|
|
21
23
|
let observer;
|
|
22
24
|
const tops = /* @__PURE__ */ new WeakMap();
|
|
@@ -147,8 +149,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
147
149
|
busy.value = next;
|
|
148
150
|
}
|
|
149
151
|
}
|
|
152
|
+
const { copy } = useClipboard();
|
|
153
|
+
const copiedId = ref(null);
|
|
154
|
+
let copiedTimer;
|
|
155
|
+
const copyable = (t) => t.variant === "error" || t.variant === "warning";
|
|
156
|
+
async function copyToast(t) {
|
|
157
|
+
if (!await copy([t.title, t.message].filter(Boolean).join("\n"))) return;
|
|
158
|
+
copiedId.value = tag(t);
|
|
159
|
+
clearTimeout(copiedTimer);
|
|
160
|
+
copiedTimer = setTimeout(() => copiedId.value = null, 1500);
|
|
161
|
+
}
|
|
162
|
+
onBeforeUnmount(() => clearTimeout(copiedTimer));
|
|
163
|
+
function selecting() {
|
|
164
|
+
return Boolean(window.getSelection()?.toString());
|
|
165
|
+
}
|
|
150
166
|
function runClick(t) {
|
|
151
|
-
if (swiped === tag(t)) return;
|
|
167
|
+
if (swiped === tag(t) || selecting()) return;
|
|
152
168
|
if (t.onClick) return settle(t, t.onClick);
|
|
153
169
|
}
|
|
154
170
|
function runAction(t, action) {
|
|
@@ -189,7 +205,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
189
205
|
]),
|
|
190
206
|
_: 2
|
|
191
207
|
}, 1024)) : createCommentVNode("", true),
|
|
192
|
-
createVNode(unref(ToastDescription), {
|
|
208
|
+
createVNode(unref(ToastDescription), {
|
|
209
|
+
class: "cursor-text select-text break-words text-xs text-muted",
|
|
210
|
+
onPointerdown: _cache[0] || (_cache[0] = withModifiers(() => {
|
|
211
|
+
}, ["stop"]))
|
|
212
|
+
}, {
|
|
193
213
|
default: withCtx(() => [
|
|
194
214
|
createTextVNode(toDisplayString(t.message), 1)
|
|
195
215
|
]),
|
|
@@ -198,7 +218,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
198
218
|
t.actions?.length ? (openBlock(), createElementBlock("div", {
|
|
199
219
|
key: 1,
|
|
200
220
|
class: "mt-2 flex flex-wrap gap-2",
|
|
201
|
-
onClick: _cache[
|
|
221
|
+
onClick: _cache[1] || (_cache[1] = withModifiers(() => {
|
|
202
222
|
}, ["stop"]))
|
|
203
223
|
}, [
|
|
204
224
|
(openBlock(true), createElementBlock(Fragment, null, renderList(t.actions, (action, i) => {
|
|
@@ -220,6 +240,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
220
240
|
}), 128))
|
|
221
241
|
])) : createCommentVNode("", true)
|
|
222
242
|
]),
|
|
243
|
+
copyable(t) ? (openBlock(), createElementBlock("button", {
|
|
244
|
+
key: 0,
|
|
245
|
+
type: "button",
|
|
246
|
+
class: "-mt-1 rounded-md p-1 text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring",
|
|
247
|
+
"aria-label": copiedId.value === tag(t) ? unref(text).copied : unref(text).copy,
|
|
248
|
+
title: copiedId.value === tag(t) ? unref(text).copied : unref(text).copy,
|
|
249
|
+
onClick: withModifiers(($event) => copyToast(t), ["stop"])
|
|
250
|
+
}, [
|
|
251
|
+
createVNode(_sfc_main$1, {
|
|
252
|
+
name: copiedId.value === tag(t) ? "lucide:check" : "lucide:copy",
|
|
253
|
+
size: 15
|
|
254
|
+
}, null, 8, ["name"])
|
|
255
|
+
], 8, _hoisted_4)) : createCommentVNode("", true),
|
|
223
256
|
createElementVNode("button", {
|
|
224
257
|
type: "button",
|
|
225
258
|
class: "group -mr-1 -mt-1 rounded-md p-1 text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink",
|
|
@@ -231,7 +264,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
231
264
|
size: 16,
|
|
232
265
|
class: normalizeClass(unref(CLOSE_ICON))
|
|
233
266
|
}, null, 8, ["class"])
|
|
234
|
-
], 8,
|
|
267
|
+
], 8, _hoisted_5)
|
|
235
268
|
]),
|
|
236
269
|
t.dismissAt ? (openBlock(), createElementBlock("div", {
|
|
237
270
|
key: 0,
|
|
@@ -10,7 +10,7 @@ import { useModalLayer } from "./modalDepth.js";
|
|
|
10
10
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
11
11
|
import { parseCommandQuery, rankCommandItems } from "./commandSearch.js";
|
|
12
12
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
13
|
-
import '../assets/LpCommandPalette-
|
|
13
|
+
import '../assets/LpCommandPalette-HzAA4gri.css';const _hoisted_1 = { class: "flex shrink-0 items-center gap-2.5 border-b border-line px-4" };
|
|
14
14
|
const _hoisted_2 = ["title", "onClick"];
|
|
15
15
|
const _hoisted_3 = ["aria-activedescendant", "placeholder", "onKeydown"];
|
|
16
16
|
const _hoisted_4 = { class: "shrink-0 rounded border border-line px-1.5 py-0.5 text-[10px] text-muted" };
|
|
@@ -554,7 +554,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
554
554
|
createVNode(unref(DialogContent), {
|
|
555
555
|
ref_key: "contentRef",
|
|
556
556
|
ref: contentRef,
|
|
557
|
-
class: normalizeClass(["lp-cmd-dialog fixed left-1/2 top-[12vh] flex max-h-[76vh] -translate-x-1/2 flex-col overflow-hidden rounded-card border border-line shadow-panel outline-none data-[state=open]:animate-[pop-in_160ms_var(--ease-emphasized)] data-[state=closed]:animate-[pop-out_130ms_ease]", [unref(frosted) ? unref(layer).nested ? "lp-glass-overlay--nested" : "lp-glass-overlay" : "bg-surface-raised", __props.previewPane && "lp-cmd-split"]]),
|
|
557
|
+
class: normalizeClass(["lp-cmd-dialog fixed left-1/2 top-[12vh] flex max-h-[76vh] -translate-x-1/2 flex-col overflow-hidden rounded-card border border-line shadow-panel outline-none data-[state=open]:animate-[pop-in_160ms_var(--ease-emphasized)] data-[state=closed]:animate-[pop-out_130ms_ease]", [unref(frosted) ? unref(layer).nested ? "lp-glass-overlay lp-glass-overlay--nested" : "lp-glass-overlay" : "bg-surface-raised", __props.previewPane && "lp-cmd-split"]]),
|
|
558
558
|
style: normalizeStyle({ zIndex: unref(layer).panel }),
|
|
559
559
|
"data-pane": paneOpen.value ? "open" : void 0,
|
|
560
560
|
onOpenAutoFocus: _cache[2] || (_cache[2] = withModifiers(() => {
|
|
@@ -844,7 +844,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
844
844
|
};
|
|
845
845
|
}
|
|
846
846
|
});
|
|
847
|
-
const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
847
|
+
const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-bb9a3f4c"]]);
|
|
848
848
|
export {
|
|
849
849
|
LpCommandPalette as default
|
|
850
850
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent, computed, openBlock, createBlock, unref, withCtx, createElementVNode, createElementBlock, Fragment, renderList, toDisplayString, createTextVNode, createCommentVNode } from "vue";
|
|
2
|
-
import { _ as _sfc_main$1 } from "../chunks/LpModal-
|
|
2
|
+
import { _ as _sfc_main$1 } from "../chunks/LpModal-BzTVeNqe.js";
|
|
3
3
|
import { useAppleKeyboard, mergeShortcutGroups, activeShortcuts, useHotkeys, appleModifierLabel } from "../composables/useHotkeys.js";
|
|
4
4
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
5
5
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
type __VLS_Props = {
|
|
2
2
|
labels?: Partial<{
|
|
3
3
|
dismiss: string;
|
|
4
|
+
copy: string;
|
|
5
|
+
copied: string;
|
|
4
6
|
}>;
|
|
5
7
|
};
|
|
6
8
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { computed, toValue } from "vue";
|
|
2
|
+
import { injectConfigProviderContext } from "reka-ui";
|
|
3
|
+
function useLocale(own) {
|
|
4
|
+
const context = injectConfigProviderContext({});
|
|
5
|
+
return computed(() => toValue(own) || context.locale?.value || void 0);
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
useLocale
|
|
9
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { _ } from "./chunks/LayoutCanvas-BkaGXTjx.js";
|
|
2
|
-
import { _ as _2 } from "./chunks/LpAddressInput-
|
|
2
|
+
import { _ as _2 } from "./chunks/LpAddressInput-CJOYGZlI.js";
|
|
3
3
|
import { _ as _3 } from "./chunks/LpMapPicker-Cc84LaM3.js";
|
|
4
4
|
import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
|
|
5
5
|
import { _ as _4 } from "./chunks/LpActionBar-CnfFVIwC.js";
|
|
6
6
|
import { _ as _5 } from "./chunks/LpAlert-B6ilrM7T.js";
|
|
7
|
-
import { _ as _6 } from "./chunks/LpAppShell-
|
|
7
|
+
import { _ as _6 } from "./chunks/LpAppShell-B07Lf48e.js";
|
|
8
8
|
import { _ as _7 } from "./chunks/LpAutocomplete-C8IgSMsi.js";
|
|
9
9
|
import { _ as _8 } from "./chunks/LpAvatar-C1XStdOo.js";
|
|
10
10
|
import { _ as _9 } from "./chunks/LpBadge-Fe0D1bYx.js";
|
|
@@ -22,17 +22,17 @@ import { _ as _16 } from "./chunks/LpColorPicker-zz4VGkG4.js";
|
|
|
22
22
|
import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, normalizeHue, opaqueCss, parseColor, parseHex, rgbToHex, rgbToHsv } from "./components/color.js";
|
|
23
23
|
import { default as default3 } from "./components/LpCommandPalette.vue.js";
|
|
24
24
|
import { parseCommandQuery, rankCommandItems } from "./components/commandSearch.js";
|
|
25
|
-
import { _ as _17 } from "./chunks/LpConfirmDialog-
|
|
26
|
-
import { _ as _18 } from "./chunks/LpConfirmHost-
|
|
25
|
+
import { _ as _17 } from "./chunks/LpConfirmDialog-BTVAR4tF.js";
|
|
26
|
+
import { _ as _18 } from "./chunks/LpConfirmHost-Ci_uCHgQ.js";
|
|
27
27
|
import { confirm, useConfirm } from "./components/confirm.js";
|
|
28
28
|
import { _ as _19 } from "./chunks/LpContextMenu-BqkAYa9X.js";
|
|
29
|
-
import { _ as _20 } from "./chunks/LpDatePicker-
|
|
30
|
-
import { _ as _21 } from "./chunks/LpDateRangePicker-
|
|
29
|
+
import { _ as _20 } from "./chunks/LpDatePicker-BrdFtSTy.js";
|
|
30
|
+
import { _ as _21 } from "./chunks/LpDateRangePicker-Drd7EbIz.js";
|
|
31
31
|
import { _ as _22 } from "./chunks/LpRangeCalendar-DZuaRV0W.js";
|
|
32
32
|
import { clampRange, defaultRangePresets, formatRange, normalizeRange, sameRange } from "./components/dateRange.js";
|
|
33
33
|
import { _ as _23 } from "./chunks/LpDisclosure-Cc23-JOT.js";
|
|
34
34
|
import { _ as _24 } from "./chunks/LpDivider-CUX46KR0.js";
|
|
35
|
-
import { _ as _25 } from "./chunks/LpDrawer-
|
|
35
|
+
import { _ as _25 } from "./chunks/LpDrawer-CfRhHwmE.js";
|
|
36
36
|
import { _ as _26 } from "./chunks/LpDropdownMenu-DdJGQzPn.js";
|
|
37
37
|
import { default as default4 } from "./components/LpDropzone.vue.js";
|
|
38
38
|
import { _ as _27 } from "./chunks/LpEmptyState-BJbZXC8D.js";
|
|
@@ -51,8 +51,8 @@ import { _ as _35 } from "./chunks/LpLink-Krkjhe_y.js";
|
|
|
51
51
|
import { _ as _36 } from "./chunks/LpLogViewer-KypbgOyo.js";
|
|
52
52
|
import { countLevels, matchPositions, matchesTerm, ringWindow, stepMatch } from "./components/logSearch.js";
|
|
53
53
|
import { _ as _37 } from "./chunks/LpMediaGallery-YKr-cQPN.js";
|
|
54
|
-
import { _ as _38 } from "./chunks/LpModal-
|
|
55
|
-
import { _ as _39 } from "./chunks/LpModalNav-
|
|
54
|
+
import { _ as _38 } from "./chunks/LpModal-BzTVeNqe.js";
|
|
55
|
+
import { _ as _39 } from "./chunks/LpModalNav-CjABSGCu.js";
|
|
56
56
|
import { _ as _40 } from "./chunks/LpNotificationBell-CCwyJP5C.js";
|
|
57
57
|
import { _ as _41 } from "./chunks/LpNumberField-B77O-z28.js";
|
|
58
58
|
import { _ as _42 } from "./chunks/LpTimeField-Cqe7fXnh.js";
|
|
@@ -75,7 +75,7 @@ import { _ as _57 } from "./chunks/LpSelect-DNIL6MB9.js";
|
|
|
75
75
|
import { _ as _58 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
76
76
|
import { _ as _59 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
77
77
|
import { default as default6 } from "./components/LpShortcutsDialog.vue.js";
|
|
78
|
-
import { _ as _60 } from "./chunks/LpSidebar-
|
|
78
|
+
import { _ as _60 } from "./chunks/LpSidebar-Bwws_X29.js";
|
|
79
79
|
import { _ as _61 } from "./chunks/LpSkeleton-BB6XIV-w.js";
|
|
80
80
|
import { _ as _62 } from "./chunks/LpSlider-Cuzmrd7p.js";
|
|
81
81
|
import { _ as _63 } from "./chunks/LpSparkline-CB80N8SJ.js";
|
|
@@ -91,7 +91,7 @@ import { addTags, splitTags } from "./components/tags.js";
|
|
|
91
91
|
import { _ as _70 } from "./chunks/LpTextarea-uuScWo6-.js";
|
|
92
92
|
import { _ as _71 } from "./chunks/LpThemeSwitcher-B4aVPbNC.js";
|
|
93
93
|
import { _ as _72 } from "./chunks/LpTilt-B7KHX1zH.js";
|
|
94
|
-
import { _ as _73 } from "./chunks/LpToaster-
|
|
94
|
+
import { _ as _73 } from "./chunks/LpToaster-DTtWuKvq.js";
|
|
95
95
|
import { _ as _74 } from "./chunks/LpTooltip-CXVKcOXT.js";
|
|
96
96
|
import { _ as _75 } from "./chunks/LpTooltipProvider-CftjV7Xc.js";
|
|
97
97
|
import { _ as _76 } from "./chunks/LpTopologyCanvas-6ozNrQKh.js";
|
package/package.json
CHANGED
|
@@ -939,7 +939,7 @@ useHotkeys(() =>
|
|
|
939
939
|
<DialogContent
|
|
940
940
|
ref="contentRef"
|
|
941
941
|
class="lp-cmd-dialog fixed left-1/2 top-[12vh] flex max-h-[76vh] -translate-x-1/2 flex-col overflow-hidden rounded-card border border-line shadow-panel outline-none data-[state=open]:animate-[pop-in_160ms_var(--ease-emphasized)] data-[state=closed]:animate-[pop-out_130ms_ease]"
|
|
942
|
-
:class="[frosted ? (layer.nested ? 'lp-glass-overlay--nested' : 'lp-glass-overlay') : 'bg-surface-raised', previewPane && 'lp-cmd-split']"
|
|
942
|
+
:class="[frosted ? (layer.nested ? 'lp-glass-overlay lp-glass-overlay--nested' : 'lp-glass-overlay') : 'bg-surface-raised', previewPane && 'lp-cmd-split']"
|
|
943
943
|
:style="{ zIndex: layer.panel }"
|
|
944
944
|
:data-pane="paneOpen ? 'open' : undefined"
|
|
945
945
|
@open-auto-focus.prevent
|
|
@@ -20,6 +20,7 @@ export default { inheritAttrs: false }
|
|
|
20
20
|
import { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from "reka-ui"
|
|
21
21
|
import { computed, ref, useAttrs } from "vue"
|
|
22
22
|
import { useFieldControl } from "../composables/useField"
|
|
23
|
+
import { useLocale } from "../composables/useLocale"
|
|
23
24
|
import { useLabels } from "../composables/useLpConfig"
|
|
24
25
|
import { mergeClass } from "../composables/useMergedClass"
|
|
25
26
|
import { POPOVER_PANEL } from "./dropdown"
|
|
@@ -73,12 +74,13 @@ const minute = computed(() => {
|
|
|
73
74
|
return /^\d{2}:\d{2}$/.test(at) ? at : ""
|
|
74
75
|
})
|
|
75
76
|
|
|
77
|
+
const locale = useLocale()
|
|
76
78
|
const display = computed(() => {
|
|
77
79
|
if (!props.modelValue) return ""
|
|
78
80
|
// Parse as local midnight so the formatted day can't drift across a timezone.
|
|
79
81
|
const [y, m, d] = day.value.split("-").map(Number)
|
|
80
82
|
if (!y || !m || !d) return props.modelValue
|
|
81
|
-
const shown = new Intl.DateTimeFormat(
|
|
83
|
+
const shown = new Intl.DateTimeFormat(locale.value, props.format).format(new Date(y, m - 1, d))
|
|
82
84
|
return props.time && minute.value ? `${shown}, ${minute.value}` : shown
|
|
83
85
|
})
|
|
84
86
|
|
|
@@ -12,6 +12,7 @@ export default { inheritAttrs: false }
|
|
|
12
12
|
import { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from "reka-ui"
|
|
13
13
|
import { computed, onBeforeUnmount, onMounted, ref, useAttrs } from "vue"
|
|
14
14
|
import { useFieldControl } from "../composables/useField"
|
|
15
|
+
import { useLocale } from "../composables/useLocale"
|
|
15
16
|
import { useLabels } from "../composables/useLpConfig"
|
|
16
17
|
import { mergeClass } from "../composables/useMergedClass"
|
|
17
18
|
import {
|
|
@@ -85,7 +86,8 @@ const text = useLabels<DateRangePickerLabels>(
|
|
|
85
86
|
|
|
86
87
|
const open = ref(false)
|
|
87
88
|
const value = computed(() => normalizeRange(props.modelValue))
|
|
88
|
-
const
|
|
89
|
+
const locale = useLocale(() => props.locale)
|
|
90
|
+
const display = computed(() => (value.value ? formatRange(value.value, locale.value, props.format) : ""))
|
|
89
91
|
|
|
90
92
|
const presetList = computed<DateRangePreset[]>(() => {
|
|
91
93
|
return props.presets ?? defaultRangePresets(text.value)
|
|
@@ -162,7 +162,7 @@ watch(() => props.open, (open) => (open ? claim() : release()), { immediate: tru
|
|
|
162
162
|
onBeforeUnmount(release)
|
|
163
163
|
|
|
164
164
|
const contentClass = computed(() => {
|
|
165
|
-
const surface = frosted.value ? (layer.value.nested ? "lp-glass-overlay--nested" : "lp-glass-overlay") : "bg-surface-raised"
|
|
165
|
+
const surface = frosted.value ? (layer.value.nested ? "lp-glass-overlay lp-glass-overlay--nested" : "lp-glass-overlay") : "bg-surface-raised"
|
|
166
166
|
const base = `fixed z-(--z-modal) flex flex-col border-line ${surface} shadow-panel outline-none`
|
|
167
167
|
const map: Record<Direction, string> = {
|
|
168
168
|
left: "inset-y-0 left-0 border-r rounded-r-card",
|
|
@@ -325,7 +325,7 @@ watch(
|
|
|
325
325
|
<div
|
|
326
326
|
ref="panelRef"
|
|
327
327
|
class="relative flex max-h-[min(90vh,calc(100dvh-2rem))] min-h-0 flex-col overflow-hidden rounded-card border border-line shadow-panel"
|
|
328
|
-
:class="[frosted ? (layer.nested ? 'lp-glass-overlay--nested' : 'lp-glass-overlay') : 'bg-surface-raised', widthClass, tweening ? 'transition-[height] duration-fast ease-[var(--ease-emphasized)] motion-reduce:transition-none' : '']"
|
|
328
|
+
:class="[frosted ? (layer.nested ? 'lp-glass-overlay lp-glass-overlay--nested' : 'lp-glass-overlay') : 'bg-surface-raised', widthClass, tweening ? 'transition-[height] duration-fast ease-[var(--ease-emphasized)] motion-reduce:transition-none' : '']"
|
|
329
329
|
:style="{ ...(width ? { width } : {}), ...(hasAside ? { alignSelf: 'stretch' } : {}) }"
|
|
330
330
|
>
|
|
331
331
|
<DialogTitle v-if="!(title || $slots.title) && ariaLabel" class="sr-only">
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* one the sections are simply unreachable on a phone.
|
|
15
15
|
*/
|
|
16
16
|
import { computed, ref } from "vue"
|
|
17
|
+
import { useGlass } from "../composables/useGlass"
|
|
17
18
|
import { useLabels } from "../composables/useLpConfig"
|
|
18
19
|
import LpButton from "./LpButton.vue"
|
|
19
20
|
import LpIcon from "./LpIcon.vue"
|
|
@@ -127,6 +128,16 @@ const triggerClass = computed(() => TRIGGER_VISIBILITY[props.mobileBreakpoint])
|
|
|
127
128
|
* consuming app's scan.
|
|
128
129
|
*/
|
|
129
130
|
const railStyle = { maxHeight: "min(90vh, calc(100dvh - 2rem))" }
|
|
131
|
+
|
|
132
|
+
/*
|
|
133
|
+
* The rail is part of the dialog, so it takes the same surface: a glass
|
|
134
|
+
* dialog beside a solid rail read as two different windows.
|
|
135
|
+
*/
|
|
136
|
+
const frosted = useGlass(() => props.glass)
|
|
137
|
+
const railPanel = computed(() => [
|
|
138
|
+
"rounded-card border border-line p-2 shadow-panel",
|
|
139
|
+
frosted.value ? "lp-glass-overlay" : "bg-surface-raised",
|
|
140
|
+
])
|
|
130
141
|
</script>
|
|
131
142
|
|
|
132
143
|
<template>
|
|
@@ -158,7 +169,7 @@ const railStyle = { maxHeight: "min(90vh, calc(100dvh - 2rem))" }
|
|
|
158
169
|
responsive
|
|
159
170
|
:mobile-breakpoint="mobileBreakpoint"
|
|
160
171
|
:style="railStyle"
|
|
161
|
-
class="
|
|
172
|
+
:class="railPanel"
|
|
162
173
|
/>
|
|
163
174
|
</div>
|
|
164
175
|
</template>
|
|
@@ -178,7 +189,7 @@ const railStyle = { maxHeight: "min(90vh, calc(100dvh - 2rem))" }
|
|
|
178
189
|
responsive
|
|
179
190
|
:mobile-breakpoint="mobileBreakpoint"
|
|
180
191
|
:style="railStyle"
|
|
181
|
-
class="
|
|
192
|
+
:class="railPanel"
|
|
182
193
|
/>
|
|
183
194
|
</div>
|
|
184
195
|
</template>
|
|
@@ -13,13 +13,14 @@ import {
|
|
|
13
13
|
} from "reka-ui"
|
|
14
14
|
import { nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from "vue"
|
|
15
15
|
import { prefersReducedMotion } from "../composables/easing"
|
|
16
|
+
import { useClipboard } from "../composables/useClipboard"
|
|
16
17
|
import { useLabels } from "../composables/useLpConfig"
|
|
17
18
|
import { useToast, type ToastItem } from "../composables/useToast"
|
|
18
19
|
import { CLOSE_ICON } from "./dropdown"
|
|
19
20
|
import LpIcon from "./LpIcon.vue"
|
|
20
21
|
|
|
21
|
-
const props = defineProps<{ labels?: Partial<{ dismiss: string }> }>()
|
|
22
|
-
const text = useLabels("toast", { dismiss: "Dismiss" }, () => props.labels)
|
|
22
|
+
const props = defineProps<{ labels?: Partial<{ dismiss: string; copy: string; copied: string }> }>()
|
|
23
|
+
const text = useLabels("toast", { dismiss: "Dismiss", copy: "Copy message", copied: "Copied" }, () => props.labels)
|
|
23
24
|
|
|
24
25
|
const { queue, dismiss } = useToast()
|
|
25
26
|
|
|
@@ -211,8 +212,32 @@ async function settle(t: ToastItem, run: () => void | Promise<void>) {
|
|
|
211
212
|
}
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
/*
|
|
216
|
+
* An error is something people need to pass on, so its text can be selected
|
|
217
|
+
* and copied. reka sets user-select: none on the toast and starts a swipe on
|
|
218
|
+
* any press, which made the message impossible to select: the description
|
|
219
|
+
* opts back into selection and keeps its presses from starting a swipe. A
|
|
220
|
+
* click that ends a selection is not a click on the toast.
|
|
221
|
+
*/
|
|
222
|
+
const { copy } = useClipboard()
|
|
223
|
+
const copiedId = ref<string | null>(null)
|
|
224
|
+
let copiedTimer: ReturnType<typeof setTimeout> | undefined
|
|
225
|
+
const copyable = (t: ToastItem) => t.variant === "error" || t.variant === "warning"
|
|
226
|
+
|
|
227
|
+
async function copyToast(t: ToastItem) {
|
|
228
|
+
if (!(await copy([t.title, t.message].filter(Boolean).join("\n")))) return
|
|
229
|
+
copiedId.value = tag(t)
|
|
230
|
+
clearTimeout(copiedTimer)
|
|
231
|
+
copiedTimer = setTimeout(() => (copiedId.value = null), 1500)
|
|
232
|
+
}
|
|
233
|
+
onBeforeUnmount(() => clearTimeout(copiedTimer))
|
|
234
|
+
|
|
235
|
+
function selecting(): boolean {
|
|
236
|
+
return Boolean(window.getSelection()?.toString())
|
|
237
|
+
}
|
|
238
|
+
|
|
214
239
|
function runClick(t: ToastItem) {
|
|
215
|
-
if (swiped === tag(t)) return
|
|
240
|
+
if (swiped === tag(t) || selecting()) return
|
|
216
241
|
if (t.onClick) return settle(t, t.onClick)
|
|
217
242
|
}
|
|
218
243
|
|
|
@@ -250,7 +275,10 @@ function runAction(t: ToastItem, action: NonNullable<ToastItem["actions"]>[numbe
|
|
|
250
275
|
<ToastTitle v-if="t.title" class="text-sm font-semibold text-ink">
|
|
251
276
|
{{ t.title }}
|
|
252
277
|
</ToastTitle>
|
|
253
|
-
<ToastDescription
|
|
278
|
+
<ToastDescription
|
|
279
|
+
class="cursor-text select-text break-words text-xs text-muted"
|
|
280
|
+
@pointerdown.stop
|
|
281
|
+
>
|
|
254
282
|
{{ t.message }}
|
|
255
283
|
</ToastDescription>
|
|
256
284
|
|
|
@@ -274,6 +302,16 @@ function runAction(t: ToastItem, action: NonNullable<ToastItem["actions"]>[numbe
|
|
|
274
302
|
</div>
|
|
275
303
|
</div>
|
|
276
304
|
|
|
305
|
+
<button
|
|
306
|
+
v-if="copyable(t)"
|
|
307
|
+
type="button"
|
|
308
|
+
class="-mt-1 rounded-md p-1 text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
309
|
+
:aria-label="copiedId === tag(t) ? text.copied : text.copy"
|
|
310
|
+
:title="copiedId === tag(t) ? text.copied : text.copy"
|
|
311
|
+
@click.stop="copyToast(t)"
|
|
312
|
+
>
|
|
313
|
+
<LpIcon :name="copiedId === tag(t) ? 'lucide:check' : 'lucide:copy'" :size="15" />
|
|
314
|
+
</button>
|
|
277
315
|
<button
|
|
278
316
|
type="button"
|
|
279
317
|
class="group -mr-1 -mt-1 rounded-md p-1 text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { computed, toValue, type ComputedRef, type MaybeRefOrGetter } from "vue"
|
|
2
|
+
import { injectConfigProviderContext } from "reka-ui"
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* The locale a date is written in: the component's own `locale`, else the one
|
|
6
|
+
* the app gave reka's ConfigProvider, else undefined, which lets Intl use the
|
|
7
|
+
* browser's. The calendars already followed ConfigProvider while the field
|
|
8
|
+
* that shows the picked date did not, so a Russian app showed a Russian
|
|
9
|
+
* calendar under "Oct 8, 2026".
|
|
10
|
+
*/
|
|
11
|
+
export function useLocale(own?: MaybeRefOrGetter<string | undefined>): ComputedRef<string | undefined> {
|
|
12
|
+
const context = injectConfigProviderContext({})
|
|
13
|
+
return computed(() => toValue(own) || context.locale?.value || undefined)
|
|
14
|
+
}
|
package/src/tokens/tokens.css
CHANGED
|
@@ -550,11 +550,14 @@
|
|
|
550
550
|
backdrop-filter: blur(var(--glass-overlay-blur, 28px)) saturate(170%);
|
|
551
551
|
}
|
|
552
552
|
|
|
553
|
+
/*
|
|
554
|
+
* A dialog opened over another is glass too: without its own blur the text of
|
|
555
|
+
* the dialog below read straight through the fill. Its scrim stays unblurred
|
|
556
|
+
* (.lp-scrim--nested), so the only blur is the panel's, and the fill is a
|
|
557
|
+
* little denser than the first layer's, since what it blurs is glass already.
|
|
558
|
+
*/
|
|
553
559
|
.lp-glass-overlay--nested {
|
|
554
|
-
|
|
555
|
-
background-image: none;
|
|
556
|
-
-webkit-backdrop-filter: none;
|
|
557
|
-
backdrop-filter: none;
|
|
560
|
+
--glass-overlay-fill: 62%;
|
|
558
561
|
}
|
|
559
562
|
|
|
560
563
|
:root[data-lp-no-backdrop] .lp-glass-overlay {
|