@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 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, computed, openBlock, createBlock, unref, withCtx, createVNode, normalizeClass, createElementBlock, Fragment, renderList, createCommentVNode, createElementVNode, toDisplayString, renderSlot } from "vue";
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 = { class: "relative z-10" };
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
- class: normalizeClass(["max-w-full gap-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", [
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 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring", [
81
- __props.block ? "flex-1" : "",
82
- __props.variant === "underline" ? "rounded-t-md px-3 pt-1.5 pb-2" : "rounded-md px-3 py-1.5",
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(), createBlock(_sfc_main$1, {
103
- key: 1,
104
- name: item.icon,
105
- size: 14,
106
- class: "relative z-10"
107
- }, null, 8, ["name"])) : createCommentVNode("", true),
108
- createElementVNode("span", _hoisted_1, toDisplayString(item.label), 1)
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-DJm1JSsY.js";
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 applyThemeWithTransition(theme, origin, root = document.documentElement, durationMs = 480) {
442
+ function revealTransition(update, origin, durationMs = 480) {
443
443
  const doc = document;
444
444
  if (typeof doc.startViewTransition !== "function" || prefersReducedMotion()) {
445
- applyTheme(theme, root);
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(() => applyTheme(theme, root));
454
+ const transition = doc.startViewTransition(update);
455
455
  transition.ready.then(() => {
456
- root.animate(
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
- setGlassBackdrop as o,
620
+ rose as o,
618
621
  presets as p,
619
- themeFromCookie as q,
620
- rose as r,
622
+ setGlassBackdrop as q,
623
+ revealTransition as r,
621
624
  serializeTheme as s,
622
625
  themeEntries as t,
623
626
  useTheme as u,
624
- themeToCssRule as v,
625
- themeToCssVars as w,
626
- violet as x
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>;
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpOtpInput-CziPF3Oq.js";
1
+ import { _ as _sfc_main } from "../chunks/LpOtpInput-PbeNJ5In.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -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>;
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpTabs-UM0FQmPA.js";
1
+ import { _ as _sfc_main } from "../chunks/LpTabs-BMSBB78h.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -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
  }>;
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpThemeProvider-Be4r2TQX.js";
1
+ import { _ as _sfc_main } from "../chunks/LpThemeProvider-CQ2jC9TA.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpThemeSwitcher-CPmhYOjX.js";
1
+ import { _ as _sfc_main } from "../chunks/LpThemeSwitcher-Fz85BCRS.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -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>;
@@ -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-CziPF3Oq.js";
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-UM0FQmPA.js";
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-CPmhYOjX.js";
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-DJm1JSsY.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, t, q, v, w, u, x } from "./chunks/useTheme-DJm1JSsY.js";
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-Be4r2TQX.js";
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
- r as rose,
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
- o as setGlassBackdrop,
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
- q as themeFromCookie,
424
- v as themeToCssRule,
425
- w as themeToCssVars,
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
- x as violet
463
+ y as violet
463
464
  };