@leavepulse/ui 0.53.1 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/chunks/LpOtpInput-PbeNJ5In.js +131 -0
- package/dist/chunks/{LpTabs-UM0FQmPA.js → LpTabs-BMSBB78h.js} +44 -17
- package/dist/chunks/LpThemeProvider-CQ2jC9TA.js +69 -0
- package/dist/chunks/{LpThemeSwitcher-CPmhYOjX.js → LpThemeSwitcher-Fz85BCRS.js} +1 -1
- package/dist/chunks/{useTheme-DJm1JSsY.js → useTheme-2qHG8NEU.js} +14 -10
- package/dist/components/LpOtpInput.vue.d.ts +17 -0
- package/dist/components/LpOtpInput.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +10 -2
- package/dist/components/LpTabs.vue.js +1 -1
- package/dist/components/LpThemeProvider.vue.d.ts +5 -0
- package/dist/components/LpThemeProvider.vue.js +1 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/otp.d.ts +2 -0
- package/dist/components/otp.js +17 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +13 -12
- package/dist/theme/useTheme.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/LpOtpInput.vue +84 -28
- package/src/components/LpTabs.vue +60 -21
- package/src/components/LpThemeProvider.vue +49 -6
- package/src/components/otp.ts +29 -0
- package/src/index.ts +1 -0
- package/src/theme/useTheme.ts +28 -14
- package/dist/chunks/LpOtpInput-CziPF3Oq.js +0 -99
- package/dist/chunks/LpThemeProvider-Be4r2TQX.js +0 -35
package/README.md
CHANGED
|
@@ -61,7 +61,9 @@ useTheme().setSystem({ light, dark }) // follow the OS colour scheme
|
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
`LpThemeProvider` applies a theme to one subtree only (a dark sidebar in a light
|
|
64
|
-
app, a live preview).
|
|
64
|
+
app, a live preview). With `transition`, changing its `theme` reveals the new one
|
|
65
|
+
with the same circular transition as the page switch, from where the user last
|
|
66
|
+
pressed. `revealTransition(update, origin)` runs any repaint behind that reveal.
|
|
65
67
|
|
|
66
68
|
### App-wide configuration
|
|
67
69
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { defineComponent, computed, ref, watch, openBlock, createBlock, unref, mergeProps, withCtx, createElementBlock, Fragment, renderList, createVNode, normalizeClass, createCommentVNode } from "vue";
|
|
2
|
+
import { PinInputRoot, PinInputInput } from "reka-ui";
|
|
3
|
+
import { useFieldControl } from "../composables/useField.js";
|
|
4
|
+
import { useMergedAttrs } from "../composables/useMergedClass.js";
|
|
5
|
+
import { splitCode, upperCells, joinCells, groupBreaks } from "../components/otp.js";
|
|
6
|
+
const _hoisted_1 = {
|
|
7
|
+
key: 0,
|
|
8
|
+
"aria-hidden": "true",
|
|
9
|
+
class: "h-0.5 w-2 shrink-0 rounded-full bg-muted opacity-60"
|
|
10
|
+
};
|
|
11
|
+
const __default__ = { inheritAttrs: false };
|
|
12
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
13
|
+
...__default__,
|
|
14
|
+
__name: "LpOtpInput",
|
|
15
|
+
props: {
|
|
16
|
+
modelValue: {},
|
|
17
|
+
length: { default: 6 },
|
|
18
|
+
disabled: { type: Boolean },
|
|
19
|
+
mask: { type: Boolean },
|
|
20
|
+
alphanumeric: { type: Boolean, default: false },
|
|
21
|
+
uppercase: { type: Boolean, default: void 0 },
|
|
22
|
+
group: {},
|
|
23
|
+
invalid: { type: Boolean },
|
|
24
|
+
size: { default: "md" }
|
|
25
|
+
},
|
|
26
|
+
emits: ["update:modelValue", "complete"],
|
|
27
|
+
setup(__props, { emit: __emit }) {
|
|
28
|
+
const props = __props;
|
|
29
|
+
const emit = __emit;
|
|
30
|
+
const upper = computed(() => props.alphanumeric && (props.uppercase ?? true));
|
|
31
|
+
const local = ref(splitCode(props.modelValue, props.length));
|
|
32
|
+
let emitted = props.modelValue ?? "";
|
|
33
|
+
watch(
|
|
34
|
+
() => props.modelValue ?? "",
|
|
35
|
+
(value) => {
|
|
36
|
+
if (value === emitted) return;
|
|
37
|
+
emitted = value;
|
|
38
|
+
local.value = splitCode(value, props.length);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
watch(
|
|
42
|
+
() => props.length,
|
|
43
|
+
(length) => {
|
|
44
|
+
local.value = local.value.slice(0, length);
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
const cells = computed({
|
|
48
|
+
get: () => local.value,
|
|
49
|
+
set: (arr) => {
|
|
50
|
+
local.value = upper.value ? upperCells(arr) : arr;
|
|
51
|
+
emitted = joinCells(local.value);
|
|
52
|
+
emit("update:modelValue", emitted);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
const field = useFieldControl(() => ({
|
|
56
|
+
wrapped: false,
|
|
57
|
+
invalid: props.invalid,
|
|
58
|
+
disabled: props.disabled
|
|
59
|
+
}));
|
|
60
|
+
function onComplete(arr) {
|
|
61
|
+
emit("complete", joinCells(upper.value ? upperCells(arr) : arr));
|
|
62
|
+
}
|
|
63
|
+
const breaks = computed(() => groupBreaks(props.length, props.group));
|
|
64
|
+
const root = ref(null);
|
|
65
|
+
function onBeforeInput(event, index) {
|
|
66
|
+
if (event.inputType !== "deleteContentBackward") return;
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
const target = event.target;
|
|
69
|
+
const next = [...local.value];
|
|
70
|
+
let clear = index;
|
|
71
|
+
if (!target.value && index > 0) {
|
|
72
|
+
clear = index - 1;
|
|
73
|
+
root.value?.$el.querySelectorAll("input")[clear]?.focus();
|
|
74
|
+
}
|
|
75
|
+
next[clear] = props.alphanumeric ? "" : void 0;
|
|
76
|
+
cells.value = next;
|
|
77
|
+
}
|
|
78
|
+
const cellSize = {
|
|
79
|
+
sm: "max-w-9 text-base",
|
|
80
|
+
md: "max-w-11 text-lg",
|
|
81
|
+
lg: "max-w-13 text-xl"
|
|
82
|
+
};
|
|
83
|
+
const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
84
|
+
"flex min-w-0 max-w-full items-center gap-1.5 sm:gap-2"
|
|
85
|
+
);
|
|
86
|
+
return (_ctx, _cache) => {
|
|
87
|
+
return openBlock(), createBlock(unref(PinInputRoot), mergeProps({
|
|
88
|
+
ref_key: "root",
|
|
89
|
+
ref: root,
|
|
90
|
+
modelValue: cells.value,
|
|
91
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => cells.value = $event),
|
|
92
|
+
type: __props.alphanumeric ? "text" : "number",
|
|
93
|
+
mask: __props.mask,
|
|
94
|
+
disabled: unref(field).disabled,
|
|
95
|
+
otp: "",
|
|
96
|
+
class: unref(rootClass)
|
|
97
|
+
}, unref(rest), { onComplete }), {
|
|
98
|
+
default: withCtx(() => [
|
|
99
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.length, (i) => {
|
|
100
|
+
return openBlock(), createElementBlock(Fragment, { key: i }, [
|
|
101
|
+
createVNode(unref(PinInputInput), {
|
|
102
|
+
index: i - 1,
|
|
103
|
+
id: i === 1 ? unref(field).id : void 0,
|
|
104
|
+
"aria-invalid": unref(field).invalid || void 0,
|
|
105
|
+
"aria-describedby": unref(field).describedBy,
|
|
106
|
+
autocapitalize: upper.value ? "characters" : "none",
|
|
107
|
+
autocorrect: "off",
|
|
108
|
+
spellcheck: false,
|
|
109
|
+
class: normalizeClass([
|
|
110
|
+
cellSize[__props.size],
|
|
111
|
+
"aspect-square h-auto min-w-0 flex-1 basis-0 p-0",
|
|
112
|
+
"rounded-control border bg-surface-soft text-center font-semibold text-ink caret-brand",
|
|
113
|
+
"outline-none transition-colors duration-[var(--duration-fast)]",
|
|
114
|
+
"focus:border-brand focus:ring-2 focus:ring-ring",
|
|
115
|
+
"disabled:cursor-not-allowed disabled:opacity-55",
|
|
116
|
+
unref(field).invalid ? "border-danger focus:border-danger focus:ring-danger-soft" : "border-line"
|
|
117
|
+
]),
|
|
118
|
+
onBeforeinput: ($event) => onBeforeInput($event, i - 1)
|
|
119
|
+
}, null, 8, ["index", "id", "aria-invalid", "aria-describedby", "autocapitalize", "class", "onBeforeinput"]),
|
|
120
|
+
breaks.value.has(i - 1) ? (openBlock(), createElementBlock("span", _hoisted_1)) : createCommentVNode("", true)
|
|
121
|
+
], 64);
|
|
122
|
+
}), 128))
|
|
123
|
+
]),
|
|
124
|
+
_: 1
|
|
125
|
+
}, 16, ["modelValue", "type", "mask", "disabled", "class"]);
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
export {
|
|
130
|
+
_sfc_main as _
|
|
131
|
+
};
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import { defineComponent, ref, watch, nextTick, useId,
|
|
1
|
+
import { defineComponent, computed, ref, watch, nextTick, useId, openBlock, createBlock, unref, withCtx, createVNode, normalizeClass, createElementBlock, Fragment, renderList, createCommentVNode, createElementVNode, toDisplayString, renderSlot } from "vue";
|
|
2
2
|
import { useReducedMotion, Motion } from "motion-v";
|
|
3
3
|
import { TabsRoot, TabsList, TabsTrigger, TabsContent } from "reka-ui";
|
|
4
4
|
import { usePillTransition } from "../composables/usePillTransition.js";
|
|
5
5
|
import { _ as _sfc_main$1 } from "./LpIcon-DYtaid0K.js";
|
|
6
|
-
const _hoisted_1 = {
|
|
6
|
+
const _hoisted_1 = {
|
|
7
|
+
key: 1,
|
|
8
|
+
class: "relative z-10 inline-flex"
|
|
9
|
+
};
|
|
10
|
+
const _hoisted_2 = {
|
|
11
|
+
key: 0,
|
|
12
|
+
"aria-hidden": "true",
|
|
13
|
+
class: "absolute -right-1 -top-0.5 size-2 rounded-full bg-accent"
|
|
14
|
+
};
|
|
15
|
+
const _hoisted_3 = {
|
|
16
|
+
key: 2,
|
|
17
|
+
"aria-hidden": "true",
|
|
18
|
+
class: "relative z-10 size-1.5 self-start rounded-full bg-accent"
|
|
19
|
+
};
|
|
7
20
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
8
21
|
__name: "LpTabs",
|
|
9
22
|
props: {
|
|
@@ -12,11 +25,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
12
25
|
items: {},
|
|
13
26
|
variant: { default: "contained" },
|
|
14
27
|
accent: { type: Boolean, default: false },
|
|
15
|
-
block: { type: Boolean, default: false }
|
|
28
|
+
block: { type: Boolean, default: false },
|
|
29
|
+
label: {}
|
|
16
30
|
},
|
|
17
31
|
emits: ["update:modelValue"],
|
|
18
32
|
setup(__props, { emit: __emit }) {
|
|
19
33
|
const props = __props;
|
|
34
|
+
const bottom = computed(() => props.variant === "bottom");
|
|
20
35
|
const emit = __emit;
|
|
21
36
|
const current = ref(props.modelValue ?? props.defaultValue ?? props.items[0]?.value);
|
|
22
37
|
watch(
|
|
@@ -50,6 +65,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
50
65
|
() => reduceMotion.value ? { duration: 0 } : { type: "spring", stiffness: 520, damping: 42, mass: 0.9 }
|
|
51
66
|
);
|
|
52
67
|
function pillUnder(value, active) {
|
|
68
|
+
if (bottom.value) return active === value;
|
|
53
69
|
return hovered.value ? hovered.value === value : active === value;
|
|
54
70
|
}
|
|
55
71
|
function releaseFocusAfterPointer(event) {
|
|
@@ -65,11 +81,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
65
81
|
createVNode(unref(TabsList), {
|
|
66
82
|
ref_key: "list",
|
|
67
83
|
ref: list,
|
|
68
|
-
|
|
84
|
+
"aria-label": __props.label,
|
|
85
|
+
class: normalizeClass(bottom.value ? "grid w-full auto-cols-fr grid-flow-col border-t border-line bg-surface pb-[env(safe-area-inset-bottom)] pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]" : [
|
|
86
|
+
"max-w-full gap-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
69
87
|
__props.block ? "flex w-full" : "inline-flex",
|
|
70
88
|
__props.variant === "contained" ? "rounded-control border border-line bg-surface-soft p-1" : "",
|
|
71
89
|
__props.variant === "underline" ? "border-b border-line" : ""
|
|
72
|
-
]
|
|
90
|
+
]),
|
|
73
91
|
onPointerleave: _cache[0] || (_cache[0] = ($event) => hovered.value = null)
|
|
74
92
|
}, {
|
|
75
93
|
default: withCtx(() => [
|
|
@@ -77,11 +95,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
77
95
|
return openBlock(), createBlock(unref(TabsTrigger), {
|
|
78
96
|
key: item.value,
|
|
79
97
|
value: item.value,
|
|
80
|
-
class: normalizeClass(["relative inline-flex
|
|
81
|
-
|
|
82
|
-
__props.
|
|
98
|
+
class: normalizeClass(["relative inline-flex items-center justify-center outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring", [
|
|
99
|
+
bottom.value ? "min-h-14 min-w-0 flex-col gap-0.5 px-1 py-1.5 text-[11px] font-medium focus-visible:ring-inset" : "shrink-0 gap-1.5 whitespace-nowrap text-sm",
|
|
100
|
+
__props.block && !bottom.value ? "flex-1" : "",
|
|
101
|
+
__props.variant === "underline" ? "rounded-t-md px-3 pt-1.5 pb-2" : "",
|
|
102
|
+
__props.variant === "contained" || __props.variant === "plain" ? "rounded-md px-3 py-1.5" : "",
|
|
83
103
|
__props.accent ? "data-[state=active]:text-brand" : "data-[state=active]:text-ink",
|
|
84
|
-
hovered.value === item.value ? "text-ink" : "text-muted"
|
|
104
|
+
hovered.value === item.value && !bottom.value ? "text-ink" : "text-muted"
|
|
85
105
|
]]),
|
|
86
106
|
onPointerenter: ($event) => hovered.value = item.value,
|
|
87
107
|
onPointerup: releaseFocusAfterPointer
|
|
@@ -94,25 +114,32 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
94
114
|
class: normalizeClass(__props.variant === "underline" ? [
|
|
95
115
|
"absolute inset-x-0 -bottom-px z-0 h-0.5 rounded-full",
|
|
96
116
|
__props.accent ? "bg-brand" : "bg-ink"
|
|
117
|
+
] : bottom.value ? [
|
|
118
|
+
"absolute inset-x-[22%] top-0 z-0 h-0.5 rounded-b-full",
|
|
119
|
+
__props.accent ? "bg-brand" : "bg-ink"
|
|
97
120
|
] : [
|
|
98
121
|
"absolute inset-0 z-0 rounded-md shadow-sm",
|
|
99
122
|
__props.accent ? "border border-brand/35 bg-brand/12" : "border border-line bg-surface-raised"
|
|
100
123
|
])
|
|
101
124
|
}, null, 8, ["transition", "class"])) : createCommentVNode("", true),
|
|
102
|
-
item.icon ? (openBlock(),
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
125
|
+
item.icon ? (openBlock(), createElementBlock("span", _hoisted_1, [
|
|
126
|
+
createVNode(_sfc_main$1, {
|
|
127
|
+
name: item.icon,
|
|
128
|
+
size: bottom.value ? 22 : 14
|
|
129
|
+
}, null, 8, ["name", "size"]),
|
|
130
|
+
item.dot ? (openBlock(), createElementBlock("span", _hoisted_2)) : createCommentVNode("", true)
|
|
131
|
+
])) : createCommentVNode("", true),
|
|
132
|
+
createElementVNode("span", {
|
|
133
|
+
class: normalizeClass(["relative z-10", bottom.value ? "max-w-full truncate" : ""])
|
|
134
|
+
}, toDisplayString(item.label), 3),
|
|
135
|
+
item.dot && !item.icon ? (openBlock(), createElementBlock("span", _hoisted_3)) : createCommentVNode("", true)
|
|
109
136
|
]),
|
|
110
137
|
_: 2
|
|
111
138
|
}, 1032, ["value", "class", "onPointerenter"]);
|
|
112
139
|
}), 128))
|
|
113
140
|
]),
|
|
114
141
|
_: 1
|
|
115
|
-
}, 8, ["class"]),
|
|
142
|
+
}, 8, ["aria-label", "class"]),
|
|
116
143
|
_ctx.$slots.panel ? (openBlock(), createBlock(unref(Motion), {
|
|
117
144
|
key: 0,
|
|
118
145
|
layout: true,
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defineComponent, ref, shallowRef, computed, watch, nextTick, openBlock, createBlock, resolveDynamicComponent, mergeProps, unref, withCtx, renderSlot } from "vue";
|
|
2
|
+
import { t as themeEntries, r as revealTransition } from "./useTheme-2qHG8NEU.js";
|
|
3
|
+
import { useMergedAttrs } from "../composables/useMergedClass.js";
|
|
4
|
+
const PRESS_FRESH_MS = 1500;
|
|
5
|
+
let lastPress = null;
|
|
6
|
+
if (typeof window !== "undefined") {
|
|
7
|
+
window.addEventListener(
|
|
8
|
+
"pointerdown",
|
|
9
|
+
(event) => lastPress = { x: event.clientX, y: event.clientY, at: performance.now() },
|
|
10
|
+
{ capture: true, passive: true }
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
const __default__ = { inheritAttrs: false };
|
|
14
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
15
|
+
...__default__,
|
|
16
|
+
__name: "LpThemeProvider",
|
|
17
|
+
props: {
|
|
18
|
+
theme: {},
|
|
19
|
+
as: { default: "div" },
|
|
20
|
+
transition: { type: Boolean, default: false }
|
|
21
|
+
},
|
|
22
|
+
setup(__props) {
|
|
23
|
+
const props = __props;
|
|
24
|
+
const { class: rootClass, attrs: rest } = useMergedAttrs("bg-surface text-ink");
|
|
25
|
+
const root = ref(null);
|
|
26
|
+
const shown = shallowRef(props.theme);
|
|
27
|
+
const style = computed(() => ({
|
|
28
|
+
...Object.fromEntries(themeEntries(shown.value)),
|
|
29
|
+
colorScheme: shown.value.mode
|
|
30
|
+
}));
|
|
31
|
+
function originOf() {
|
|
32
|
+
if (lastPress && performance.now() - lastPress.at < PRESS_FRESH_MS) return lastPress;
|
|
33
|
+
const value = root.value;
|
|
34
|
+
const el = value instanceof HTMLElement ? value : value?.$el;
|
|
35
|
+
const box = el?.getBoundingClientRect?.();
|
|
36
|
+
return box ? { x: box.left + box.width / 2, y: box.top + box.height / 2 } : void 0;
|
|
37
|
+
}
|
|
38
|
+
watch(
|
|
39
|
+
() => props.theme,
|
|
40
|
+
(next) => {
|
|
41
|
+
if (!props.transition) {
|
|
42
|
+
shown.value = next;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
revealTransition(async () => {
|
|
46
|
+
shown.value = next;
|
|
47
|
+
await nextTick();
|
|
48
|
+
}, originOf());
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
return (_ctx, _cache) => {
|
|
52
|
+
return openBlock(), createBlock(resolveDynamicComponent(__props.as), mergeProps({
|
|
53
|
+
ref_key: "root",
|
|
54
|
+
ref: root,
|
|
55
|
+
style: style.value,
|
|
56
|
+
"data-theme-mode": shown.value.mode,
|
|
57
|
+
class: unref(rootClass)
|
|
58
|
+
}, unref(rest)), {
|
|
59
|
+
default: withCtx(() => [
|
|
60
|
+
renderSlot(_ctx.$slots, "default")
|
|
61
|
+
]),
|
|
62
|
+
_: 3
|
|
63
|
+
}, 16, ["style", "data-theme-mode", "class"]);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
export {
|
|
68
|
+
_sfc_main as _
|
|
69
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineComponent, computed, onMounted, ref, openBlock, createBlock, withCtx, createElementVNode, normalizeClass, createElementBlock, createVNode, toDisplayString, createCommentVNode } from "vue";
|
|
2
2
|
import { useLabels } from "../composables/useLpConfig.js";
|
|
3
|
-
import { u as useTheme, p as presets } from "./useTheme-
|
|
3
|
+
import { u as useTheme, p as presets } from "./useTheme-2qHG8NEU.js";
|
|
4
4
|
import { _ as _sfc_main$1 } from "./LpContextMenu-EF_90u3g.js";
|
|
5
5
|
import { _ as _sfc_main$2 } from "./LpIcon-DYtaid0K.js";
|
|
6
6
|
const _hoisted_1 = ["aria-label", "title"];
|
|
@@ -439,10 +439,10 @@ function applyTheme(theme, root = document.documentElement) {
|
|
|
439
439
|
root.style.colorScheme = theme.mode;
|
|
440
440
|
detectBackdropFilter(root);
|
|
441
441
|
}
|
|
442
|
-
function
|
|
442
|
+
function revealTransition(update, origin, durationMs = 480) {
|
|
443
443
|
const doc = document;
|
|
444
444
|
if (typeof doc.startViewTransition !== "function" || prefersReducedMotion()) {
|
|
445
|
-
|
|
445
|
+
void update();
|
|
446
446
|
return;
|
|
447
447
|
}
|
|
448
448
|
const x = origin?.x ?? window.innerWidth / 2;
|
|
@@ -451,9 +451,9 @@ function applyThemeWithTransition(theme, origin, root = document.documentElement
|
|
|
451
451
|
Math.max(x, window.innerWidth - x),
|
|
452
452
|
Math.max(y, window.innerHeight - y)
|
|
453
453
|
);
|
|
454
|
-
const transition = doc.startViewTransition(
|
|
454
|
+
const transition = doc.startViewTransition(update);
|
|
455
455
|
transition.ready.then(() => {
|
|
456
|
-
|
|
456
|
+
document.documentElement.animate(
|
|
457
457
|
{
|
|
458
458
|
clipPath: [`circle(${endRadius}px at ${x}px ${y}px)`, `circle(0px at ${x}px ${y}px)`]
|
|
459
459
|
},
|
|
@@ -471,6 +471,9 @@ function applyThemeWithTransition(theme, origin, root = document.documentElement
|
|
|
471
471
|
);
|
|
472
472
|
});
|
|
473
473
|
}
|
|
474
|
+
function applyThemeWithTransition(theme, origin, root = document.documentElement, durationMs = 480) {
|
|
475
|
+
revealTransition(() => applyTheme(theme, root), origin, durationMs);
|
|
476
|
+
}
|
|
474
477
|
function serializeTheme(theme) {
|
|
475
478
|
return JSON.stringify(theme);
|
|
476
479
|
}
|
|
@@ -614,14 +617,15 @@ export {
|
|
|
614
617
|
light as l,
|
|
615
618
|
prefersDarkScheme as m,
|
|
616
619
|
nord as n,
|
|
617
|
-
|
|
620
|
+
rose as o,
|
|
618
621
|
presets as p,
|
|
619
|
-
|
|
620
|
-
|
|
622
|
+
setGlassBackdrop as q,
|
|
623
|
+
revealTransition as r,
|
|
621
624
|
serializeTheme as s,
|
|
622
625
|
themeEntries as t,
|
|
623
626
|
useTheme as u,
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
+
themeFromCookie as v,
|
|
628
|
+
themeToCssRule as w,
|
|
629
|
+
themeToCssVars as x,
|
|
630
|
+
violet as y
|
|
627
631
|
};
|
|
@@ -10,6 +10,14 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
10
10
|
mask?: boolean;
|
|
11
11
|
/** Allow letters too (backup codes). Default: digits only (TOTP). */
|
|
12
12
|
alphanumeric?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Turn typed letters into capitals, and open a phone's keyboard in capitals.
|
|
15
|
+
* Default: on with `alphanumeric`, where codes are printed in capitals and
|
|
16
|
+
* compared without regard to case; pass `false` for a case-sensitive code.
|
|
17
|
+
*/
|
|
18
|
+
uppercase?: boolean;
|
|
19
|
+
/** Draw a separator after every `group` cells (e.g. 3 for "123-456"). */
|
|
20
|
+
group?: number;
|
|
13
21
|
/** Error state — tints the cells red (e.g. wrong code). */
|
|
14
22
|
invalid?: boolean;
|
|
15
23
|
size?: "sm" | "md" | "lg";
|
|
@@ -26,6 +34,14 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
26
34
|
mask?: boolean;
|
|
27
35
|
/** Allow letters too (backup codes). Default: digits only (TOTP). */
|
|
28
36
|
alphanumeric?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Turn typed letters into capitals, and open a phone's keyboard in capitals.
|
|
39
|
+
* Default: on with `alphanumeric`, where codes are printed in capitals and
|
|
40
|
+
* compared without regard to case; pass `false` for a case-sensitive code.
|
|
41
|
+
*/
|
|
42
|
+
uppercase?: boolean;
|
|
43
|
+
/** Draw a separator after every `group` cells (e.g. 3 for "123-456"). */
|
|
44
|
+
group?: number;
|
|
29
45
|
/** Error state — tints the cells red (e.g. wrong code). */
|
|
30
46
|
invalid?: boolean;
|
|
31
47
|
size?: "sm" | "md" | "lg";
|
|
@@ -35,5 +51,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
35
51
|
}>, {
|
|
36
52
|
size: "sm" | "md" | "lg";
|
|
37
53
|
length: number;
|
|
54
|
+
uppercase: boolean;
|
|
38
55
|
alphanumeric: boolean;
|
|
39
56
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -3,6 +3,8 @@ export interface TabItem {
|
|
|
3
3
|
label: string;
|
|
4
4
|
/** Optional iconify name (e.g. "lucide:palette"), shown left of the label. */
|
|
5
5
|
icon?: string;
|
|
6
|
+
/** A small dot on the tab: something behind it wants a look (unread, a problem). */
|
|
7
|
+
dot?: boolean;
|
|
6
8
|
}
|
|
7
9
|
type __VLS_Props = {
|
|
8
10
|
modelValue?: string;
|
|
@@ -15,12 +17,18 @@ type __VLS_Props = {
|
|
|
15
17
|
* sliding pill marking the active one (for nav bars over a custom surface).
|
|
16
18
|
* "underline" is a flat row over a hairline baseline, marking the active
|
|
17
19
|
* tab with a sliding bottom bar instead of a pill (page-section nav style).
|
|
20
|
+
* "bottom" is a phone's bottom navigation: full width, equal-share tabs
|
|
21
|
+
* with the icon over the label, a sliding bar along the top edge marking
|
|
22
|
+
* the active one, and padding for the gesture strip and side insets of an
|
|
23
|
+
* edge-to-edge screen. Place it as the last row of the layout.
|
|
18
24
|
*/
|
|
19
|
-
variant?: "contained" | "plain" | "underline";
|
|
25
|
+
variant?: "contained" | "plain" | "underline" | "bottom";
|
|
20
26
|
/** Tint the active pill + label with the brand colour (nav-bar style). */
|
|
21
27
|
accent?: boolean;
|
|
22
28
|
/** Stretch the bar to full width with equal-share triggers. */
|
|
23
29
|
block?: boolean;
|
|
30
|
+
/** Accessible name of the tab list, e.g. "Main" for an app's navigation. */
|
|
31
|
+
label?: string;
|
|
24
32
|
};
|
|
25
33
|
declare var __VLS_51: {
|
|
26
34
|
value: string;
|
|
@@ -36,7 +44,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
36
44
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
37
45
|
}>, {
|
|
38
46
|
block: boolean;
|
|
39
|
-
variant: "contained" | "plain" | "underline";
|
|
47
|
+
variant: "contained" | "plain" | "underline" | "bottom";
|
|
40
48
|
accent: boolean;
|
|
41
49
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
42
50
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -6,12 +6,17 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
|
6
6
|
theme: TokenSet;
|
|
7
7
|
/** Root element. A wrapper that should not affect layout can use `class="contents"`. */
|
|
8
8
|
as?: string | Component;
|
|
9
|
+
/** Reveal a change of `theme` with the circular transition. */
|
|
10
|
+
transition?: boolean;
|
|
9
11
|
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
|
|
10
12
|
theme: TokenSet;
|
|
11
13
|
/** Root element. A wrapper that should not affect layout can use `class="contents"`. */
|
|
12
14
|
as?: string | Component;
|
|
15
|
+
/** Reveal a change of `theme` with the circular transition. */
|
|
16
|
+
transition?: boolean;
|
|
13
17
|
}> & Readonly<{}>, {
|
|
14
18
|
as: string | Component;
|
|
19
|
+
transition: boolean;
|
|
15
20
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
16
21
|
default?: (props: {}) => any;
|
|
17
22
|
}>;
|
package/dist/components/otp.d.ts
CHANGED
|
@@ -3,3 +3,5 @@ export type OtpCells = (string | number | undefined)[];
|
|
|
3
3
|
export declare function joinCells(cells: OtpCells): string;
|
|
4
4
|
/** Cells for a code given from outside, one character each. */
|
|
5
5
|
export declare function splitCode(code: string | undefined, length: number): string[];
|
|
6
|
+
export declare function upperCells<T extends OtpCells>(cells: T): T;
|
|
7
|
+
export declare function groupBreaks(length: number, group: number | undefined): Set<number>;
|
package/dist/components/otp.js
CHANGED
|
@@ -4,7 +4,23 @@ function joinCells(cells) {
|
|
|
4
4
|
function splitCode(code, length) {
|
|
5
5
|
return (code ?? "").split("").slice(0, length);
|
|
6
6
|
}
|
|
7
|
+
function upperCells(cells) {
|
|
8
|
+
const out = [];
|
|
9
|
+
cells.forEach((c, i) => {
|
|
10
|
+
out[i] = typeof c === "string" ? c.toUpperCase() : c;
|
|
11
|
+
});
|
|
12
|
+
out.length = cells.length;
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
function groupBreaks(length, group) {
|
|
16
|
+
const breaks = /* @__PURE__ */ new Set();
|
|
17
|
+
if (!group || group < 1 || group >= length) return breaks;
|
|
18
|
+
for (let i = group; i < length; i += group) breaks.add(i - 1);
|
|
19
|
+
return breaks;
|
|
20
|
+
}
|
|
7
21
|
export {
|
|
22
|
+
groupBreaks,
|
|
8
23
|
joinCells,
|
|
9
|
-
splitCode
|
|
24
|
+
splitCode,
|
|
25
|
+
upperCells
|
|
10
26
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -168,7 +168,7 @@ export { blockTitle, defineBlocks } from "./layout/registry";
|
|
|
168
168
|
export type { BlockDef, BlockRegistry } from "./layout/registry";
|
|
169
169
|
export { useLayout } from "./layout/useLayout";
|
|
170
170
|
export type { UseLayout, UseLayoutOptions } from "./layout/useLayout";
|
|
171
|
-
export { applyTheme, applyThemeWithTransition, bootstrapTheme, parseTheme, serializeTheme, THEME_COOKIE, themeFromCookie, themeToCssRule, themeToCssVars, useTheme, } from "./theme/useTheme";
|
|
171
|
+
export { applyTheme, applyThemeWithTransition, revealTransition, bootstrapTheme, parseTheme, serializeTheme, THEME_COOKIE, themeFromCookie, themeToCssRule, themeToCssVars, useTheme, } from "./theme/useTheme";
|
|
172
172
|
export type { RevealOrigin } from "./theme/useTheme";
|
|
173
173
|
export { detectBackdropFilter, GLASS_BACKDROP_ATTR, isBrokenBackdropEngine, NO_BACKDROP_ATTR, setGlassBackdrop } from "./theme/backdrop";
|
|
174
174
|
export { DEFAULT_SURFACE } from "./theme/tokens";
|
package/dist/index.js
CHANGED
|
@@ -65,7 +65,7 @@ import { _ as _41 } from "./chunks/LpNotificationBell-wZ3meeim.js";
|
|
|
65
65
|
import { _ as _42 } from "./chunks/LpNumberField-B77O-z28.js";
|
|
66
66
|
import { _ as _43 } from "./chunks/LpTimeField-Cqe7fXnh.js";
|
|
67
67
|
import { _ as _44 } from "./chunks/LpNumberFlow-z4WPZcZu.js";
|
|
68
|
-
import { _ as _45 } from "./chunks/LpOtpInput-
|
|
68
|
+
import { _ as _45 } from "./chunks/LpOtpInput-PbeNJ5In.js";
|
|
69
69
|
import { _ as _46 } from "./chunks/LpPagination-BcDlo3r_.js";
|
|
70
70
|
import { _ as _47 } from "./chunks/LpPasswordInput-eKzQhbQP.js";
|
|
71
71
|
import { _ as _48 } from "./chunks/LpPie-B7ti5qCH.js";
|
|
@@ -96,11 +96,11 @@ import { _ as _69 } from "./chunks/LpSwitch-DG2AhXIL.js";
|
|
|
96
96
|
import { default as default12 } from "./components/LpTable.vue.js";
|
|
97
97
|
import { compareValues } from "./components/tableSort.js";
|
|
98
98
|
import { _ as _70 } from "./chunks/LpTableOfContents-BUcAfGPQ.js";
|
|
99
|
-
import { _ as _71 } from "./chunks/LpTabs-
|
|
99
|
+
import { _ as _71 } from "./chunks/LpTabs-BMSBB78h.js";
|
|
100
100
|
import { _ as _72 } from "./chunks/LpTagsInput-D1SuqbhB.js";
|
|
101
101
|
import { addTags, splitTags } from "./components/tags.js";
|
|
102
102
|
import { _ as _73 } from "./chunks/LpTextarea-uuScWo6-.js";
|
|
103
|
-
import { _ as _74 } from "./chunks/LpThemeSwitcher-
|
|
103
|
+
import { _ as _74 } from "./chunks/LpThemeSwitcher-Fz85BCRS.js";
|
|
104
104
|
import { _ as _75 } from "./chunks/LpTilt-B7KHX1zH.js";
|
|
105
105
|
import { _ as _76 } from "./chunks/LpToaster-DTtWuKvq.js";
|
|
106
106
|
import { _ as _77 } from "./chunks/LpTooltip-CXVKcOXT.js";
|
|
@@ -111,8 +111,8 @@ import { deserializeLayout, serializeLayout } from "./layout/tree.js";
|
|
|
111
111
|
import { addLeaf, addTab, countBlocks, countLeaves, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, setActiveTab } from "./layout/tree.js";
|
|
112
112
|
import { blockTitle, defineBlocks } from "./layout/registry.js";
|
|
113
113
|
import { layoutController, useLayout } from "./layout/useLayout.js";
|
|
114
|
-
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/useTheme-
|
|
115
|
-
import { D, G, N, T, b as b2, c as c2, d, e, f, g, h, i as i2, l, j, n, k, m, r, o,
|
|
114
|
+
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/useTheme-2qHG8NEU.js";
|
|
115
|
+
import { D, G, N, T, b as b2, c as c2, d, e, f, g, h, i as i2, l, j, n, k, m, r, o, q, t, v, w, x, u, y } from "./chunks/useTheme-2qHG8NEU.js";
|
|
116
116
|
import { useClipboard } from "./composables/useClipboard.js";
|
|
117
117
|
import { activeShortcuts, appleModifierLabel, findHotkeyConflicts, hotkeyConflicts, hotkeySteps, isAppleKeyboard, matchesHotkey, mergeShortcutGroups, pendingHotkey, sequenceProgress, useAppleKeyboard, useHotkeys } from "./composables/useHotkeys.js";
|
|
118
118
|
import { anyModalOpen, topModalElement, useModalLayer } from "./components/modalDepth.js";
|
|
@@ -137,7 +137,7 @@ import { useShift } from "./composables/useShift.js";
|
|
|
137
137
|
import { useTilt } from "./composables/useTilt.js";
|
|
138
138
|
import { useZoomPan } from "./composables/useZoomPan.js";
|
|
139
139
|
import { useToast } from "./composables/useToast.js";
|
|
140
|
-
import { _ as _81 } from "./chunks/LpThemeProvider-
|
|
140
|
+
import { _ as _81 } from "./chunks/LpThemeProvider-CQ2jC9TA.js";
|
|
141
141
|
import { isInternalHref, resolveLink } from "./components/link.js";
|
|
142
142
|
function defineTheme(base, overrides = {}) {
|
|
143
143
|
const src = typeof base === "string" ? presets[base] : base;
|
|
@@ -399,10 +399,11 @@ export {
|
|
|
399
399
|
resolveCssColor,
|
|
400
400
|
resolveLink,
|
|
401
401
|
resolveSlices,
|
|
402
|
+
r as revealTransition,
|
|
402
403
|
rgbToHex,
|
|
403
404
|
rgbToHsv,
|
|
404
405
|
ringWindow,
|
|
405
|
-
|
|
406
|
+
o as rose,
|
|
406
407
|
sameRange,
|
|
407
408
|
seamProgress,
|
|
408
409
|
seamReached,
|
|
@@ -411,7 +412,7 @@ export {
|
|
|
411
412
|
serializeLayout,
|
|
412
413
|
serializeTheme,
|
|
413
414
|
setActiveTab,
|
|
414
|
-
|
|
415
|
+
q as setGlassBackdrop,
|
|
415
416
|
sortNodes,
|
|
416
417
|
splitTags,
|
|
417
418
|
stepMatch,
|
|
@@ -420,9 +421,9 @@ export {
|
|
|
420
421
|
subtreeSize,
|
|
421
422
|
svgToPng,
|
|
422
423
|
t as themeEntries,
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
424
|
+
v as themeFromCookie,
|
|
425
|
+
w as themeToCssRule,
|
|
426
|
+
x as themeToCssVars,
|
|
426
427
|
tileUrl,
|
|
427
428
|
toCsv,
|
|
428
429
|
toRecentItem,
|
|
@@ -459,5 +460,5 @@ export {
|
|
|
459
460
|
useTilt,
|
|
460
461
|
useToast,
|
|
461
462
|
useZoomPan,
|
|
462
|
-
|
|
463
|
+
y as violet
|
|
463
464
|
};
|