@leavepulse/ui 0.94.0 → 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 (96) hide show
  1. package/dist/assets/{LpTable-DxnthVz4.css → LpTable-BJjNEvgJ.css} +57 -30
  2. package/dist/assets/LpTabs-7yQjX2ih.css +18 -0
  3. package/dist/chunks/{LpAddressInput-BCqR0zmv.js → LpAddressInput-C5VIgRp0.js} +1 -1
  4. package/dist/chunks/{LpAppShell-xEBmGV78.js → LpAppShell-C4b3ySa_.js} +3 -3
  5. package/dist/chunks/{LpCodeBlock-BgWcg2mk.js → LpCodeBlock-DTU40x8P.js} +1 -1
  6. package/dist/chunks/{LpCodeDisplay-DBi1YPLp.js → LpCodeDisplay-F2hjLb0X.js} +2 -2
  7. package/dist/chunks/{LpConfirmDialog-y6k0ryWR.js → LpConfirmDialog-DrHcIxRn.js} +1 -1
  8. package/dist/chunks/{LpConfirmHost-D-X0tDym.js → LpConfirmHost-D0Cd8FA_.js} +1 -1
  9. package/dist/chunks/{LpCopyButton-BGzw95Xc.js → LpCopyButton-CiqUS4SX.js} +1 -1
  10. package/dist/chunks/{LpDataList-B56Gu6Yt.js → LpDataList-Cit9fOSp.js} +2 -2
  11. package/dist/chunks/{LpDrawer-BkWjFdV0.js → LpDrawer-BHlqi62K.js} +1 -1
  12. package/dist/chunks/{LpFileTree-BN_zybBN.js → LpFileTree-gVjF_b6r.js} +1 -1
  13. package/dist/chunks/{LpInspector-oTfkOdYd.js → LpInspector-DSL1lINx.js} +2 -2
  14. package/dist/chunks/{LpLightbox-DPgz7IsT.js → LpLightbox--EwvQGe-.js} +1 -1
  15. package/dist/chunks/{LpLogViewer-BuIzr_6h.js → LpLogViewer-DSq9e8mT.js} +1 -1
  16. package/dist/chunks/{LpMediaGallery-CTejKF2-.js → LpMediaGallery-DlYJf3DS.js} +1 -1
  17. package/dist/chunks/{LpModal-D1E7rQzw.js → LpModal-COMHrBKL.js} +1 -1
  18. package/dist/chunks/{LpModalNav-DVXAF-DG.js → LpModalNav-Cj02cfhL.js} +2 -2
  19. package/dist/chunks/{LpNotificationBell-KRgdRZs-.js → LpNotificationBell-DNGijtmW.js} +1 -1
  20. package/dist/chunks/{LpNotificationFeed-CMGYU8c-.js → LpNotificationFeed-BoovbtfL.js} +3 -3
  21. package/dist/chunks/{LpPageScrollbar-C9sTeU-2.js → LpPageScrollbar-BniFeL2U.js} +5 -1
  22. package/dist/chunks/{LpPaletteTheme-CLwO-SDf.js → LpPaletteTheme-_FwkJO2o.js} +1 -1
  23. package/dist/chunks/{LpPasswordInput-LPVI7D3v.js → LpPasswordInput-BBDz2zyU.js} +1 -1
  24. package/dist/chunks/{LpPie-CsiBXe-e.js → LpPie-CtC4XdhC.js} +1 -1
  25. package/dist/chunks/{LpPipeline-DVcoSs--.js → LpPipeline-aCALaUY8.js} +1 -1
  26. package/dist/chunks/{LpRelativeTime-CN5bWD73.js → LpRelativeTime-9MHlbq6F.js} +1 -1
  27. package/dist/chunks/{LpScrollArea-CqvwfZs2.js → LpScrollArea-B_1KZOSS.js} +11 -1
  28. package/dist/chunks/{LpSecretField-BwrZ4TfT.js → LpSecretField-C9vwMFQ6.js} +4 -4
  29. package/dist/chunks/{LpSidebar-BIhusppV.js → LpSidebar-DPri9uyz.js} +4 -4
  30. package/dist/chunks/{LpSidebarNav-CFcI7--7.js → LpSidebarNav-CV1rU6La.js} +34 -20
  31. package/dist/chunks/{LpThemeStudio-BPPctXgd.js → LpThemeStudio-yiEdFJQL.js} +1 -1
  32. package/dist/chunks/{LpThemeSwitcher-B3c44xFH.js → LpThemeSwitcher-DKkCFaFk.js} +1 -1
  33. package/dist/chunks/{LpToaster-Cdx1tnHB.js → LpToaster-C7hHkGOA.js} +1 -1
  34. package/dist/chunks/LpTooltip-Bt1ZFViJ.js +333 -0
  35. package/dist/chunks/{LpTruncate-C_C8eiIE.js → LpTruncate-DEHWL1OA.js} +2 -2
  36. package/dist/chunks/{LpUptimeBar-Dt6SY_-m.js → LpUptimeBar-CXgzU5ym.js} +1 -1
  37. package/dist/chunks/{LpWorkspaceSwitcher-DCIiOQt_.js → LpWorkspaceSwitcher-CrUVSI7x.js} +1 -1
  38. package/dist/chunks/{RevealToggle-BsYxY6Oz.js → RevealToggle-D9Vs88kM.js} +1 -1
  39. package/dist/components/LpAddressInput.vue.js +1 -1
  40. package/dist/components/LpAppShell.vue.js +1 -1
  41. package/dist/components/LpCodeBlock.vue.js +1 -1
  42. package/dist/components/LpCodeDisplay.vue.js +1 -1
  43. package/dist/components/LpCommandPalette.vue.js +1 -1
  44. package/dist/components/LpConfirmDialog.vue.js +1 -1
  45. package/dist/components/LpConfirmHost.vue.js +1 -1
  46. package/dist/components/LpCopyButton.vue.js +1 -1
  47. package/dist/components/LpDataList.vue.js +1 -1
  48. package/dist/components/LpDock.vue.js +1 -1
  49. package/dist/components/LpDrawer.vue.js +1 -1
  50. package/dist/components/LpFileTree.vue.js +1 -1
  51. package/dist/components/LpInspector.vue.js +1 -1
  52. package/dist/components/LpLightbox.vue.js +1 -1
  53. package/dist/components/LpLogViewer.vue.js +1 -1
  54. package/dist/components/LpMediaGallery.vue.js +1 -1
  55. package/dist/components/LpModal.vue.js +1 -1
  56. package/dist/components/LpModalNav.vue.js +1 -1
  57. package/dist/components/LpNotificationBell.vue.js +1 -1
  58. package/dist/components/LpNotificationFeed.vue.js +1 -1
  59. package/dist/components/LpPageScrollbar.vue.js +1 -1
  60. package/dist/components/LpPaletteTheme.vue.js +1 -1
  61. package/dist/components/LpPasswordInput.vue.js +1 -1
  62. package/dist/components/LpPie.vue.js +1 -1
  63. package/dist/components/LpPipeline.vue.js +1 -1
  64. package/dist/components/LpRelativeTime.vue.js +1 -1
  65. package/dist/components/LpScrollArea.vue.js +1 -1
  66. package/dist/components/LpSecretField.vue.js +1 -1
  67. package/dist/components/LpShortcutsDialog.vue.js +1 -1
  68. package/dist/components/LpSidebar.vue.js +1 -1
  69. package/dist/components/LpSidebarNav.vue.js +1 -1
  70. package/dist/components/LpTable.vue.js +38 -12
  71. package/dist/components/LpTabs.vue.js +11 -6
  72. package/dist/components/LpThemeStudio.vue.js +1 -1
  73. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  74. package/dist/components/LpToaster.vue.js +1 -1
  75. package/dist/components/LpTooltip.vue.d.ts +3 -3
  76. package/dist/components/LpTooltip.vue.js +1 -1
  77. package/dist/components/LpTruncate.vue.js +1 -1
  78. package/dist/components/LpUptimeBar.vue.js +1 -1
  79. package/dist/components/LpWorkspaceSwitcher.vue.js +1 -1
  80. package/dist/components/RevealToggle.vue.js +1 -1
  81. package/dist/components/tableFeatures.d.ts +1 -0
  82. package/dist/components/tableFeatures.js +25 -0
  83. package/dist/composables/useShift.js +28 -11
  84. package/dist/index.js +34 -34
  85. package/package.json +1 -1
  86. package/src/components/LpPageScrollbar.vue +14 -1
  87. package/src/components/LpScrollArea.vue +18 -1
  88. package/src/components/LpSidebar.vue +1 -1
  89. package/src/components/LpSidebarNav.vue +18 -8
  90. package/src/components/LpTable.vue +76 -4
  91. package/src/components/LpTabs.vue +14 -5
  92. package/src/components/LpTooltip.vue +153 -14
  93. package/src/components/tableFeatures.ts +36 -0
  94. package/src/composables/useShift.ts +45 -15
  95. package/dist/assets/LpTabs-D7EyG21l.css +0 -18
  96. package/dist/chunks/LpTooltip-BKde8Xjv.js +0 -230
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-xEBmGV78.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-DVXAF-DG.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-BIhusppV.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.0",
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
  }
@@ -185,7 +185,7 @@ const props = withDefaults(
185
185
  }>(),
186
186
  {
187
187
  skeletonRows: 6,
188
- skeletonHeader: true,
188
+ skeletonHeader: false,
189
189
  responsive: false,
190
190
  mobileBreakpoint: "md",
191
191
  divider: true,
@@ -56,7 +56,7 @@ const props = withDefaults(
56
56
  previewDelay?: number
57
57
  labels: { pinned: string; pin: string; unpin: string; expand: string }
58
58
  }>(),
59
- { skeletonRows: 6, skeletonHeader: true, collapsedKeys: () => [], hoverFollow: false, pinned: () => [], previewDelay: 900 },
59
+ { skeletonRows: 6, skeletonHeader: false, collapsedKeys: () => [], hoverFollow: false, pinned: () => [], previewDelay: 900 },
60
60
  )
61
61
 
62
62
  const emit = defineEmits<{
@@ -212,6 +212,8 @@ function activate(item: SidebarItem) {
212
212
  }
213
213
 
214
214
  // The nav fills the remaining height with a fixed gap between groups; a short sidebar needs both under the consumer's control.
215
+ const SKELETON_WIDTHS = ["55%", "70%", "45%", "62%", "50%", "68%"]
216
+
215
217
  const { class: rootClass, attrs: rest } = useMergedAttrs(
216
218
  "flex min-h-0 flex-1 flex-col gap-4",
217
219
  )
@@ -222,7 +224,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
222
224
  LpSkeleton wrapper so it pulses in phase with every other placeholder
223
225
  on the page and stops under reduced motion. -->
224
226
  <LpSkeleton v-if="loading"
225
- :class="rootClass"
227
+ :class="[rootClass, 'overflow-hidden']"
226
228
  v-bind="rest">
227
229
  <div v-if="skeletonHeader" class="flex items-center gap-3 px-1">
228
230
  <div class="lp-skeleton-item size-10 shrink-0 rounded-pill bg-surface-soft" />
@@ -231,12 +233,20 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
231
233
  <div class="lp-skeleton-item h-3 w-16 rounded-small bg-surface-soft/60" />
232
234
  </div>
233
235
  </div>
234
- <div class="space-y-1">
235
- <div
236
- v-for="n in skeletonRows"
237
- :key="n"
238
- class="lp-skeleton-item h-9 rounded-control bg-surface-soft"
239
- />
236
+ <!-- Rows in the shape of the items they stand in for: an icon and a label
237
+ of uneven width at the item's own height and padding, with a section
238
+ label after the first three. A run of full-width bars read as a list
239
+ of buttons, not as navigation. -->
240
+ <div class="flex flex-col gap-1">
241
+ <template v-for="n in skeletonRows" :key="n">
242
+ <div v-if="n === 4" class="px-3 pb-1 pt-3">
243
+ <div class="lp-skeleton-item h-2.5 w-20 rounded-small bg-surface-soft/60" />
244
+ </div>
245
+ <div class="flex h-9 items-center gap-3 px-3">
246
+ <div class="lp-skeleton-item size-4 shrink-0 rounded-small bg-surface-soft" />
247
+ <div class="lp-skeleton-item h-3 rounded-small bg-surface-soft" :style="{ width: SKELETON_WIDTHS[(n - 1) % SKELETON_WIDTHS.length] }" />
248
+ </div>
249
+ </template>
240
250
  </div>
241
251
  </LpSkeleton>
242
252
 
@@ -39,6 +39,7 @@ import {
39
39
  orderPinned,
40
40
  pinOffsets,
41
41
  presetHidden,
42
+ rowChanges,
42
43
  rowWindow,
43
44
  sortByKeys,
44
45
  type ColumnPin,
@@ -48,6 +49,7 @@ import {
48
49
  import { devWarn } from "../composables/devWarn"
49
50
  import { startPointerDrag } from "../composables/pointerDrag"
50
51
  import { isHTMLElement, nodeWindow } from "../composables/useView"
52
+ import { prefersReducedMotion } from "../composables/easing"
51
53
  import LpButton from "./LpButton.vue"
52
54
  import { downloadFile, fileStem, toCsv, type CsvOptions } from "./exportData"
53
55
  import {
@@ -1708,6 +1710,47 @@ const roving = useRovingFocus(rovingItems, {
1708
1710
  },
1709
1711
  })
1710
1712
 
1713
+ /*
1714
+ * A change that brings in, takes out or reorders many rows at once — a filter
1715
+ * lifted from ten rows back to sixty, a page of new rows, a sort of a long
1716
+ * list — is not animated row by row. Each row eased on its own reads as noise
1717
+ * at that size, and following them is costly: TransitionGroup measures every
1718
+ * row before and after (a forced layout of all the new rows inside the click),
1719
+ * then sets an enter or move transition on each. The rows land at once and the
1720
+ * body eases in as one instead, a single opacity animation on the compositor.
1721
+ * A few rows leaving, arriving or moving (a filter that hides some, a row
1722
+ * deleted) keep their own motion, which is what lets the eye follow them.
1723
+ *
1724
+ * Counted by rowChanges: the rows that arrive, leave or change their order;
1725
+ * the ones that only slide aside to close a gap do not count.
1726
+ */
1727
+ const ROW_MOTION_LIMIT = 12
1728
+ const rowsEl = shallowRef<HTMLElement | null>(null)
1729
+ function setRowsEl(el: unknown) {
1730
+ const node = (el as { $el?: HTMLElement } | null)?.$el ?? null
1731
+ rowsEl.value = node
1732
+ roving.setContainer(node)
1733
+ }
1734
+ const motionIds = computed(() => (headerless.value ? allEntries.value : viewEntries.value).map((entry) => entry.id))
1735
+ /* The rows on screen, written after each render: what the next change is measured against. */
1736
+ let shownIds: readonly string[] = []
1737
+ const bigSwap = computed(() => rowChanges(shownIds, motionIds.value) > ROW_MOTION_LIMIT)
1738
+ let settleFlip = false
1739
+ watch(
1740
+ motionIds,
1741
+ (ids) => {
1742
+ const eased = bigSwap.value && shownIds.length > 0 && ids.length > 0
1743
+ shownIds = ids
1744
+ const body = rowsEl.value
1745
+ if (!eased || !body || props.virtualRowHeight || prefersReducedMotion(nodeWindow(body))) return
1746
+ // Two names for one animation: switching between them restarts it without
1747
+ // the reflow that taking a class off and putting it back would need.
1748
+ settleFlip = !settleFlip
1749
+ body.dataset.lpSettle = settleFlip ? "a" : "b"
1750
+ },
1751
+ { flush: "post", immediate: true },
1752
+ )
1753
+
1711
1754
  function onRowKeydown(event: KeyboardEvent) {
1712
1755
  // Space ticks rather than activates when the table is selectable — the
1713
1756
  // standard split for a multi-select list.
@@ -2088,10 +2131,11 @@ usePaletteCommands(() => {
2088
2131
  <TransitionGroup
2089
2132
  tag="tbody"
2090
2133
  name="lp-row"
2091
- :css="animating && !virtualRowHeight"
2134
+ :css="animating && !virtualRowHeight && !bigSwap"
2135
+ :move-class="bigSwap ? 'lp-row-still' : undefined"
2092
2136
  :class="busy && displayRows.length ? 'opacity-60 transition-opacity' : 'transition-opacity'"
2093
2137
  :aria-busy="busy || undefined"
2094
- :ref="(el: unknown) => roving.setContainer((el as { $el?: HTMLElement })?.$el ?? null)"
2138
+ :ref="setRowsEl"
2095
2139
  >
2096
2140
  <!-- The first page on its way: rows in the shape of the columns rather
2097
2141
  than a spinner in an empty box, so the table already has its height
@@ -2252,7 +2296,8 @@ usePaletteCommands(() => {
2252
2296
  :key="activeLayout"
2253
2297
  tag="div"
2254
2298
  name="lp-row"
2255
- :css="animating"
2299
+ :css="animating && !bigSwap"
2300
+ :move-class="bigSwap ? 'lp-row-still' : undefined"
2256
2301
  v-bind="scrollAttrs"
2257
2302
  class="min-h-0 transition-opacity"
2258
2303
  :class="[
@@ -2263,7 +2308,7 @@ usePaletteCommands(() => {
2263
2308
  ]"
2264
2309
  :style="activeLayout === 'cards' ? { gridTemplateColumns: `repeat(auto-fill, minmax(min(${cardWidth}, 100%), 1fr))` } : undefined"
2265
2310
  :aria-busy="busy || undefined"
2266
- :ref="(el: unknown) => roving.setContainer((el as { $el?: HTMLElement })?.$el ?? null)"
2311
+ :ref="setRowsEl"
2267
2312
  >
2268
2313
  <template v-if="displayRows.length === 0 && busy">
2269
2314
  <div
@@ -2501,6 +2546,30 @@ usePaletteCommands(() => {
2501
2546
  transition: transform var(--duration-medium) var(--ease-emphasized);
2502
2547
  }
2503
2548
 
2549
+ /*
2550
+ * A change too big to animate row by row (see ROW_MOTION_LIMIT): the rows
2551
+ * land at once and the body comes up from half-faded as one. `lp-row-still`
2552
+ * is the move class then, and has no transition on purpose: TransitionGroup
2553
+ * checks the move class for one before it measures the rows, and skips the
2554
+ * measuring when there is none.
2555
+ */
2556
+ [data-lp-settle="a"] {
2557
+ animation: lp-rows-settle-a var(--duration-fast) var(--ease-emphasized);
2558
+ }
2559
+ [data-lp-settle="b"] {
2560
+ animation: lp-rows-settle-b var(--duration-fast) var(--ease-emphasized);
2561
+ }
2562
+ @keyframes lp-rows-settle-a {
2563
+ from {
2564
+ opacity: 0.4;
2565
+ }
2566
+ }
2567
+ @keyframes lp-rows-settle-b {
2568
+ from {
2569
+ opacity: 0.4;
2570
+ }
2571
+ }
2572
+
2504
2573
  .lp-row-enter-from,
2505
2574
  .lp-row-leave-to {
2506
2575
  opacity: 0;
@@ -2624,5 +2693,8 @@ tr:hover .lp-tick-cue,
2624
2693
  .lp-tick {
2625
2694
  transition: none;
2626
2695
  }
2696
+ [data-lp-settle] {
2697
+ animation: none;
2698
+ }
2627
2699
  }
2628
2700
  </style>
@@ -3,7 +3,8 @@ import { isHTMLElement } from "../composables/useView"
3
3
  import { usePaletteCommands, usePaletteScope } from "../composables/usePaletteCommands"
4
4
  import { Motion } from "motion-v"
5
5
  import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "reka-ui"
6
- import { computed, nextTick, ref, useId, watch, type FunctionalComponent } from "vue"
6
+ import { computed, nextTick, onMounted, ref, useId, watch, type FunctionalComponent } from "vue"
7
+ import { useResizeObserver } from "../composables/useResizeObserver"
7
8
  import { usePillTransition } from "../composables/usePillTransition"
8
9
  import { useStepHistory } from "../composables/useOverlayHistory"
9
10
  import LpContextMenu, { type ContextMenuItemDef } from "./LpContextMenu.vue"
@@ -106,13 +107,21 @@ watch(
106
107
  // A row wider than its container scrolls sideways (a phone, a narrow card)
107
108
  // instead of wrapping each label onto two lines. LpScrollStrip lets a mouse
108
109
  // reach the tabs off to the side (wheel, drag, edge buttons), and the active
109
- // tab is brought into view whenever it changes, including from outside.
110
+ // tab is brought into view whenever it changes, including from outside, and
111
+ // also on mount and when the row resizes: a tab picked by the address before
112
+ // the first paint, or left beyond the edge by a narrower window, would
113
+ // otherwise sit off-screen with nothing saying which section is open. Those
114
+ // two jump; only a change the person can follow eases.
110
115
  const strip = ref<InstanceType<typeof LpScrollStrip> | null>(null)
111
116
  const Passthrough: FunctionalComponent = (_, { slots }) => slots.default?.()
112
117
  const list = ref<{ $el: HTMLElement } | null>(null)
113
- watch(current, () => {
114
- void nextTick(() => strip.value?.reveal(list.value?.$el?.querySelector('[data-state="active"]')))
115
- })
118
+ function revealActive(smooth: boolean) {
119
+ if (bottom.value) return
120
+ strip.value?.reveal(list.value?.$el?.querySelector('[data-state="active"]'), { smooth })
121
+ }
122
+ watch(current, () => void nextTick(() => revealActive(true)))
123
+ onMounted(() => requestAnimationFrame(() => revealActive(false)))
124
+ useResizeObserver(() => strip.value?.scroller, () => revealActive(false))
116
125
 
117
126
  /*
118
127
  * reka selects a tab on mousedown, so a press meant to drag the row would