@leavepulse/ui 0.94.1 → 0.95.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.
Files changed (90) hide show
  1. package/dist/assets/{LpTable-DxnthVz4.css → LpTable-BJjNEvgJ.css} +57 -30
  2. package/dist/chunks/{LpAddressInput-BCqR0zmv.js → LpAddressInput-C5VIgRp0.js} +1 -1
  3. package/dist/chunks/{LpAppShell-DlpQierx.js → LpAppShell-C4b3ySa_.js} +3 -3
  4. package/dist/chunks/{LpCodeBlock-BgWcg2mk.js → LpCodeBlock-DTU40x8P.js} +1 -1
  5. package/dist/chunks/{LpCodeDisplay-DBi1YPLp.js → LpCodeDisplay-F2hjLb0X.js} +2 -2
  6. package/dist/chunks/{LpConfirmDialog-y6k0ryWR.js → LpConfirmDialog-DrHcIxRn.js} +1 -1
  7. package/dist/chunks/{LpConfirmHost-D-X0tDym.js → LpConfirmHost-D0Cd8FA_.js} +1 -1
  8. package/dist/chunks/{LpCopyButton-BGzw95Xc.js → LpCopyButton-CiqUS4SX.js} +1 -1
  9. package/dist/chunks/{LpDataList-B56Gu6Yt.js → LpDataList-Cit9fOSp.js} +2 -2
  10. package/dist/chunks/{LpDrawer-BkWjFdV0.js → LpDrawer-BHlqi62K.js} +1 -1
  11. package/dist/chunks/{LpFileTree-BN_zybBN.js → LpFileTree-gVjF_b6r.js} +1 -1
  12. package/dist/chunks/{LpInspector-oTfkOdYd.js → LpInspector-DSL1lINx.js} +2 -2
  13. package/dist/chunks/{LpLightbox-DPgz7IsT.js → LpLightbox--EwvQGe-.js} +1 -1
  14. package/dist/chunks/{LpLogViewer-BuIzr_6h.js → LpLogViewer-DSq9e8mT.js} +1 -1
  15. package/dist/chunks/{LpMediaGallery-CTejKF2-.js → LpMediaGallery-DlYJf3DS.js} +1 -1
  16. package/dist/chunks/{LpModal-D1E7rQzw.js → LpModal-COMHrBKL.js} +1 -1
  17. package/dist/chunks/{LpModalNav-BFjiHWbr.js → LpModalNav-Cj02cfhL.js} +2 -2
  18. package/dist/chunks/{LpNotificationBell-KRgdRZs-.js → LpNotificationBell-DNGijtmW.js} +1 -1
  19. package/dist/chunks/{LpNotificationFeed-CMGYU8c-.js → LpNotificationFeed-BoovbtfL.js} +3 -3
  20. package/dist/chunks/{LpPageScrollbar-C9sTeU-2.js → LpPageScrollbar-BniFeL2U.js} +5 -1
  21. package/dist/chunks/{LpPaletteTheme-CLwO-SDf.js → LpPaletteTheme-_FwkJO2o.js} +1 -1
  22. package/dist/chunks/{LpPasswordInput-LPVI7D3v.js → LpPasswordInput-BBDz2zyU.js} +1 -1
  23. package/dist/chunks/{LpPie-CsiBXe-e.js → LpPie-CtC4XdhC.js} +1 -1
  24. package/dist/chunks/{LpPipeline-DVcoSs--.js → LpPipeline-aCALaUY8.js} +1 -1
  25. package/dist/chunks/{LpRelativeTime-CN5bWD73.js → LpRelativeTime-9MHlbq6F.js} +1 -1
  26. package/dist/chunks/{LpScrollArea-CqvwfZs2.js → LpScrollArea-B_1KZOSS.js} +11 -1
  27. package/dist/chunks/{LpSecretField-BwrZ4TfT.js → LpSecretField-C9vwMFQ6.js} +4 -4
  28. package/dist/chunks/{LpSidebar-BKhVDsMt.js → LpSidebar-DPri9uyz.js} +3 -3
  29. package/dist/chunks/{LpSidebarNav-DbCap8z1.js → LpSidebarNav-CV1rU6La.js} +1 -1
  30. package/dist/chunks/{LpThemeStudio-BPPctXgd.js → LpThemeStudio-yiEdFJQL.js} +1 -1
  31. package/dist/chunks/{LpThemeSwitcher-B3c44xFH.js → LpThemeSwitcher-DKkCFaFk.js} +1 -1
  32. package/dist/chunks/{LpToaster-Cdx1tnHB.js → LpToaster-C7hHkGOA.js} +1 -1
  33. package/dist/chunks/LpTooltip-Bt1ZFViJ.js +333 -0
  34. package/dist/chunks/{LpTruncate-C_C8eiIE.js → LpTruncate-DEHWL1OA.js} +2 -2
  35. package/dist/chunks/{LpUptimeBar-Dt6SY_-m.js → LpUptimeBar-CXgzU5ym.js} +1 -1
  36. package/dist/chunks/{LpWorkspaceSwitcher-DCIiOQt_.js → LpWorkspaceSwitcher-CrUVSI7x.js} +1 -1
  37. package/dist/chunks/{RevealToggle-BsYxY6Oz.js → RevealToggle-D9Vs88kM.js} +1 -1
  38. package/dist/components/LpAddressInput.vue.js +1 -1
  39. package/dist/components/LpAppShell.vue.js +1 -1
  40. package/dist/components/LpCodeBlock.vue.js +1 -1
  41. package/dist/components/LpCodeDisplay.vue.js +1 -1
  42. package/dist/components/LpCommandPalette.vue.js +1 -1
  43. package/dist/components/LpConfirmDialog.vue.js +1 -1
  44. package/dist/components/LpConfirmHost.vue.js +1 -1
  45. package/dist/components/LpCopyButton.vue.js +1 -1
  46. package/dist/components/LpDataList.vue.js +1 -1
  47. package/dist/components/LpDock.vue.js +1 -1
  48. package/dist/components/LpDrawer.vue.js +1 -1
  49. package/dist/components/LpFileTree.vue.js +1 -1
  50. package/dist/components/LpInspector.vue.js +1 -1
  51. package/dist/components/LpLightbox.vue.js +1 -1
  52. package/dist/components/LpLogViewer.vue.js +1 -1
  53. package/dist/components/LpMediaGallery.vue.js +1 -1
  54. package/dist/components/LpModal.vue.js +1 -1
  55. package/dist/components/LpModalNav.vue.js +1 -1
  56. package/dist/components/LpNotificationBell.vue.js +1 -1
  57. package/dist/components/LpNotificationFeed.vue.js +1 -1
  58. package/dist/components/LpPageScrollbar.vue.js +1 -1
  59. package/dist/components/LpPaletteTheme.vue.js +1 -1
  60. package/dist/components/LpPasswordInput.vue.js +1 -1
  61. package/dist/components/LpPie.vue.js +1 -1
  62. package/dist/components/LpPipeline.vue.js +1 -1
  63. package/dist/components/LpRelativeTime.vue.js +1 -1
  64. package/dist/components/LpScrollArea.vue.js +1 -1
  65. package/dist/components/LpSecretField.vue.js +1 -1
  66. package/dist/components/LpShortcutsDialog.vue.js +1 -1
  67. package/dist/components/LpSidebar.vue.js +1 -1
  68. package/dist/components/LpSidebarNav.vue.js +1 -1
  69. package/dist/components/LpTable.vue.js +38 -12
  70. package/dist/components/LpThemeStudio.vue.js +1 -1
  71. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  72. package/dist/components/LpToaster.vue.js +1 -1
  73. package/dist/components/LpTooltip.vue.d.ts +3 -3
  74. package/dist/components/LpTooltip.vue.js +1 -1
  75. package/dist/components/LpTruncate.vue.js +1 -1
  76. package/dist/components/LpUptimeBar.vue.js +1 -1
  77. package/dist/components/LpWorkspaceSwitcher.vue.js +1 -1
  78. package/dist/components/RevealToggle.vue.js +1 -1
  79. package/dist/components/tableFeatures.d.ts +1 -0
  80. package/dist/components/tableFeatures.js +25 -0
  81. package/dist/composables/useShift.js +28 -11
  82. package/dist/index.js +34 -34
  83. package/package.json +1 -1
  84. package/src/components/LpPageScrollbar.vue +14 -1
  85. package/src/components/LpScrollArea.vue +18 -1
  86. package/src/components/LpTable.vue +76 -4
  87. package/src/components/LpTooltip.vue +153 -14
  88. package/src/components/tableFeatures.ts +36 -0
  89. package/src/composables/useShift.ts +45 -15
  90. package/dist/chunks/LpTooltip-BKde8Xjv.js +0 -230
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, computed, useAttrs, ref, shallowRef, watch, onMounted, useSlots, onBeforeUnmount, useId, h, openBlock, createElementBlock, normalizeClass, createVNode, withCtx, renderSlot, createCommentVNode, createBlock, createTextVNode, toDisplayString, Fragment, renderList, createElementVNode, Transition, mergeProps, normalizeStyle, withModifiers, TransitionGroup, unref, nextTick } from "vue";
2
2
  import { usePaletteScope, suppressPaletteDiscovery, usePaletteCommands } from "../composables/usePaletteCommands.js";
3
3
  import { menuPaletteCommands } from "./commandPalette.js";
4
- import { _ as _sfc_main$1 } from "../chunks/LpDataList-B56Gu6Yt.js";
4
+ import { _ as _sfc_main$1 } from "../chunks/LpDataList-Cit9fOSp.js";
5
5
  import { _ as _sfc_main$d } from "../chunks/LpCheckbox-C9VnPIQf.js";
6
6
  import { _ as _sfc_main$c } from "../chunks/LpContextMenu-DEFirphS.js";
7
7
  import { _ as _sfc_main$g } from "../chunks/LpEditable-DfRUAGkA.js";
@@ -11,7 +11,7 @@ import { _ as _sfc_main$5 } from "../chunks/LpIcon-CxHFPwKt.js";
11
11
  import { _ as _sfc_main$e } from "../chunks/LpSkeleton-leTl53V9.js";
12
12
  import { _ as _sfc_main$h } from "../chunks/LpPagination-DGLntZJN.js";
13
13
  import { _ as _sfc_main$6 } from "../chunks/LpPopover-w2rr4x7n.js";
14
- import { _ as _sfc_main$b } from "../chunks/LpScrollArea-CqvwfZs2.js";
14
+ import { _ as _sfc_main$b } from "../chunks/LpScrollArea-B_1KZOSS.js";
15
15
  import { _ as _sfc_main$9 } from "../chunks/LpRollingText-B54Pje7P.js";
16
16
  import { _ as _sfc_main$2 } from "../chunks/LpShift-DAgS_d2x.js";
17
17
  import { _ as _sfc_main$7 } from "../chunks/LpTableFilter-CILHffC1.js";
@@ -25,16 +25,17 @@ import { usePaintSelect } from "../composables/usePaintSelect.js";
25
25
  import { useRovingFocus } from "../composables/useRovingFocus.js";
26
26
  import { useLabels } from "../composables/useLpConfig.js";
27
27
  import { useResizeObserver } from "../composables/useResizeObserver.js";
28
- import { orderPinned, pinOffsets, groupRows, rowWindow, presetHidden, sortByKeys, nextSorts, clampColumnWidth } from "./tableFeatures.js";
28
+ import { orderPinned, pinOffsets, groupRows, rowWindow, rowChanges, presetHidden, sortByKeys, nextSorts, clampColumnWidth } from "./tableFeatures.js";
29
29
  import { devWarn } from "../composables/devWarn.js";
30
30
  import { startPointerDrag } from "../composables/pointerDrag.js";
31
- import { isHTMLElement, nodeWindow } from "../composables/realm.js";
31
+ import { nodeWindow, isHTMLElement } from "../composables/realm.js";
32
+ import { prefersReducedMotion } from "../composables/easing.js";
32
33
  import { _ as _sfc_main$4 } from "../chunks/LpButton-BvVoF-PO.js";
33
34
  import { toCsv, downloadFile, fileStem } from "./exportData.js";
34
35
  import { toHiddenSets, sameHidden, summarizeShown, parseTableState, mergeRestored, serializeTableState, fromHiddenSets } from "./tableFilter.js";
35
36
  import { resolveRowMenu } from "./tableRowMenu.js";
36
37
  import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
37
- import '../assets/LpTable-DxnthVz4.css';const _hoisted_1 = {
38
+ import '../assets/LpTable-BJjNEvgJ.css';const _hoisted_1 = {
38
39
  key: 0,
39
40
  class: "flex min-h-8 flex-wrap items-center gap-x-3 gap-y-2 pb-3 text-xs"
40
41
  };
@@ -1044,6 +1045,29 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1044
1045
  emit("rowClick", row);
1045
1046
  }
1046
1047
  });
1048
+ const ROW_MOTION_LIMIT = 12;
1049
+ const rowsEl = shallowRef(null);
1050
+ function setRowsEl(el) {
1051
+ const node = el?.$el ?? null;
1052
+ rowsEl.value = node;
1053
+ roving.setContainer(node);
1054
+ }
1055
+ const motionIds = computed(() => (headerless.value ? allEntries.value : viewEntries.value).map((entry) => entry.id));
1056
+ let shownIds = [];
1057
+ const bigSwap = computed(() => rowChanges(shownIds, motionIds.value) > ROW_MOTION_LIMIT);
1058
+ let settleFlip = false;
1059
+ watch(
1060
+ motionIds,
1061
+ (ids) => {
1062
+ const eased = bigSwap.value && shownIds.length > 0 && ids.length > 0;
1063
+ shownIds = ids;
1064
+ const body = rowsEl.value;
1065
+ if (!eased || !body || props.virtualRowHeight || prefersReducedMotion(nodeWindow(body))) return;
1066
+ settleFlip = !settleFlip;
1067
+ body.dataset.lpSettle = settleFlip ? "a" : "b";
1068
+ },
1069
+ { flush: "post", immediate: true }
1070
+ );
1047
1071
  function onRowKeydown(event) {
1048
1072
  if (event.key === " " && props.selectable && roving.activeId.value) {
1049
1073
  event.preventDefault();
@@ -1437,10 +1461,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1437
1461
  createVNode(TransitionGroup, {
1438
1462
  tag: "tbody",
1439
1463
  name: "lp-row",
1440
- css: animating.value && !__props.virtualRowHeight,
1464
+ css: animating.value && !__props.virtualRowHeight && !bigSwap.value,
1465
+ "move-class": bigSwap.value ? "lp-row-still" : void 0,
1441
1466
  class: normalizeClass(busy.value && displayRows.value.length ? "opacity-60 transition-opacity" : "transition-opacity"),
1442
1467
  "aria-busy": busy.value || void 0,
1443
- ref: (el) => unref(roving).setContainer(el?.$el ?? null)
1468
+ ref: setRowsEl
1444
1469
  }, {
1445
1470
  default: withCtx(() => [
1446
1471
  displayRows.value.length === 0 && busy.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(__props.skeletonRows, (n) => {
@@ -1647,7 +1672,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1647
1672
  ])) : createCommentVNode("", true)
1648
1673
  ]),
1649
1674
  _: 3
1650
- }, 8, ["css", "class", "aria-busy"])
1675
+ }, 8, ["css", "move-class", "class", "aria-busy"])
1651
1676
  ], 14, _hoisted_11)
1652
1677
  ]),
1653
1678
  _: 3
@@ -1669,7 +1694,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1669
1694
  key: activeLayout.value,
1670
1695
  tag: "div",
1671
1696
  name: "lp-row",
1672
- css: animating.value
1697
+ css: animating.value && !bigSwap.value,
1698
+ "move-class": bigSwap.value ? "lp-row-still" : void 0
1673
1699
  }, scrollAttrs.value, {
1674
1700
  class: ["min-h-0 transition-opacity", [
1675
1701
  busy.value && displayRows.value.length ? "opacity-60" : "",
@@ -1677,7 +1703,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1677
1703
  ]],
1678
1704
  style: activeLayout.value === "cards" ? { gridTemplateColumns: `repeat(auto-fill, minmax(min(${__props.cardWidth}, 100%), 1fr))` } : void 0,
1679
1705
  "aria-busy": busy.value || void 0,
1680
- ref: (el) => unref(roving).setContainer(el?.$el ?? null)
1706
+ ref: setRowsEl
1681
1707
  }), {
1682
1708
  default: withCtx(() => [
1683
1709
  displayRows.value.length === 0 && busy.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(__props.skeletonRows, (n) => {
@@ -1896,7 +1922,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1896
1922
  }), 128))
1897
1923
  ]),
1898
1924
  _: 3
1899
- }, 16, ["css", "class", "style", "aria-busy"]))
1925
+ }, 16, ["css", "move-class", "class", "style", "aria-busy"]))
1900
1926
  ]),
1901
1927
  _: 3
1902
1928
  }, 8, ["items", "no-hint", "title", "subtitle", "title-icon", "title-image"]))
@@ -1915,7 +1941,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1915
1941
  };
1916
1942
  }
1917
1943
  });
1918
- const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-a346ca36"]]);
1944
+ const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-a366adee"]]);
1919
1945
  export {
1920
1946
  LpTable as default
1921
1947
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpThemeStudio-BPPctXgd.js";
1
+ import { _ as _sfc_main } from "../chunks/LpThemeStudio-yiEdFJQL.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpThemeSwitcher-B3c44xFH.js";
1
+ import { _ as _sfc_main } from "../chunks/LpThemeSwitcher-DKkCFaFk.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpToaster-Cdx1tnHB.js";
1
+ import { _ as _sfc_main } from "../chunks/LpToaster-C7hHkGOA.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -46,11 +46,11 @@ type __VLS_Props = {
46
46
  */
47
47
  touch?: "hold" | "none";
48
48
  };
49
- declare var __VLS_24: {}, __VLS_41: {};
49
+ declare var __VLS_9: {}, __VLS_50: {};
50
50
  type __VLS_Slots = {} & {
51
- default?: (props: typeof __VLS_24) => any;
51
+ default?: (props: typeof __VLS_9) => any;
52
52
  } & {
53
- content?: (props: typeof __VLS_41) => any;
53
+ content?: (props: typeof __VLS_50) => any;
54
54
  };
55
55
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
56
56
  touch: "hold" | "none";
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpTooltip-BKde8Xjv.js";
1
+ import { _ as _sfc_main } from "../chunks/LpTooltip-Bt1ZFViJ.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpTruncate-C_C8eiIE.js";
1
+ import { _ as _sfc_main } from "../chunks/LpTruncate-DEHWL1OA.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpUptimeBar-Dt6SY_-m.js";
1
+ import { _ as _sfc_main } from "../chunks/LpUptimeBar-CXgzU5ym.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/LpWorkspaceSwitcher-DCIiOQt_.js";
1
+ import { _ as _sfc_main } from "../chunks/LpWorkspaceSwitcher-CrUVSI7x.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -1,4 +1,4 @@
1
- import { _ as _sfc_main } from "../chunks/RevealToggle-BsYxY6Oz.js";
1
+ import { _ as _sfc_main } from "../chunks/RevealToggle-D9Vs88kM.js";
2
2
  export {
3
3
  _sfc_main as default
4
4
  };
@@ -65,3 +65,4 @@ export declare function presetHidden(preset: Pick<ColumnPreset, "columns">, colu
65
65
  * - `list`: one compact line per row with no header, for narrow places.
66
66
  */
67
67
  export type TableLayout = "table" | "cards" | "list";
68
+ export declare function rowChanges(before: readonly string[], after: readonly string[]): number;
@@ -74,6 +74,30 @@ function presetHidden(preset, columns) {
74
74
  const hidden = columns.filter((c) => !c.alwaysVisible && !shown.has(c.key)).map((c) => c.key);
75
75
  return hidden.length === columns.length ? /* @__PURE__ */ new Set() : new Set(hidden);
76
76
  }
77
+ function rowChanges(before, after) {
78
+ const old = /* @__PURE__ */ new Map();
79
+ before.forEach((id, i) => old.set(id, i));
80
+ let entered = 0;
81
+ const kept = [];
82
+ for (const id of after) {
83
+ const at = old.get(id);
84
+ if (at === void 0) entered++;
85
+ else kept.push(at);
86
+ }
87
+ const left = before.length - kept.length;
88
+ const tails = [];
89
+ for (const at of kept) {
90
+ let lo = 0;
91
+ let hi = tails.length;
92
+ while (lo < hi) {
93
+ const mid = lo + hi >> 1;
94
+ if (tails[mid] < at) lo = mid + 1;
95
+ else hi = mid;
96
+ }
97
+ tails[lo] = at;
98
+ }
99
+ return entered + left + (kept.length - tails.length);
100
+ }
77
101
  export {
78
102
  MIN_COLUMN_PX,
79
103
  clampColumnWidth,
@@ -82,6 +106,7 @@ export {
82
106
  orderPinned,
83
107
  pinOffsets,
84
108
  presetHidden,
109
+ rowChanges,
85
110
  rowWindow,
86
111
  sortByKeys
87
112
  };
@@ -1,6 +1,23 @@
1
1
  import { ref, watch, toValue, onBeforeUnmount, nextTick } from "vue";
2
2
  import { nodeWindow, isElement } from "./realm.js";
3
3
  import { prefersReducedMotion } from "./easing.js";
4
+ const firstReads = /* @__PURE__ */ new Map();
5
+ function firstRead(win, pass) {
6
+ let queue = firstReads.get(win);
7
+ if (!queue) {
8
+ const batch2 = /* @__PURE__ */ new Set();
9
+ queue = batch2;
10
+ firstReads.set(win, batch2);
11
+ win.requestAnimationFrame(() => {
12
+ firstReads.delete(win);
13
+ for (const p of batch2) p.read();
14
+ for (const p of batch2) p.write();
15
+ });
16
+ }
17
+ queue.add(pass);
18
+ const batch = queue;
19
+ return () => batch.delete(pass);
20
+ }
4
21
  const TWEEN_MS = 160;
5
22
  const RETARGET_AFTER_MS = 40;
6
23
  function useShift(options = {}) {
@@ -9,7 +26,7 @@ function useShift(options = {}) {
9
26
  const resizing = ref(false);
10
27
  let ro;
11
28
  let mo;
12
- let raf = 0;
29
+ let cancelFirstRead;
13
30
  let settleTimer;
14
31
  let lastHeight = 0;
15
32
  let lastWidth = 0;
@@ -95,7 +112,8 @@ function useShift(options = {}) {
95
112
  mo?.disconnect();
96
113
  ro = void 0;
97
114
  mo = void 0;
98
- cancelAnimationFrame(raf);
115
+ cancelFirstRead?.();
116
+ cancelFirstRead = void 0;
99
117
  clearTimeout(settleTimer);
100
118
  tweening.value = false;
101
119
  resizing.value = false;
@@ -109,17 +127,16 @@ function useShift(options = {}) {
109
127
  ([node, enabled]) => {
110
128
  teardown();
111
129
  if (!enabled || !node) return;
112
- lastHeight = node.offsetHeight;
113
- lastWidth = node.offsetWidth;
114
- laidOut = node.getClientRects().length > 0;
115
130
  scrollHost = node;
116
131
  node.addEventListener("scroll", rememberScroll, { capture: true, passive: true });
117
- if (wantsHeight()) node.style.height = `${lastHeight}px`;
118
- if (wantsWidth()) node.style.width = `${lastWidth}px`;
119
- raf = requestAnimationFrame(() => {
120
- tweening.value = true;
121
- if (wantsHeight()) node.style.height = "";
122
- if (wantsWidth()) node.style.width = "";
132
+ cancelFirstRead = firstRead(nodeWindow(node), {
133
+ read: () => {
134
+ if (inFlight) return;
135
+ lastHeight = node.offsetHeight;
136
+ lastWidth = node.offsetWidth;
137
+ laidOut = node.getClientRects().length > 0;
138
+ },
139
+ write: () => tweening.value = true
123
140
  });
124
141
  const watchChildren = () => {
125
142
  if (!ro) return;
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { _ } from "./chunks/LayoutCanvas-j4TZqx1A.js";
2
- import { _ as _2 } from "./chunks/LpAddressInput-BCqR0zmv.js";
2
+ import { _ as _2 } from "./chunks/LpAddressInput-C5VIgRp0.js";
3
3
  import { _ as _3 } from "./chunks/LpMapPicker-V0Lybi10.js";
4
4
  import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
5
5
  import { _ as _4 } from "./chunks/LpActionBar-43WHmTsM.js";
6
6
  import { _ as _5 } from "./chunks/LpAlert-Q0h7Gucu.js";
7
- import { _ as _6 } from "./chunks/LpAppShell-DlpQierx.js";
7
+ import { _ as _6 } from "./chunks/LpAppShell-C4b3ySa_.js";
8
8
  import { _ as _7 } from "./chunks/LpAutocomplete-YPxAPHEo.js";
9
9
  import { _ as _8 } from "./chunks/LpAvatar-CfLBqlY1.js";
10
10
  import { _ as _9 } from "./chunks/LpBadge-Bh5roBr_.js";
@@ -19,7 +19,7 @@ import { chartView, lttbIndices, minMaxBuckets, panRange, slotOf, sourceOf, zoom
19
19
  import { useChartSync } from "./composables/useChartSync.js";
20
20
  import { createLinkedView, linkChart, linkLog, linkPipeline, linkTable, linkTopology, provideLinkedView, useLinkedView } from "./composables/useLinkedView.js";
21
21
  import { _ as _14 } from "./chunks/LpCheckbox-C9VnPIQf.js";
22
- import { _ as _15 } from "./chunks/LpCodeBlock-BgWcg2mk.js";
22
+ import { _ as _15 } from "./chunks/LpCodeBlock-DTU40x8P.js";
23
23
  import { tokenizeLines } from "./components/codeHighlight.js";
24
24
  import { _ as _16 } from "./chunks/LpColorPicker-KGMG8QEh.js";
25
25
  import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, normalizeHue, opaqueCss, parseColor, parseHex, rgbToHex, rgbToHsv } from "./components/color.js";
@@ -33,8 +33,8 @@ import { default as default6 } from "./components/LpPaletteStats.vue.js";
33
33
  import { default as default7 } from "./components/LpPaletteSwatches.vue.js";
34
34
  import { default as default8 } from "./components/LpKeys.vue.js";
35
35
  import { comboKeys, comboSteps } from "./components/keys.js";
36
- import { _ as _18 } from "./chunks/LpConfirmDialog-y6k0ryWR.js";
37
- import { _ as _19 } from "./chunks/LpConfirmHost-D-X0tDym.js";
36
+ import { _ as _18 } from "./chunks/LpConfirmDialog-DrHcIxRn.js";
37
+ import { _ as _19 } from "./chunks/LpConfirmHost-D0Cd8FA_.js";
38
38
  import { confirm, useConfirm } from "./components/confirm.js";
39
39
  import { _ as _20 } from "./chunks/LpContextMenu-DEFirphS.js";
40
40
  import { _ as _21 } from "./chunks/LpDatePicker-Dlyvgsan.js";
@@ -43,11 +43,11 @@ import { _ as _23 } from "./chunks/LpRangeCalendar-9BvaLZji.js";
43
43
  import { clampRange, dayAllowed, defaultDatePresets, defaultRangePresets, formatRange, normalizeRange, sameRange } from "./components/dateRange.js";
44
44
  import { _ as _24 } from "./chunks/LpDisclosure-D4JZ-o8K.js";
45
45
  import { _ as _25 } from "./chunks/LpDivider-CUX46KR0.js";
46
- import { _ as _26 } from "./chunks/LpDrawer-BkWjFdV0.js";
46
+ import { _ as _26 } from "./chunks/LpDrawer-BHlqi62K.js";
47
47
  import { _ as _27 } from "./chunks/LpDropdownMenu-CdCe7D2d.js";
48
48
  import { default as default9 } from "./components/LpDropzone.vue.js";
49
49
  import { _ as _28 } from "./chunks/LpEmptyState-DLOm07KH.js";
50
- import { _ as _29 } from "./chunks/LpFileTree-BN_zybBN.js";
50
+ import { _ as _29 } from "./chunks/LpFileTree-gVjF_b6r.js";
51
51
  import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
52
52
  import { _ as _30 } from "./chunks/LpFieldNotice-DUPo1Yii.js";
53
53
  import { _ as _31 } from "./chunks/LpFormField-jbM7K1Hg.js";
@@ -56,25 +56,25 @@ import { i, b, a, c } from "./chunks/icons-C8ccRCKw.js";
56
56
  import { default as default10 } from "./components/LpImageEditor.vue.js";
57
57
  import { _ as _33 } from "./chunks/LpInfraNode-tD5x5YOy.js";
58
58
  import { _ as _34 } from "./chunks/LpInput-DGMpxrcg.js";
59
- import { _ as _35 } from "./chunks/LpLightbox-DPgz7IsT.js";
59
+ import { _ as _35 } from "./chunks/LpLightbox--EwvQGe-.js";
60
60
  import { fileNameOf, isVideoItem } from "./components/lightbox.js";
61
61
  import { _ as _36 } from "./chunks/LpLink-Krkjhe_y.js";
62
- import { _ as _37 } from "./chunks/LpLogViewer-BuIzr_6h.js";
62
+ import { _ as _37 } from "./chunks/LpLogViewer-DSq9e8mT.js";
63
63
  import { _ as _38 } from "./chunks/LpLogInspector-BhJTJIst.js";
64
64
  import { compilePattern, findIds, messageShape, structuredPayload, timeMs } from "./components/logTools.js";
65
65
  import { countLevels, matchPositions, matchesTerm, ringWindow, stepMatch } from "./components/logSearch.js";
66
- import { _ as _39 } from "./chunks/LpMediaGallery-CTejKF2-.js";
67
- import { _ as _40 } from "./chunks/LpModal-D1E7rQzw.js";
68
- import { _ as _41 } from "./chunks/LpModalNav-BFjiHWbr.js";
69
- import { _ as _42 } from "./chunks/LpNotificationBell-KRgdRZs-.js";
70
- import { _ as _43 } from "./chunks/LpNotificationFeed-CMGYU8c-.js";
66
+ import { _ as _39 } from "./chunks/LpMediaGallery-DlYJf3DS.js";
67
+ import { _ as _40 } from "./chunks/LpModal-COMHrBKL.js";
68
+ import { _ as _41 } from "./chunks/LpModalNav-Cj02cfhL.js";
69
+ import { _ as _42 } from "./chunks/LpNotificationBell-DNGijtmW.js";
70
+ import { _ as _43 } from "./chunks/LpNotificationFeed-BoovbtfL.js";
71
71
  import { _ as _44 } from "./chunks/LpNumberField-C0LSu-tl.js";
72
72
  import { _ as _45 } from "./chunks/LpTimeField-Dio7Tj9A.js";
73
73
  import { _ as _46 } from "./chunks/LpNumberFlow-Vqj0tP7B.js";
74
74
  import { _ as _47 } from "./chunks/LpOtpInput-C14XagVB.js";
75
75
  import { _ as _48 } from "./chunks/LpPagination-DGLntZJN.js";
76
- import { _ as _49 } from "./chunks/LpPasswordInput-LPVI7D3v.js";
77
- import { _ as _50 } from "./chunks/LpPie-CsiBXe-e.js";
76
+ import { _ as _49 } from "./chunks/LpPasswordInput-BBDz2zyU.js";
77
+ import { _ as _50 } from "./chunks/LpPie-CtC4XdhC.js";
78
78
  import { _ as _51 } from "./chunks/LpPhoneInput-BdglZsGH.js";
79
79
  import { filterCountries, flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
80
80
  import { _ as _52 } from "./chunks/LpPopover-w2rr4x7n.js";
@@ -82,9 +82,9 @@ import { _ as _53 } from "./chunks/LpProgress-D_MSjowb.js";
82
82
  import { _ as _54 } from "./chunks/LpRadio-4KyxeSz4.js";
83
83
  import { _ as _55 } from "./chunks/LpRadioGroup-Cr_fmrBY.js";
84
84
  import { _ as _56 } from "./chunks/LpRollingText-B54Pje7P.js";
85
- import { _ as _57 } from "./chunks/LpScrollArea-CqvwfZs2.js";
85
+ import { _ as _57 } from "./chunks/LpScrollArea-B_1KZOSS.js";
86
86
  import { _ as _58 } from "./chunks/LpScrollStrip-D4tsOfAQ.js";
87
- import { _ as _59 } from "./chunks/LpPageScrollbar-C9sTeU-2.js";
87
+ import { _ as _59 } from "./chunks/LpPageScrollbar-BniFeL2U.js";
88
88
  import { _ as _60 } from "./chunks/LpSegmented-DzFYP0ZF.js";
89
89
  import { _ as _61 } from "./chunks/LpSection-CwsfNR7N.js";
90
90
  import { _ as _62 } from "./chunks/LpSelect-Dffg5r4I.js";
@@ -94,7 +94,7 @@ import { _ as _64 } from "./chunks/LpShift-DAgS_d2x.js";
94
94
  import { _ as _65 } from "./chunks/LpSwap-M7nFeW3C.js";
95
95
  import { _ as _66 } from "./chunks/LpHintExample-YzCXiSUp.js";
96
96
  import { default as default11 } from "./components/LpShortcutsDialog.vue.js";
97
- import { _ as _67 } from "./chunks/LpSidebar-BKhVDsMt.js";
97
+ import { _ as _67 } from "./chunks/LpSidebar-DPri9uyz.js";
98
98
  import { _ as _68 } from "./chunks/LpContextSwitcher-COw6GHPW.js";
99
99
  import { _ as _69 } from "./chunks/LpSkeleton-leTl53V9.js";
100
100
  import { _ as _70 } from "./chunks/LpSlider-DUd4gXnw.js";
@@ -122,10 +122,10 @@ import { _ as _80 } from "./chunks/LpBottomNav-9AqvZlRW.js";
122
122
  import { _ as _81 } from "./chunks/LpTagsInput-DD8-xe3F.js";
123
123
  import { addTags, splitTags } from "./components/tags.js";
124
124
  import { _ as _82 } from "./chunks/LpTextarea-CQg-dVxN.js";
125
- import { _ as _83 } from "./chunks/LpThemeSwitcher-B3c44xFH.js";
125
+ import { _ as _83 } from "./chunks/LpThemeSwitcher-DKkCFaFk.js";
126
126
  import { _ as _84 } from "./chunks/LpTilt-B7KHX1zH.js";
127
- import { _ as _85 } from "./chunks/LpToaster-Cdx1tnHB.js";
128
- import { _ as _86 } from "./chunks/LpTooltip-BKde8Xjv.js";
127
+ import { _ as _85 } from "./chunks/LpToaster-C7hHkGOA.js";
128
+ import { _ as _86 } from "./chunks/LpTooltip-Bt1ZFViJ.js";
129
129
  import { _ as _87 } from "./chunks/LpTour-BGUKUxSZ.js";
130
130
  import { holeOf, openContextMenu, panelsAround } from "./components/tour.js";
131
131
  import { _ as _88 } from "./chunks/LpHintLayer-nuMqfzvy.js";
@@ -134,13 +134,13 @@ import { HINT_SIGNALS, contextMenuTip, createHintSystem, dropzoneTip, hintKey, h
134
134
  import { _ as _90 } from "./chunks/LpTooltipProvider-CftjV7Xc.js";
135
135
  import { _ as _91 } from "./chunks/LpTopologyCanvas-B1YFfMaq.js";
136
136
  import { clusterGraph, diffTopology, findPath, layeredLayout, neighborhood, topologyToSvg } from "./components/topologyGraph.js";
137
- import { _ as _92 } from "./chunks/LpUptimeBar-Dt6SY_-m.js";
137
+ import { _ as _92 } from "./chunks/LpUptimeBar-CXgzU5ym.js";
138
138
  import { addLeaf, addTab, countBlocks, countLeaves, deserializeLayout, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, serializeLayout, setActiveTab } from "./layout/tree.js";
139
139
  import { blockTitle, defineBlocks } from "./layout/registry.js";
140
140
  import { layoutController, useLayout } from "./layout/useLayout.js";
141
141
  import { useWorkspaces } from "./layout/useWorkspaces.js";
142
- import { _ as _93 } from "./chunks/LpWorkspaceSwitcher-DCIiOQt_.js";
143
- import { _ as _94 } from "./chunks/LpInspector-oTfkOdYd.js";
142
+ import { _ as _93 } from "./chunks/LpWorkspaceSwitcher-CrUVSI7x.js";
143
+ import { _ as _94 } from "./chunks/LpInspector-DSL1lINx.js";
144
144
  import { _ as _95 } from "./chunks/LpWindow-DsPeiDCZ.js";
145
145
  import { WINDOW_DOCKS, clampRect, dockAt, dockedRect, isWindowRect, resizeRect, snapRect, useWindowLayer } from "./composables/windowing.js";
146
146
  import { THEME_COOKIE, applyTheme, applyThemeWithTransition, bootstrapTheme, cacheSystemThemes, normalizeTheme, parseTheme, prefersDarkScheme, revealTransition, serializeTheme, themeEntries, themeFromCookie, themeToCssRule, themeToCssVars, useTheme } from "./theme/useTheme.js";
@@ -192,14 +192,14 @@ import { useScrollStrip } from "./composables/useScrollStrip.js";
192
192
  import { useToast } from "./composables/useToast.js";
193
193
  import { _ as _96 } from "./chunks/LpThemeProvider-XK6ZeWAE.js";
194
194
  import { _ as _97 } from "./chunks/LpFrame-Bv5Fphte.js";
195
- import { _ as _98 } from "./chunks/LpThemeStudio-BPPctXgd.js";
195
+ import { _ as _98 } from "./chunks/LpThemeStudio-yiEdFJQL.js";
196
196
  import { _ as _99 } from "./chunks/LpThemeStudioSection-B7bt8Iyg.js";
197
197
  import { isInternalHref, resolveLink } from "./components/link.js";
198
198
  import { _ as _100 } from "./chunks/LpRepeater-C0rns2xW.js";
199
199
  import { _ as _101 } from "./chunks/LpGauge-KZaQ_FDR.js";
200
200
  import { _ as _102 } from "./chunks/LpQuota-BaCq5YOQ.js";
201
201
  import { _ as _103 } from "./chunks/LpStatus-C6GqSHJj.js";
202
- import { _ as _104 } from "./chunks/LpRelativeTime-CN5bWD73.js";
202
+ import { _ as _104 } from "./chunks/LpRelativeTime-9MHlbq6F.js";
203
203
  import { _ as _105 } from "./chunks/LpActivityLine-Ea-t5Vza.js";
204
204
  import { TONE_COLOR, TONE_SOFT, arcPath, capacityThresholds, meterFraction, toneAt } from "./components/meter.js";
205
205
  import { TONES, TONE_ALIASES, toneLook, toneOf } from "./components/tone.js";
@@ -207,7 +207,7 @@ import { formatAmount, quotaSegments, quotaState } from "./components/quota.js";
207
207
  import { compactNumber, decimalMark, formatBytes } from "./components/format.js";
208
208
  import { STATUS_LABELS, STATUS_LOOK } from "./components/status.js";
209
209
  import { formatRelativeTime } from "./components/relativeTime.js";
210
- import { _ as _106 } from "./chunks/LpPipeline-DVcoSs--.js";
210
+ import { _ as _106 } from "./chunks/LpPipeline-aCALaUY8.js";
211
211
  import { _ as _107 } from "./chunks/LpStepMark-CPGVj1XG.js";
212
212
  import { childProgress, connectorFilled, currentStepIndex, isSettled, overallStatus, stepElapsed } from "./components/pipeline.js";
213
213
  import { _ as _108 } from "./chunks/LpLoader-Bf1yZwaU.js";
@@ -216,12 +216,12 @@ import { useAppUpdate } from "./composables/useAppUpdate.js";
216
216
  import { useNow } from "./composables/useNow.js";
217
217
  import { _ as _109 } from "./chunks/LpCountdown-DVl7vXI1.js";
218
218
  import { DEFAULT_MILESTONES, DEFAULT_UNIT_LABELS, ceilToSecond, crossedMilestone, formatElapsed, formatTime, msToNextSecond, splitTime, timeParts } from "./components/timeSpan.js";
219
- import { _ as _110 } from "./chunks/LpCopyButton-BGzw95Xc.js";
220
- import { _ as _111 } from "./chunks/LpSecretField-BwrZ4TfT.js";
221
- import { _ as _112 } from "./chunks/LpDataList-B56Gu6Yt.js";
219
+ import { _ as _110 } from "./chunks/LpCopyButton-CiqUS4SX.js";
220
+ import { _ as _111 } from "./chunks/LpSecretField-C9vwMFQ6.js";
221
+ import { _ as _112 } from "./chunks/LpDataList-Cit9fOSp.js";
222
222
  import { _ as _113 } from "./chunks/LpEditable-DfRUAGkA.js";
223
- import { _ as _114 } from "./chunks/LpTruncate-C_C8eiIE.js";
224
- import { _ as _115 } from "./chunks/LpCodeDisplay-DBi1YPLp.js";
223
+ import { _ as _114 } from "./chunks/LpTruncate-DEHWL1OA.js";
224
+ import { _ as _115 } from "./chunks/LpCodeDisplay-F2hjLb0X.js";
225
225
  import { formatRemaining, groupCode, middleTruncate, normalizeCode } from "./components/fieldText.js";
226
226
  import { _ as _116 } from "./chunks/LpHoverCard-DYguY2AP.js";
227
227
  import { _ as _117 } from "./chunks/LpIdenticon-Dbbr4fvt.js";
@@ -251,7 +251,7 @@ import { _ as _129 } from "./chunks/LpCommandScope-DRUvHiX7.js";
251
251
  import { createPaletteRegistry, mergePaletteCommands, usePaletteCommands, vPalette } from "./composables/usePaletteCommands.js";
252
252
  import { commandShortcuts, commandToHotkey, commandToMenuItem, commandToPalette, useCommands } from "./composables/useCommands.js";
253
253
  import { usePaletteTheme } from "./theme/palette.js";
254
- import { _ as _130 } from "./chunks/LpPaletteTheme-CLwO-SDf.js";
254
+ import { _ as _130 } from "./chunks/LpPaletteTheme-_FwkJO2o.js";
255
255
  const uk = {
256
256
  actionBar: { dismiss: "Закрити" },
257
257
  activityLine: { busy: "Завантаження" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leavepulse/ui",
3
- "version": "0.94.1",
3
+ "version": "0.95.0",
4
4
  "type": "module",
5
5
  "description": "LeavePulse token-driven Vue component kit.",
6
6
  "repository": {
@@ -75,9 +75,22 @@ function measure() {
75
75
  const height = Math.max(MIN_THUMB_PX, Math.round((track * view.clientHeight) / view.scrollHeight))
76
76
  thumb.value = { height, top: Math.round(((track - height) * view.scrollTop) / range) }
77
77
  }
78
+ /*
79
+ * At most once a frame, and never in the middle of someone's render. A scroll
80
+ * or a resize of the window asks for the next frame. A change of the page's
81
+ * size is measured where the observer reports it, which is after the browser
82
+ * has laid the page out: the sizes are read for free there. Put off to the
83
+ * next frame instead, the read landed after whatever that frame had changed
84
+ * first (a list's rows starting their entrance) and laid the page out again
85
+ * for it, the cost of a whole table inside the frame that showed it.
86
+ */
78
87
  function measureSoon() {
79
88
  if (!frame && doc) frame = nodeWindow(doc).requestAnimationFrame(measure)
80
89
  }
90
+ function measureLaidOut() {
91
+ if (frame && doc) nodeWindow(doc).cancelAnimationFrame(frame)
92
+ measure()
93
+ }
81
94
 
82
95
  function onScroll() {
83
96
  measureSoon()
@@ -146,7 +159,7 @@ onMounted(() => {
146
159
  const win = nodeWindow(doc)
147
160
  win.addEventListener("scroll", onScroll, { passive: true })
148
161
  win.addEventListener("resize", measureSoon)
149
- sizes = new win.ResizeObserver(measureSoon)
162
+ sizes = new win.ResizeObserver(measureLaidOut)
150
163
  sizes.observe(doc.body)
151
164
  if (host) sizes.observe(host)
152
165
  measure()
@@ -155,8 +155,12 @@ function onViewportScroll(event: Event) {
155
155
  // state has to track content size even where the fade is off.
156
156
  let edgeResize: ResizeObserver | undefined
157
157
  let edgeMutation: MutationObserver | undefined
158
+ let edgeFrame = 0
159
+ let edgeWindow: Window | undefined
158
160
 
159
161
  function stopEdgeWatch() {
162
+ if (edgeFrame) edgeWindow?.cancelAnimationFrame(edgeFrame)
163
+ edgeFrame = 0
160
164
  edgeResize?.disconnect()
161
165
  edgeMutation?.disconnect()
162
166
  edgeResize = undefined
@@ -187,6 +191,14 @@ watch(
187
191
  // Rows arriving after the first paint are the common case — a list waiting
188
192
  // on a query renders empty, and observing only the boxes that existed then
189
193
  // left the fade off until something else happened to trigger a measure.
194
+ //
195
+ // Measured in the next frame, not here: a mutation is reported straight
196
+ // after the render that made it, before the browser has laid anything out,
197
+ // so reading the sizes here laid out fifty fresh table rows inside the
198
+ // click that brought them. The resize observer, which reports after layout,
199
+ // usually measures first anyway; the frame covers a change that resized
200
+ // nothing it watches.
201
+ edgeWindow = win
190
202
  if (win.MutationObserver) {
191
203
  edgeMutation = new win.MutationObserver(() => {
192
204
  if (edgeResize) {
@@ -194,7 +206,12 @@ watch(
194
206
  edgeResize.observe(el)
195
207
  for (const child of Array.from(el.children)) edgeResize.observe(child)
196
208
  }
197
- remeasure()
209
+ if (!edgeFrame) {
210
+ edgeFrame = win.requestAnimationFrame(() => {
211
+ edgeFrame = 0
212
+ remeasure()
213
+ })
214
+ }
198
215
  })
199
216
  edgeMutation.observe(el, { childList: true, subtree: true })
200
217
  }