@leavepulse/ui 0.20.6 → 0.20.8

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.
Files changed (27) hide show
  1. package/dist/assets/{LpCommandPalette-Cp6Y-j7g.css → LpCommandPalette-C3LdDNHk.css} +4 -4
  2. package/dist/chunks/{LpAddressInput-l2Znlwgc.js → LpAddressInput-DaJ97mQ4.js} +1 -1
  3. package/dist/chunks/{LpAppShell-D9KnS0j_.js → LpAppShell-Ds3WkurD.js} +1 -1
  4. package/dist/chunks/{LpConfirmDialog-gtsGL1kb.js → LpConfirmDialog-Cwqzbfgo.js} +1 -1
  5. package/dist/chunks/{LpDrawer-CYVF8abJ.js → LpDrawer-DcxlpxJ7.js} +1 -1
  6. package/dist/chunks/{LpLightbox-CzhFe9wZ.js → LpLightbox-Ci35Y_xP.js} +1 -1
  7. package/dist/chunks/{LpModal-BLOKvrJM.js → LpModal-2YEJI45Q.js} +1 -1
  8. package/dist/chunks/{LpSidebar-BaqVlOmo.js → LpSidebar-B_UD_yUx.js} +1 -1
  9. package/dist/chunks/{LpTabs-D7aTVPOb.js → LpTabs-Cefe_lys.js} +6 -1
  10. package/dist/components/LpAddressInput.vue.js +1 -1
  11. package/dist/components/LpAppShell.vue.js +1 -1
  12. package/dist/components/LpCommandPalette.vue.js +3 -3
  13. package/dist/components/LpConfirmDialog.vue.js +1 -1
  14. package/dist/components/LpDrawer.vue.js +1 -1
  15. package/dist/components/LpLightbox.vue.js +1 -1
  16. package/dist/components/LpModal.vue.js +1 -1
  17. package/dist/components/LpSidebar.vue.js +1 -1
  18. package/dist/components/LpTabs.vue.d.ts +4 -4
  19. package/dist/components/LpTabs.vue.js +1 -1
  20. package/dist/index.js +8 -8
  21. package/package.json +1 -1
  22. package/src/components/LpCommandPalette.vue +1 -1
  23. package/src/components/LpDrawer.vue +1 -1
  24. package/src/components/LpLightbox.vue +1 -1
  25. package/src/components/LpModal.vue +1 -1
  26. package/src/components/LpTabs.vue +20 -0
  27. package/src/tokens/tokens.css +20 -0
@@ -1,16 +1,16 @@
1
1
 
2
2
  /* Each result eases in; honours reduced motion. */
3
- .lp-cmd-item[data-v-7fba2dd8] {
4
- animation: lp-cmd-in-7fba2dd8 140ms ease-out both;
3
+ .lp-cmd-item[data-v-75a17488] {
4
+ animation: lp-cmd-in-75a17488 140ms ease-out both;
5
5
  }
6
- @keyframes lp-cmd-in-7fba2dd8 {
6
+ @keyframes lp-cmd-in-75a17488 {
7
7
  from {
8
8
  opacity: 0;
9
9
  transform: translateY(3px);
10
10
  }
11
11
  }
12
12
  @media (prefers-reduced-motion: reduce) {
13
- .lp-cmd-item[data-v-7fba2dd8] {
13
+ .lp-cmd-item[data-v-75a17488] {
14
14
  animation: none;
15
15
  }
16
16
  }
@@ -6,7 +6,7 @@ import { _ as _sfc_main$3 } from "./LpButton-5VXXCjwF.js";
6
6
  import { _ as _sfc_main$1 } from "./LpFormField-Bn-ZwC6z.js";
7
7
  import { _ as _sfc_main$4 } from "./LpIcon-CCnX5_2j.js";
8
8
  import { _ as _sfc_main$5 } from "./LpInput-BauZRyzm.js";
9
- import { _ as _sfc_main$7 } from "./LpModal-BLOKvrJM.js";
9
+ import { _ as _sfc_main$7 } from "./LpModal-2YEJI45Q.js";
10
10
  import { _ as _sfc_main$6 } from "./LpSelect-D5mU4cZO.js";
11
11
  const _hoisted_1 = { class: "flex flex-col gap-3" };
12
12
  const _hoisted_2 = { class: "flex items-stretch gap-2" };
@@ -2,7 +2,7 @@ import { defineComponent, computed, watch, openBlock, createElementBlock, create
2
2
  import { _ as _sfc_main$2 } from "./LpButton-5VXXCjwF.js";
3
3
  import { _ as _sfc_main$3 } from "./LpIcon-CCnX5_2j.js";
4
4
  import { _ as _sfc_main$4 } from "./LpScrollArea-CXy8dkTN.js";
5
- import { _ as _sfc_main$1 } from "./LpSidebar-BaqVlOmo.js";
5
+ import { _ as _sfc_main$1 } from "./LpSidebar-B_UD_yUx.js";
6
6
  const _hoisted_1 = { class: "flex h-dvh overflow-hidden bg-surface text-ink" };
7
7
  const _hoisted_2 = { class: "flex min-w-0 flex-1 flex-col" };
8
8
  const _hoisted_3 = { class: "flex h-16 shrink-0 items-center gap-3 border-b border-line bg-surface px-4 md:px-6" };
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, openBlock, createBlock, withCtx, renderSlot, createVNode, createTextVNode, toDisplayString } from "vue";
2
2
  import { _ as _sfc_main$2 } from "./LpButton-5VXXCjwF.js";
3
- import { _ as _sfc_main$1 } from "./LpModal-BLOKvrJM.js";
3
+ import { _ as _sfc_main$1 } from "./LpModal-2YEJI45Q.js";
4
4
  const _sfc_main = /* @__PURE__ */ defineComponent({
5
5
  __name: "LpConfirmDialog",
6
6
  props: {
@@ -215,7 +215,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
215
215
  default: withCtx(() => [
216
216
  createVNode(unref(DrawerPortal), null, {
217
217
  default: withCtx(() => [
218
- createVNode(unref(DrawerOverlay), { class: "lp-scrim fixed inset-0 z-(--z-overlay) backdrop-blur-sm data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]" }),
218
+ createVNode(unref(DrawerOverlay), { class: "lp-scrim fixed inset-0 z-(--z-overlay) data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]" }),
219
219
  createVNode(unref(DrawerContent), {
220
220
  class: normalizeClass(contentClass.value),
221
221
  style: normalizeStyle(sizeStyle.value),
@@ -210,7 +210,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
210
210
  default: withCtx(() => [
211
211
  createVNode(unref(DialogPortal), null, {
212
212
  default: withCtx(() => [
213
- createVNode(unref(DialogOverlay), { class: "lp-scrim fixed inset-0 z-(--z-lightbox-overlay) backdrop-blur-sm data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]" }),
213
+ createVNode(unref(DialogOverlay), { class: "lp-scrim lp-scrim--deep fixed inset-0 z-(--z-lightbox-overlay) data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]" }),
214
214
  createVNode(unref(DialogContent), {
215
215
  class: "fixed inset-0 z-(--z-lightbox) flex flex-col outline-none data-[state=open]:animate-[lightbox-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[lightbox-out_140ms_cubic-bezier(0.4,0,1,1)] motion-reduce:animate-none",
216
216
  onKeydown
@@ -135,7 +135,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
135
135
  default: withCtx(() => [
136
136
  createVNode(unref(DialogPortal), null, {
137
137
  default: withCtx(() => [
138
- createVNode(unref(DialogOverlay), { class: "lp-scrim fixed inset-0 z-(--z-overlay) backdrop-blur-sm data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]" }),
138
+ createVNode(unref(DialogOverlay), { class: "lp-scrim fixed inset-0 z-(--z-overlay) data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]" }),
139
139
  createElementVNode("div", _hoisted_1, [
140
140
  createVNode(unref(DialogContent), mergeProps({
141
141
  ref_key: "panelRef",
@@ -1,5 +1,5 @@
1
1
  import { defineComponent, computed, useId, openBlock, createElementBlock, Fragment, createElementVNode, mergeProps, normalizeClass, renderSlot, createCommentVNode, createVNode, createSlots, withCtx, normalizeProps, guardReactiveProps, createBlock } from "vue";
2
- import { _ as _sfc_main$2 } from "./LpDrawer-CYVF8abJ.js";
2
+ import { _ as _sfc_main$2 } from "./LpDrawer-DcxlpxJ7.js";
3
3
  import { _ as _sfc_main$1 } from "./LpSidebarNav-S1QPTGcg.js";
4
4
  const _hoisted_1 = {
5
5
  key: 1,
@@ -25,6 +25,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
25
25
  function pillUnder(value, active) {
26
26
  return hovered.value ? hovered.value === value : active === value;
27
27
  }
28
+ function releaseFocusAfterPointer(event) {
29
+ const target = event.currentTarget;
30
+ if (target instanceof HTMLElement) target.blur();
31
+ }
28
32
  return (_ctx, _cache) => {
29
33
  return openBlock(), createBlock(unref(TabsRoot), {
30
34
  "model-value": __props.modelValue,
@@ -50,7 +54,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
50
54
  __props.accent ? "data-[state=active]:text-brand" : "data-[state=active]:text-ink",
51
55
  hovered.value === item.value ? "text-ink" : "text-muted"
52
56
  ]]),
53
- onPointerenter: ($event) => hovered.value = item.value
57
+ onPointerenter: ($event) => hovered.value = item.value,
58
+ onPointerup: releaseFocusAfterPointer
54
59
  }, {
55
60
  default: withCtx(() => [
56
61
  pillUnder(item.value, __props.modelValue) ? (openBlock(), createBlock(unref(Motion), {
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpAddressInput-l2Znlwgc.js";
1
+ import { _ as _sfc_main } from "../chunks/LpAddressInput-DaJ97mQ4.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpAppShell-D9KnS0j_.js";
1
+ import { _ as _sfc_main } from "../chunks/LpAppShell-Ds3WkurD.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -2,7 +2,7 @@ import { defineComponent, ref, computed, watch, nextTick, onMounted, onBeforeUnm
2
2
  import { DialogRoot, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription } from "reka-ui";
3
3
  import { _ as _sfc_main$1 } from "../chunks/LpIcon-CCnX5_2j.js";
4
4
  import { _ as _sfc_main$2 } from "../chunks/LpScrollArea-CXy8dkTN.js";
5
- import '../assets/LpCommandPalette-Cp6Y-j7g.css';const _hoisted_1 = { class: "flex shrink-0 items-center gap-2.5 border-b border-line px-4" };
5
+ import '../assets/LpCommandPalette-C3LdDNHk.css';const _hoisted_1 = { class: "flex shrink-0 items-center gap-2.5 border-b border-line px-4" };
6
6
  const _hoisted_2 = ["placeholder", "onKeydown"];
7
7
  const _hoisted_3 = {
8
8
  key: 0,
@@ -167,7 +167,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
167
167
  default: withCtx(() => [
168
168
  createVNode(unref(DialogPortal), null, {
169
169
  default: withCtx(() => [
170
- createVNode(unref(DialogOverlay), { class: "lp-scrim fixed inset-0 z-(--z-overlay) backdrop-blur-sm data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]" }),
170
+ createVNode(unref(DialogOverlay), { class: "lp-scrim fixed inset-0 z-(--z-overlay) data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]" }),
171
171
  createVNode(unref(DialogContent), {
172
172
  class: "fixed left-1/2 top-[12vh] z-(--z-modal) flex max-h-[76vh] w-[min(92vw,40rem)] -translate-x-1/2 flex-col overflow-hidden rounded-card border border-line bg-surface-raised shadow-panel outline-none data-[state=open]:animate-[pop-in_160ms_var(--ease-emphasized)] data-[state=closed]:animate-[pop-out_130ms_ease]",
173
173
  onOpenAutoFocus: _cache[1] || (_cache[1] = withModifiers(() => {
@@ -304,7 +304,7 @@ const _export_sfc = (sfc, props) => {
304
304
  }
305
305
  return target;
306
306
  };
307
- const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-7fba2dd8"]]);
307
+ const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-75a17488"]]);
308
308
  export {
309
309
  LpCommandPalette as default
310
310
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpConfirmDialog-gtsGL1kb.js";
1
+ import { _ as _sfc_main } from "../chunks/LpConfirmDialog-Cwqzbfgo.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpDrawer-CYVF8abJ.js";
1
+ import { _ as _sfc_main } from "../chunks/LpDrawer-DcxlpxJ7.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpLightbox-CzhFe9wZ.js";
1
+ import { _ as _sfc_main } from "../chunks/LpLightbox-Ci35Y_xP.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpModal-BLOKvrJM.js";
1
+ import { _ as _sfc_main } from "../chunks/LpModal-2YEJI45Q.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpSidebar-BaqVlOmo.js";
1
+ import { _ as _sfc_main } from "../chunks/LpSidebar-B_UD_yUx.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -20,13 +20,13 @@ type __VLS_Props = {
20
20
  /** Stretch the bar to full width with equal-share triggers. */
21
21
  block?: boolean;
22
22
  };
23
- declare var __VLS_48: {
23
+ declare var __VLS_49: {
24
24
  value: string;
25
- }, __VLS_50: {};
25
+ }, __VLS_51: {};
26
26
  type __VLS_Slots = {} & {
27
- panel?: (props: typeof __VLS_48) => any;
27
+ panel?: (props: typeof __VLS_49) => any;
28
28
  } & {
29
- default?: (props: typeof __VLS_50) => any;
29
+ default?: (props: typeof __VLS_51) => any;
30
30
  };
31
31
  declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
32
32
  "update:modelValue": (value: string) => any;
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpTabs-D7aTVPOb.js";
1
+ import { _ as _sfc_main } from "../chunks/LpTabs-Cefe_lys.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { _ } from "./chunks/LayoutCanvas-Dd20boUG.js";
2
- import { _ as _2 } from "./chunks/LpAddressInput-l2Znlwgc.js";
2
+ import { _ as _2 } from "./chunks/LpAddressInput-DaJ97mQ4.js";
3
3
  import { _ as _3 } from "./chunks/LpMapPicker-DFKrd1Ne.js";
4
4
  import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
5
5
  import { _ as _4 } from "./chunks/LpAlert-BAYHDSS1.js";
6
- import { _ as _5 } from "./chunks/LpAppShell-D9KnS0j_.js";
6
+ import { _ as _5 } from "./chunks/LpAppShell-Ds3WkurD.js";
7
7
  import { _ as _6 } from "./chunks/LpAutocomplete-DIgXmtCA.js";
8
8
  import { _ as _7 } from "./chunks/LpAvatar-B1Ez0ZAx.js";
9
9
  import { _ as _8 } from "./chunks/LpBadge-CXzBPnwO.js";
@@ -14,12 +14,12 @@ import { _ as _12 } from "./chunks/LpCard-BmrTvWOe.js";
14
14
  import { _ as _13 } from "./chunks/LpCheckbox-BO0zuuPh.js";
15
15
  import { _ as _14 } from "./chunks/LpCodeBlock-CSiOSPs8.js";
16
16
  import { default as default2 } from "./components/LpCommandPalette.vue.js";
17
- import { _ as _15 } from "./chunks/LpConfirmDialog-gtsGL1kb.js";
17
+ import { _ as _15 } from "./chunks/LpConfirmDialog-Cwqzbfgo.js";
18
18
  import { _ as _16 } from "./chunks/LpContextMenu-D0mzXqA7.js";
19
19
  import { _ as _17 } from "./chunks/LpDatePicker-dY2q4dr4.js";
20
20
  import { _ as _18 } from "./chunks/LpDisclosure-DP6yfgfM.js";
21
21
  import { _ as _19 } from "./chunks/LpDivider-CUX46KR0.js";
22
- import { _ as _20 } from "./chunks/LpDrawer-CYVF8abJ.js";
22
+ import { _ as _20 } from "./chunks/LpDrawer-DcxlpxJ7.js";
23
23
  import { _ as _21 } from "./chunks/LpDropdownMenu-DJpoqRCb.js";
24
24
  import { _ as _22 } from "./chunks/LpEmptyState-CrfyRJUG.js";
25
25
  import { _ as _23 } from "./chunks/LpFileTree-BGNzXknB.js";
@@ -28,11 +28,11 @@ import { _ as _24 } from "./chunks/LpFormField-Bn-ZwC6z.js";
28
28
  import { _ as _25 } from "./chunks/LpIcon-CCnX5_2j.js";
29
29
  import { _ as _26 } from "./chunks/LpInfraNode-C_PHcthC.js";
30
30
  import { _ as _27 } from "./chunks/LpInput-BauZRyzm.js";
31
- import { _ as _28 } from "./chunks/LpLightbox-CzhFe9wZ.js";
31
+ import { _ as _28 } from "./chunks/LpLightbox-Ci35Y_xP.js";
32
32
  import { fileNameOf } from "./components/lightbox.js";
33
33
  import { _ as _29 } from "./chunks/LpLink-DHwOEp4e.js";
34
34
  import { _ as _30 } from "./chunks/LpLogViewer-DQod8kXW.js";
35
- import { _ as _31 } from "./chunks/LpModal-BLOKvrJM.js";
35
+ import { _ as _31 } from "./chunks/LpModal-2YEJI45Q.js";
36
36
  import { _ as _32 } from "./chunks/LpNotificationBell-D1gdEtuI.js";
37
37
  import { _ as _33 } from "./chunks/LpNumberField-C5ar-OwE.js";
38
38
  import { _ as _34 } from "./chunks/LpOtpInput-DqaT0Z75.js";
@@ -48,7 +48,7 @@ import { _ as _42 } from "./chunks/LpScrollArea-CXy8dkTN.js";
48
48
  import { _ as _43 } from "./chunks/LpSegmented-BmpanyAo.js";
49
49
  import { _ as _44 } from "./chunks/LpSelect-D5mU4cZO.js";
50
50
  import { _ as _45 } from "./chunks/LpServiceNode-Dc-Ut5RS.js";
51
- import { _ as _46 } from "./chunks/LpSidebar-BaqVlOmo.js";
51
+ import { _ as _46 } from "./chunks/LpSidebar-B_UD_yUx.js";
52
52
  import { _ as _47 } from "./chunks/LpSkeleton-eSFIo4kD.js";
53
53
  import { _ as _48 } from "./chunks/LpSlider-B1SF3pRV.js";
54
54
  import { _ as _49 } from "./chunks/LpStat-CdbEFOvn.js";
@@ -56,7 +56,7 @@ import { _ as _50 } from "./chunks/LpStepper-5dFTrW21.js";
56
56
  import { _ as _51 } from "./chunks/LpSwitch-v6fnccSM.js";
57
57
  import { _ as _52 } from "./chunks/LpTable-pZmjnEti.js";
58
58
  import { _ as _53 } from "./chunks/LpTableOfContents-CjvxPMpU.js";
59
- import { _ as _54 } from "./chunks/LpTabs-D7aTVPOb.js";
59
+ import { _ as _54 } from "./chunks/LpTabs-Cefe_lys.js";
60
60
  import { _ as _55 } from "./chunks/LpTextarea-CRAkhemZ.js";
61
61
  import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/LpThemeSwitcher-B_kj0T2b.js";
62
62
  import { D, _ as _56, N, T, b, c, d, e, f, g, i, l, h, j, n, r, t, k, m, u, v } from "./chunks/LpThemeSwitcher-B_kj0T2b.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leavepulse/ui",
3
- "version": "0.20.6",
3
+ "version": "0.20.8",
4
4
  "type": "module",
5
5
  "description": "LeavePulse token-driven Vue component kit.",
6
6
  "repository": {
@@ -212,7 +212,7 @@ onBeforeUnmount(() => window.removeEventListener("keydown", onHotkey))
212
212
  <DialogRoot :open="open" @update:open="(v) => emit('update:open', v)">
213
213
  <DialogPortal>
214
214
  <DialogOverlay
215
- class="lp-scrim fixed inset-0 z-(--z-overlay) backdrop-blur-sm data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]"
215
+ class="lp-scrim fixed inset-0 z-(--z-overlay) data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]"
216
216
  />
217
217
  <DialogContent
218
218
  class="fixed left-1/2 top-[12vh] z-(--z-modal) flex max-h-[76vh] w-[min(92vw,40rem)] -translate-x-1/2 flex-col overflow-hidden rounded-card border border-line bg-surface-raised shadow-panel outline-none data-[state=open]:animate-[pop-in_160ms_var(--ease-emphasized)] data-[state=closed]:animate-[pop-out_130ms_ease]"
@@ -345,7 +345,7 @@ const edgeStripClass = computed(() =>
345
345
  >
346
346
  <DrawerPortal>
347
347
  <DrawerOverlay
348
- class="lp-scrim fixed inset-0 z-(--z-overlay) backdrop-blur-sm data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]"
348
+ class="lp-scrim fixed inset-0 z-(--z-overlay) data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]"
349
349
  />
350
350
  <DrawerContent
351
351
  :class="contentClass"
@@ -273,7 +273,7 @@ const ARROW =
273
273
  <!-- Sits on the lightbox rung, not the shared modal one: opening this
274
274
  from inside a dialog must cover that dialog, not tie with it. -->
275
275
  <DialogOverlay
276
- class="lp-scrim fixed inset-0 z-(--z-lightbox-overlay) backdrop-blur-sm data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]"
276
+ class="lp-scrim lp-scrim--deep fixed inset-0 z-(--z-lightbox-overlay) data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]"
277
277
  />
278
278
  <DialogContent
279
279
  class="fixed inset-0 z-(--z-lightbox) flex flex-col outline-none data-[state=open]:animate-[lightbox-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[lightbox-out_140ms_cubic-bezier(0.4,0,1,1)] motion-reduce:animate-none"
@@ -219,7 +219,7 @@ onBeforeUnmount(() => {
219
219
  <DialogRoot :open="open" @update:open="(v) => $emit('update:open', v)">
220
220
  <DialogPortal>
221
221
  <DialogOverlay
222
- class="lp-scrim fixed inset-0 z-(--z-overlay) backdrop-blur-sm data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]"
222
+ class="lp-scrim fixed inset-0 z-(--z-overlay) data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]"
223
223
  />
224
224
  <!-- Centred by a full-screen flex wrapper rather than by translating the
225
225
  panel off its own centre. With `top:50% / -translate-y-1/2` the panel
@@ -57,6 +57,25 @@ const panelLayoutTransition = computed(() =>
57
57
  function pillUnder(value: string, active?: string): boolean {
58
58
  return hovered.value ? hovered.value === value : active === value
59
59
  }
60
+
61
+ /*
62
+ * Drop focus after a mouse pick.
63
+ *
64
+ * Tabs implement the ARIA roving-focus pattern: while a trigger holds focus,
65
+ * ←/→ move between tabs. That is correct for keyboard users, but a *click*
66
+ * also leaves focus on the trigger — so afterwards the arrow keys silently
67
+ * belong to the tab strip, and any arrow-key handling the surrounding app has
68
+ * (walking a grid, moving a selection) appears to be broken until the user
69
+ * clicks somewhere else.
70
+ *
71
+ * Blurring on pointerup restores the arrows to the page without touching the
72
+ * keyboard path: Tab/←/→ navigation still focuses triggers and still works,
73
+ * because those never fire a pointer event.
74
+ */
75
+ function releaseFocusAfterPointer(event: PointerEvent) {
76
+ const target = event.currentTarget
77
+ if (target instanceof HTMLElement) target.blur()
78
+ }
60
79
  </script>
61
80
 
62
81
  <template>
@@ -85,6 +104,7 @@ function pillUnder(value: string, active?: string): boolean {
85
104
  hovered === item.value ? 'text-ink' : 'text-muted',
86
105
  ]"
87
106
  @pointerenter="hovered = item.value"
107
+ @pointerup="releaseFocusAfterPointer"
88
108
  >
89
109
  <!-- Active marker: a bottom bar in "underline", a filled pill otherwise.
90
110
  Both slide between tabs via the shared motion layoutId. -->
@@ -436,14 +436,34 @@
436
436
  */
437
437
  .lp-scrim {
438
438
  background-color: rgb(0 0 0 / var(--scrim-opacity, 0.5));
439
+ backdrop-filter: blur(var(--scrim-blur, 4px));
440
+ -webkit-backdrop-filter: blur(var(--scrim-blur, 4px));
439
441
  }
440
442
 
443
+ /*
444
+ * The blur lives here rather than on each overlay as a `backdrop-blur-*`
445
+ * utility: a utility sits outside this rule and the fallback below cannot
446
+ * unset it, so on WebKitGTK every scrim carried a filter that never painted
447
+ * while the engines that do paint it disagreed with the token. One owner for
448
+ * both halves keeps the two cases in step.
449
+ */
441
450
  :root[data-lp-no-backdrop] .lp-scrim {
442
451
  backdrop-filter: none;
443
452
  -webkit-backdrop-filter: none;
444
453
  --scrim-opacity: 0.62;
445
454
  }
446
455
 
456
+ /*
457
+ * A lightbox is the one scrim that hides a whole page behind a photo, and it is
458
+ * usually opened FROM a dialog — so it is the layer the mild shared tint serves
459
+ * worst: without the blur, the content behind stayed readable around the image.
460
+ * It gets its own value instead of raising the shared one, which would darken
461
+ * every stacked pair.
462
+ */
463
+ :root[data-lp-no-backdrop] .lp-scrim--deep {
464
+ --scrim-opacity: 0.78;
465
+ }
466
+
447
467
  /* The overlay gradient rides above the base fill but under the content. */
448
468
  .lp-skin-panel::before {
449
469
  content: "";