@leavepulse/ui 0.72.8 → 0.73.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{DropzoneLinkField-C-9BCGJn.js → DropzoneLinkField-ppY9xalk.js} +2 -2
- package/dist/chunks/{FieldWrapper-CORPzo9s.js → FieldWrapper-y5bKBNxA.js} +1 -1
- package/dist/chunks/{LpActionBar-BP1ld7-S.js → LpActionBar-B55msXTr.js} +2 -2
- package/dist/chunks/{LpAddressInput-Al3HT5ey.js → LpAddressInput-mf_dEpj_.js} +3 -3
- package/dist/chunks/{LpAlert-n5XPAZfv.js → LpAlert-Cg7oIx1B.js} +2 -2
- package/dist/chunks/{LpAppShell-CPCG0I-c.js → LpAppShell-B0Yu9MVs.js} +11 -5
- package/dist/chunks/{LpBadge-wUYLN4U9.js → LpBadge-0A6sPks3.js} +1 -1
- package/dist/chunks/{LpBottomNav-CbNQQPuL.js → LpBottomNav-Dik-ZcHv.js} +1 -1
- package/dist/chunks/{LpBreadcrumbs-DPdbth-c.js → LpBreadcrumbs-ssZV3_od.js} +1 -1
- package/dist/chunks/{LpButton-CFb44IjC.js → LpButton-BgdewXxF.js} +1 -1
- package/dist/chunks/{LpCard-r13WRqox.js → LpCard-BJ59q6hR.js} +1 -1
- package/dist/chunks/{LpCheckbox-Cs4SHaHX.js → LpCheckbox-B0kJ-t6T.js} +1 -1
- package/dist/chunks/{LpCodeBlock-DRC8VbXW.js → LpCodeBlock-CXR_7t_F.js} +1 -1
- package/dist/chunks/{LpCodeDisplay-CE9TxCA4.js → LpCodeDisplay-BCghfBFC.js} +4 -4
- package/dist/chunks/{LpConfirmDialog-DY2VjDji.js → LpConfirmDialog-CaA4pAre.js} +1 -1
- package/dist/chunks/{LpConfirmHost-DvSZTJ4N.js → LpConfirmHost-CBIzALSL.js} +1 -1
- package/dist/chunks/{LpCopyButton-xF7wFVoU.js → LpCopyButton-Cw-lF7Q3.js} +1 -1
- package/dist/chunks/{LpCountdown-DgeY3cLG.js → LpCountdown-BNNhnQAK.js} +1 -1
- package/dist/chunks/{LpDataList-Jxyl9H5w.js → LpDataList-CcAA-rD9.js} +1 -1
- package/dist/chunks/{LpEditable-Cy6GLbFx.js → LpEditable-CSuJIPbG.js} +2 -2
- package/dist/chunks/{LpFileTree-zIFEgo3I.js → LpFileTree-CxOh3rL2.js} +1 -1
- package/dist/chunks/{LpFileTreeNode-cT6BIWvz.js → LpFileTreeNode-9ue2P7ER.js} +3 -3
- package/dist/chunks/{LpFormField-Ch69Jd-X.js → LpFormField-BBFg8i2I.js} +1 -1
- package/dist/chunks/{LpHintLayer-CgObdUsM.js → LpHintLayer-Db_s9_DL.js} +2 -2
- package/dist/chunks/{LpHints-Bz-BlaSl.js → LpHints-Cxf5GXsx.js} +3 -3
- package/dist/chunks/{LpInfraNode-46XOCkfq.js → LpInfraNode-6NLxkAnr.js} +2 -2
- package/dist/chunks/{LpInput-Tw-yxT4I.js → LpInput-B2dTt4pc.js} +1 -1
- package/dist/chunks/{LpLightbox-B95yu22B.js → LpLightbox-Coe4OBUl.js} +2 -2
- package/dist/chunks/{LpLoader-DVwkOmt9.js → LpLoader-DPTNhqLu.js} +1 -1
- package/dist/chunks/{LpLogViewer-D25jM2_I.js → LpLogViewer-DxiR6Mbd.js} +3 -3
- package/dist/chunks/{LpMapPicker-DRGgh89B.js → LpMapPicker-DeJRMfFN.js} +1 -1
- package/dist/chunks/{LpMediaGallery-Bkram-MO.js → LpMediaGallery-B7Km8N9l.js} +1 -1
- package/dist/chunks/{LpModalNav-DQpV2kdn.js → LpModalNav-BmxEyqOx.js} +2 -2
- package/dist/chunks/{LpNotificationBell-3244LUVc.js → LpNotificationBell-u8-ZjRON.js} +3 -3
- package/dist/chunks/{LpPaletteTheme-DiLYKQiZ.js → LpPaletteTheme-CWAIjBCi.js} +3 -3
- package/dist/chunks/{LpPasswordInput-BkHKQDhM.js → LpPasswordInput-Ih7Lv43S.js} +2 -2
- package/dist/chunks/{LpPie-DrZepi0p.js → LpPie-Idujdb3M.js} +2 -2
- package/dist/chunks/{LpPipeline-B3aOVOkV.js → LpPipeline-QCZWWB0G.js} +2 -2
- package/dist/chunks/{LpRepeater-D7ZmnIYd.js → LpRepeater-DghUJ3bc.js} +2 -2
- package/dist/chunks/{LpScramble-Bn9OoOtC.js → LpScramble-DeT_D36q.js} +1 -1
- package/dist/chunks/{LpSecretField-BbmqM9ye.js → LpSecretField-osKPNdNT.js} +6 -6
- package/dist/chunks/{LpShift-CCq7dofl.js → LpShift-kKUeG9NS.js} +4 -2
- package/dist/chunks/{LpSidebar-BoNLKgh-.js → LpSidebar-CR_WKcn2.js} +2 -2
- package/dist/chunks/{LpSidebarNav-Bky8chrv.js → LpSidebarNav-h3YunOAr.js} +2 -2
- package/dist/chunks/{LpSidebarRow-BRYhNDSo.js → LpSidebarRow-SjV0Ouhq.js} +1 -1
- package/dist/chunks/{LpStat-BVf2UvEc.js → LpStat-DXqKD1h5.js} +34 -18
- package/dist/chunks/{LpStatus-DglxttQ7.js → LpStatus-DfZREVe0.js} +2 -2
- package/dist/chunks/{LpStepMark-DpzKVyh8.js → LpStepMark-TaAyuNsH.js} +1 -1
- package/dist/chunks/{LpStepper-DpsocBNJ.js → LpStepper-CKSTFzHE.js} +1 -1
- package/dist/chunks/{LpSwap-C96c0LWh.js → LpSwap-KIS24N8W.js} +1 -1
- package/dist/chunks/{LpSwitch-BnXd1llc.js → LpSwitch-DlZHmj-M.js} +1 -1
- package/dist/chunks/{LpTabFace-DPCwKkH2.js → LpTabFace-JFJLW0kA.js} +1 -1
- package/dist/chunks/{LpTableFilter-CiVBpaq0.js → LpTableFilter-47ANnx_a.js} +3 -3
- package/dist/chunks/{LpTableOfContents-CraicEs4.js → LpTableOfContents-BN5zvpnx.js} +2 -2
- package/dist/chunks/{LpTagsInput-C-mDG648.js → LpTagsInput-CHoiid8u.js} +2 -2
- package/dist/chunks/{LpTextarea-TE-yZv2U.js → LpTextarea-CU7C1pLO.js} +1 -1
- package/dist/chunks/{LpThemeStudio-BpORDvH6.js → LpThemeStudio-zyOH3dF2.js} +2 -2
- package/dist/chunks/{LpThemeSwitcher-BnEn_mvf.js → LpThemeSwitcher-BXJhQYGD.js} +2 -2
- package/dist/chunks/{LpToaster-IwTXjbbU.js → LpToaster-C1D35SKk.js} +1 -1
- package/dist/chunks/{LpTopologyCanvas-B1gIbS0n.js → LpTopologyCanvas-1OufbBtQ.js} +1 -1
- package/dist/chunks/{LpTour-BZq-mUMv.js → LpTour-XshJslGg.js} +1 -1
- package/dist/chunks/{LpTruncate-CflAIwiJ.js → LpTruncate-qgKA-3K3.js} +1 -1
- package/dist/chunks/{LpUptimeBar-DqNvvMBK.js → LpUptimeBar-qhvvmmoI.js} +2 -2
- package/dist/chunks/{RevealToggle-BEit1n6Z.js → RevealToggle-6MlmohxS.js} +1 -1
- package/dist/chunks/{TourCard-DNclH3u_.js → TourCard-BuB-i4kv.js} +3 -3
- package/dist/components/DropzoneLinkField.vue.js +1 -1
- package/dist/components/FieldWrapper.vue.js +1 -1
- package/dist/components/LpActionBar.vue.js +1 -1
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAlert.vue.js +1 -1
- package/dist/components/LpAppShell.vue.d.ts +20 -0
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpBadge.vue.js +1 -1
- package/dist/components/LpBottomNav.vue.js +1 -1
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpButton.vue.js +1 -1
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.js +2 -2
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpCodeDisplay.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +2 -2
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.js +1 -1
- package/dist/components/LpCopyButton.vue.js +1 -1
- package/dist/components/LpCountdown.vue.js +1 -1
- package/dist/components/LpDataList.vue.js +1 -1
- package/dist/components/LpDropzone.vue.js +1 -1
- package/dist/components/LpEditable.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpHintLayer.vue.js +1 -1
- package/dist/components/LpHints.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +1 -1
- package/dist/components/LpInfraNode.vue.js +1 -1
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLoader.vue.js +1 -1
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpPaletteTheme.vue.js +1 -1
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPipeline.vue.js +1 -1
- package/dist/components/LpRepeater.vue.js +1 -1
- package/dist/components/LpScramble.vue.js +1 -1
- package/dist/components/LpSecretField.vue.js +1 -1
- package/dist/components/LpShift.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSidebarRow.vue.js +1 -1
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpStatus.vue.js +1 -1
- package/dist/components/LpStepMark.vue.js +1 -1
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/components/LpSwap.vue.js +1 -1
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTabFace.vue.js +1 -1
- package/dist/components/LpTable.vue.js +6 -6
- package/dist/components/LpTableFilter.vue.js +1 -1
- package/dist/components/LpTableOfContents.vue.js +1 -1
- package/dist/components/LpTabs.vue.js +1 -1
- package/dist/components/LpTagsInput.vue.js +1 -1
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeStudio.vue.js +1 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/components/LpTopologyCanvas.vue.js +1 -1
- package/dist/components/LpTour.vue.js +1 -1
- package/dist/components/LpTruncate.vue.js +1 -1
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/RevealToggle.vue.js +1 -1
- package/dist/components/TourCard.vue.js +1 -1
- package/dist/composables/scroll.d.ts +2 -0
- package/dist/composables/scroll.js +4 -0
- package/dist/composables/scrollMemory.d.ts +1 -0
- package/dist/composables/scrollMemory.js +111 -0
- package/dist/composables/useFitScale.d.ts +5 -0
- package/dist/composables/useFitScale.js +30 -0
- package/dist/composables/useShift.d.ts +2 -0
- package/dist/composables/useShift.js +5 -0
- package/dist/index.js +56 -56
- package/package.json +1 -1
- package/src/components/LpAppShell.vue +18 -2
- package/src/components/LpShift.vue +4 -2
- package/src/components/LpStat.vue +24 -3
- package/src/components/LpTableOfContents.vue +4 -2
- package/src/composables/scroll.ts +5 -0
- package/src/composables/scrollMemory.ts +145 -0
- package/src/composables/useFitScale.ts +43 -0
- package/src/composables/useShift.ts +10 -0
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { _ } from "./chunks/LayoutCanvas-CNOAUk7D.js";
|
|
2
|
-
import { _ as _2 } from "./chunks/LpAddressInput-
|
|
3
|
-
import { _ as _3 } from "./chunks/LpMapPicker-
|
|
2
|
+
import { _ as _2 } from "./chunks/LpAddressInput-mf_dEpj_.js";
|
|
3
|
+
import { _ as _3 } from "./chunks/LpMapPicker-DeJRMfFN.js";
|
|
4
4
|
import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
|
|
5
|
-
import { _ as _4 } from "./chunks/LpActionBar-
|
|
6
|
-
import { _ as _5 } from "./chunks/LpAlert-
|
|
7
|
-
import { _ as _6 } from "./chunks/LpAppShell-
|
|
5
|
+
import { _ as _4 } from "./chunks/LpActionBar-B55msXTr.js";
|
|
6
|
+
import { _ as _5 } from "./chunks/LpAlert-Cg7oIx1B.js";
|
|
7
|
+
import { _ as _6 } from "./chunks/LpAppShell-B0Yu9MVs.js";
|
|
8
8
|
import { _ as _7 } from "./chunks/LpAutocomplete-DOu7FN5P.js";
|
|
9
9
|
import { _ as _8 } from "./chunks/LpAvatar-Cg6Az3wz.js";
|
|
10
|
-
import { _ as _9 } from "./chunks/LpBadge-
|
|
11
|
-
import { _ as _10 } from "./chunks/LpBreadcrumbs-
|
|
12
|
-
import { _ as _11 } from "./chunks/LpButton-
|
|
10
|
+
import { _ as _9 } from "./chunks/LpBadge-0A6sPks3.js";
|
|
11
|
+
import { _ as _10 } from "./chunks/LpBreadcrumbs-ssZV3_od.js";
|
|
12
|
+
import { _ as _11 } from "./chunks/LpButton-BgdewXxF.js";
|
|
13
13
|
import { _ as _12 } from "./chunks/LpCalendar-CuoWks-0.js";
|
|
14
|
-
import { _ as _13 } from "./chunks/LpCard-
|
|
14
|
+
import { _ as _13 } from "./chunks/LpCard-BJ59q6hR.js";
|
|
15
15
|
import { default as default2 } from "./components/LpChart.vue.js";
|
|
16
16
|
import { backgroundOf, csvField, downloadFile, fileStem, inlineSvg, resolveCssColor, svgToPng, toCsv } from "./components/exportData.js";
|
|
17
17
|
import { CHART_PALETTE, axisTicks, chartSummary, formatTick, markerIndex, niceScale, resolveSlices } from "./components/chart.js";
|
|
18
|
-
import { _ as _14 } from "./chunks/LpCheckbox-
|
|
19
|
-
import { _ as _15 } from "./chunks/LpCodeBlock-
|
|
18
|
+
import { _ as _14 } from "./chunks/LpCheckbox-B0kJ-t6T.js";
|
|
19
|
+
import { _ as _15 } from "./chunks/LpCodeBlock-CXR_7t_F.js";
|
|
20
20
|
import { tokenizeLines } from "./components/codeHighlight.js";
|
|
21
21
|
import { _ as _16 } from "./chunks/LpColorPicker-1y1QJHZR.js";
|
|
22
22
|
import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, normalizeHue, opaqueCss, parseColor, parseHex, rgbToHex, rgbToHsv } from "./components/color.js";
|
|
@@ -30,8 +30,8 @@ import { default as default6 } from "./components/LpPaletteStats.vue.js";
|
|
|
30
30
|
import { default as default7 } from "./components/LpPaletteSwatches.vue.js";
|
|
31
31
|
import { default as default8 } from "./components/LpKeys.vue.js";
|
|
32
32
|
import { comboKeys, comboSteps } from "./components/keys.js";
|
|
33
|
-
import { _ as _18 } from "./chunks/LpConfirmDialog-
|
|
34
|
-
import { _ as _19 } from "./chunks/LpConfirmHost-
|
|
33
|
+
import { _ as _18 } from "./chunks/LpConfirmDialog-CaA4pAre.js";
|
|
34
|
+
import { _ as _19 } from "./chunks/LpConfirmHost-CBIzALSL.js";
|
|
35
35
|
import { confirm, useConfirm } from "./components/confirm.js";
|
|
36
36
|
import { _ as _20 } from "./chunks/LpContextMenu-rx2tCjwk.js";
|
|
37
37
|
import { _ as _21 } from "./chunks/LpDatePicker-CA0QTfBC.js";
|
|
@@ -44,31 +44,31 @@ import { _ as _26 } from "./chunks/LpDrawer-RRamxbLV.js";
|
|
|
44
44
|
import { _ as _27 } from "./chunks/LpDropdownMenu-Dl7Z4ZhS.js";
|
|
45
45
|
import { default as default9 } from "./components/LpDropzone.vue.js";
|
|
46
46
|
import { _ as _28 } from "./chunks/LpEmptyState-EQHiRYhG.js";
|
|
47
|
-
import { _ as _29 } from "./chunks/LpFileTree-
|
|
47
|
+
import { _ as _29 } from "./chunks/LpFileTree-CxOh3rL2.js";
|
|
48
48
|
import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
|
|
49
49
|
import { _ as _30 } from "./chunks/LpFieldNotice-CzQ2_5rQ.js";
|
|
50
|
-
import { _ as _31 } from "./chunks/LpFormField-
|
|
50
|
+
import { _ as _31 } from "./chunks/LpFormField-BBFg8i2I.js";
|
|
51
51
|
import { _ as _32 } from "./chunks/LpIcon--5WSb3jJ.js";
|
|
52
52
|
import { i, b, a, c } from "./chunks/icons-DMITlfw5.js";
|
|
53
53
|
import { default as default10 } from "./components/LpImageEditor.vue.js";
|
|
54
|
-
import { _ as _33 } from "./chunks/LpInfraNode-
|
|
55
|
-
import { _ as _34 } from "./chunks/LpInput-
|
|
56
|
-
import { _ as _35 } from "./chunks/LpLightbox-
|
|
54
|
+
import { _ as _33 } from "./chunks/LpInfraNode-6NLxkAnr.js";
|
|
55
|
+
import { _ as _34 } from "./chunks/LpInput-B2dTt4pc.js";
|
|
56
|
+
import { _ as _35 } from "./chunks/LpLightbox-Coe4OBUl.js";
|
|
57
57
|
import { fileNameOf } from "./components/lightbox.js";
|
|
58
58
|
import { _ as _36 } from "./chunks/LpLink-Krkjhe_y.js";
|
|
59
|
-
import { _ as _37 } from "./chunks/LpLogViewer-
|
|
59
|
+
import { _ as _37 } from "./chunks/LpLogViewer-DxiR6Mbd.js";
|
|
60
60
|
import { countLevels, matchPositions, matchesTerm, ringWindow, stepMatch } from "./components/logSearch.js";
|
|
61
|
-
import { _ as _38 } from "./chunks/LpMediaGallery-
|
|
61
|
+
import { _ as _38 } from "./chunks/LpMediaGallery-B7Km8N9l.js";
|
|
62
62
|
import { _ as _39 } from "./chunks/LpModal-BnjZ2iem.js";
|
|
63
|
-
import { _ as _40 } from "./chunks/LpModalNav-
|
|
64
|
-
import { _ as _41 } from "./chunks/LpNotificationBell-
|
|
63
|
+
import { _ as _40 } from "./chunks/LpModalNav-BmxEyqOx.js";
|
|
64
|
+
import { _ as _41 } from "./chunks/LpNotificationBell-u8-ZjRON.js";
|
|
65
65
|
import { _ as _42 } from "./chunks/LpNumberField-e0IBkWU1.js";
|
|
66
66
|
import { _ as _43 } from "./chunks/LpTimeField-BawSVsmt.js";
|
|
67
67
|
import { _ as _44 } from "./chunks/LpNumberFlow-Vqj0tP7B.js";
|
|
68
68
|
import { _ as _45 } from "./chunks/LpOtpInput-CeBPsM7D.js";
|
|
69
69
|
import { _ as _46 } from "./chunks/LpPagination-BIIiYHXR.js";
|
|
70
|
-
import { _ as _47 } from "./chunks/LpPasswordInput-
|
|
71
|
-
import { _ as _48 } from "./chunks/LpPie-
|
|
70
|
+
import { _ as _47 } from "./chunks/LpPasswordInput-Ih7Lv43S.js";
|
|
71
|
+
import { _ as _48 } from "./chunks/LpPie-Idujdb3M.js";
|
|
72
72
|
import { _ as _49 } from "./chunks/LpPhoneInput-CETEp5W7.js";
|
|
73
73
|
import { filterCountries, flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
|
|
74
74
|
import { _ as _50 } from "./chunks/LpPopover-DmZ3wUtP.js";
|
|
@@ -82,41 +82,41 @@ import { _ as _57 } from "./chunks/LpSection-DFK_uoJE.js";
|
|
|
82
82
|
import { _ as _58 } from "./chunks/LpSelect-Cxq4yBGd.js";
|
|
83
83
|
import { fitChips, toggledValues } from "./components/select.js";
|
|
84
84
|
import { _ as _59 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
85
|
-
import { _ as _60 } from "./chunks/LpShift-
|
|
86
|
-
import { _ as _61 } from "./chunks/LpSwap-
|
|
85
|
+
import { _ as _60 } from "./chunks/LpShift-kKUeG9NS.js";
|
|
86
|
+
import { _ as _61 } from "./chunks/LpSwap-KIS24N8W.js";
|
|
87
87
|
import { _ as _62 } from "./chunks/LpHintExample-9Py0wc-L.js";
|
|
88
88
|
import { default as default11 } from "./components/LpShortcutsDialog.vue.js";
|
|
89
|
-
import { _ as _63 } from "./chunks/LpSidebar-
|
|
89
|
+
import { _ as _63 } from "./chunks/LpSidebar-CR_WKcn2.js";
|
|
90
90
|
import { _ as _64 } from "./chunks/LpSkeleton-BB6XIV-w.js";
|
|
91
91
|
import { _ as _65 } from "./chunks/LpSlider-DxYoCJJO.js";
|
|
92
92
|
import { _ as _66 } from "./chunks/LpRangeSlider-CM-0ZITZ.js";
|
|
93
93
|
import { _ as _67 } from "./chunks/LpVideoBackdrop-DS1wGv-X.js";
|
|
94
94
|
import { formatClipTime, isNativeLoop, planLoop, seamProgress, seamReached } from "./components/videoBackdrop.js";
|
|
95
95
|
import { _ as _68 } from "./chunks/LpSparkline-CExIRDb3.js";
|
|
96
|
-
import { _ as _69 } from "./chunks/LpStat-
|
|
97
|
-
import { _ as _70 } from "./chunks/LpStepper-
|
|
98
|
-
import { _ as _71 } from "./chunks/LpSwitch-
|
|
96
|
+
import { _ as _69 } from "./chunks/LpStat-DXqKD1h5.js";
|
|
97
|
+
import { _ as _70 } from "./chunks/LpStepper-CKSTFzHE.js";
|
|
98
|
+
import { _ as _71 } from "./chunks/LpSwitch-DlZHmj-M.js";
|
|
99
99
|
import { default as default12 } from "./components/LpTable.vue.js";
|
|
100
100
|
import { compareValues } from "./components/tableSort.js";
|
|
101
101
|
import { resolveRowMenu } from "./components/tableRowMenu.js";
|
|
102
|
-
import { _ as _72 } from "./chunks/LpTableOfContents-
|
|
102
|
+
import { _ as _72 } from "./chunks/LpTableOfContents-BN5zvpnx.js";
|
|
103
103
|
import { default as default13 } from "./components/LpTabs.vue.js";
|
|
104
|
-
import { _ as _73 } from "./chunks/LpBottomNav-
|
|
105
|
-
import { _ as _74 } from "./chunks/LpTagsInput-
|
|
104
|
+
import { _ as _73 } from "./chunks/LpBottomNav-Dik-ZcHv.js";
|
|
105
|
+
import { _ as _74 } from "./chunks/LpTagsInput-CHoiid8u.js";
|
|
106
106
|
import { addTags, splitTags } from "./components/tags.js";
|
|
107
|
-
import { _ as _75 } from "./chunks/LpTextarea-
|
|
108
|
-
import { _ as _76 } from "./chunks/LpThemeSwitcher-
|
|
107
|
+
import { _ as _75 } from "./chunks/LpTextarea-CU7C1pLO.js";
|
|
108
|
+
import { _ as _76 } from "./chunks/LpThemeSwitcher-BXJhQYGD.js";
|
|
109
109
|
import { _ as _77 } from "./chunks/LpTilt-B7KHX1zH.js";
|
|
110
|
-
import { _ as _78 } from "./chunks/LpToaster-
|
|
110
|
+
import { _ as _78 } from "./chunks/LpToaster-C1D35SKk.js";
|
|
111
111
|
import { _ as _79 } from "./chunks/LpTooltip-BcBvIx4z.js";
|
|
112
|
-
import { _ as _80 } from "./chunks/LpTour-
|
|
112
|
+
import { _ as _80 } from "./chunks/LpTour-XshJslGg.js";
|
|
113
113
|
import { holeOf, openContextMenu, panelsAround } from "./components/tour.js";
|
|
114
|
-
import { _ as _81 } from "./chunks/LpHintLayer-
|
|
115
|
-
import { _ as _82 } from "./chunks/LpHints-
|
|
114
|
+
import { _ as _81 } from "./chunks/LpHintLayer-Db_s9_DL.js";
|
|
115
|
+
import { _ as _82 } from "./chunks/LpHints-Cxf5GXsx.js";
|
|
116
116
|
import { HINT_SIGNALS, contextMenuTip, createHintSystem, dropzoneTip, hintKey, hintSummary, hotkeyTip, localHintStorage, noteDropzone, noteHotkeyTarget, paletteTip, provideHintSystem, runningHintSystem, useHintSystem } from "./composables/useHintSystem.js";
|
|
117
117
|
import { _ as _83 } from "./chunks/LpTooltipProvider-CftjV7Xc.js";
|
|
118
|
-
import { _ as _84 } from "./chunks/LpTopologyCanvas-
|
|
119
|
-
import { _ as _85 } from "./chunks/LpUptimeBar-
|
|
118
|
+
import { _ as _84 } from "./chunks/LpTopologyCanvas-1OufbBtQ.js";
|
|
119
|
+
import { _ as _85 } from "./chunks/LpUptimeBar-qhvvmmoI.js";
|
|
120
120
|
import { deserializeLayout, serializeLayout } from "./layout/tree.js";
|
|
121
121
|
import { addLeaf, addTab, countBlocks, countLeaves, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, setActiveTab } from "./layout/tree.js";
|
|
122
122
|
import { blockTitle, defineBlocks } from "./layout/registry.js";
|
|
@@ -124,7 +124,7 @@ import { layoutController, useLayout } from "./layout/useLayout.js";
|
|
|
124
124
|
import { a as parseTheme, s as serializeTheme } from "./chunks/LpThemeProvider-8MG6yqU9.js";
|
|
125
125
|
import { D, _ as _86, T, b as b2, c as c2, d, e, f, g, l, h, n, i as i2, j, p, r, k, t, m, o, q, u, v } from "./chunks/LpThemeProvider-8MG6yqU9.js";
|
|
126
126
|
import { G, N, d as d2, i as i3, s } from "./chunks/backdrop-Dkf2vM81.js";
|
|
127
|
-
import { _ as _87, a as a2, b as b3, c as c3, d as d3, S, e as e2, u as u2, w } from "./chunks/LpThemeStudio-
|
|
127
|
+
import { _ as _87, a as a2, b as b3, c as c3, d as d3, S, e as e2, u as u2, w } from "./chunks/LpThemeStudio-zyOH3dF2.js";
|
|
128
128
|
import { useClipboard } from "./composables/useClipboard.js";
|
|
129
129
|
import { activeShortcuts, appleModifierLabel, findHotkeyConflicts, hotkeyConflicts, hotkeySteps, isAppleKeyboard, matchesHotkey, mergeShortcutGroups, parseCombo, pendingHotkey, sequenceProgress, useAppleKeyboard, useHotkeys } from "./composables/useHotkeys.js";
|
|
130
130
|
import { anyModalOpen, topModalElement, useModalLayer } from "./components/modalDepth.js";
|
|
@@ -163,10 +163,10 @@ import { useToast } from "./composables/useToast.js";
|
|
|
163
163
|
import { _ as _88 } from "./chunks/LpFrame-BVQCQLDI.js";
|
|
164
164
|
import { _ as _89 } from "./chunks/LpThemeStudioSection-B7bt8Iyg.js";
|
|
165
165
|
import { isInternalHref, resolveLink } from "./components/link.js";
|
|
166
|
-
import { _ as _90 } from "./chunks/LpRepeater-
|
|
166
|
+
import { _ as _90 } from "./chunks/LpRepeater-DghUJ3bc.js";
|
|
167
167
|
import { _ as _91 } from "./chunks/LpGauge-KZaQ_FDR.js";
|
|
168
168
|
import { _ as _92 } from "./chunks/LpQuota-Dk2MyI2Z.js";
|
|
169
|
-
import { _ as _93 } from "./chunks/LpStatus-
|
|
169
|
+
import { _ as _93 } from "./chunks/LpStatus-DfZREVe0.js";
|
|
170
170
|
import { _ as _94 } from "./chunks/LpRelativeTime-DwgCb5-8.js";
|
|
171
171
|
import { _ as _95 } from "./chunks/LpActivityLine-CJvzrNpj.js";
|
|
172
172
|
import { TONE_COLOR, TONE_SOFT, arcPath, capacityThresholds, meterFraction, toneAt } from "./components/meter.js";
|
|
@@ -175,20 +175,20 @@ import { formatAmount, quotaSegments, quotaState } from "./components/quota.js";
|
|
|
175
175
|
import { compactNumber, decimalMark, formatBytes } from "./components/format.js";
|
|
176
176
|
import { STATUS_LABELS, STATUS_LOOK } from "./components/status.js";
|
|
177
177
|
import { formatRelativeTime } from "./components/relativeTime.js";
|
|
178
|
-
import { _ as _96 } from "./chunks/LpPipeline-
|
|
179
|
-
import { _ as _97 } from "./chunks/LpStepMark-
|
|
178
|
+
import { _ as _96 } from "./chunks/LpPipeline-QCZWWB0G.js";
|
|
179
|
+
import { _ as _97 } from "./chunks/LpStepMark-TaAyuNsH.js";
|
|
180
180
|
import { childProgress, connectorFilled, currentStepIndex, isSettled, overallStatus, stepElapsed } from "./components/pipeline.js";
|
|
181
|
-
import { _ as _98 } from "./chunks/LpLoader-
|
|
181
|
+
import { _ as _98 } from "./chunks/LpLoader-DPTNhqLu.js";
|
|
182
182
|
import { useLoadingGate } from "./composables/useLoadingGate.js";
|
|
183
183
|
import { useNow } from "./composables/useNow.js";
|
|
184
|
-
import { _ as _99 } from "./chunks/LpCountdown-
|
|
184
|
+
import { _ as _99 } from "./chunks/LpCountdown-BNNhnQAK.js";
|
|
185
185
|
import { DEFAULT_MILESTONES, DEFAULT_UNIT_LABELS, ceilToSecond, crossedMilestone, formatElapsed, formatTime, msToNextSecond, splitTime, timeParts } from "./components/timeSpan.js";
|
|
186
|
-
import { _ as _100 } from "./chunks/LpCopyButton-
|
|
187
|
-
import { _ as _101 } from "./chunks/LpSecretField-
|
|
188
|
-
import { _ as _102 } from "./chunks/LpDataList-
|
|
189
|
-
import { _ as _103 } from "./chunks/LpEditable-
|
|
190
|
-
import { _ as _104 } from "./chunks/LpTruncate-
|
|
191
|
-
import { _ as _105 } from "./chunks/LpCodeDisplay-
|
|
186
|
+
import { _ as _100 } from "./chunks/LpCopyButton-Cw-lF7Q3.js";
|
|
187
|
+
import { _ as _101 } from "./chunks/LpSecretField-osKPNdNT.js";
|
|
188
|
+
import { _ as _102 } from "./chunks/LpDataList-CcAA-rD9.js";
|
|
189
|
+
import { _ as _103 } from "./chunks/LpEditable-CSuJIPbG.js";
|
|
190
|
+
import { _ as _104 } from "./chunks/LpTruncate-qgKA-3K3.js";
|
|
191
|
+
import { _ as _105 } from "./chunks/LpCodeDisplay-BCghfBFC.js";
|
|
192
192
|
import { formatRemaining, groupCode, middleTruncate, normalizeCode } from "./components/fieldText.js";
|
|
193
193
|
import { _ as _106 } from "./chunks/LpHoverCard-spGxyw7T.js";
|
|
194
194
|
import { _ as _107 } from "./chunks/LpIdenticon-BzdC_qz9.js";
|
|
@@ -200,7 +200,7 @@ import { pseudoLocalize } from "./composables/pseudoLocale.js";
|
|
|
200
200
|
import { _ as _110 } from "./chunks/LpTextReveal-CtAnOUkp.js";
|
|
201
201
|
import { _ as _111 } from "./chunks/LpShinyText-DX2ajtWq.js";
|
|
202
202
|
import { _ as _112 } from "./chunks/LpTypewriter-BCL_a6wE.js";
|
|
203
|
-
import { _ as _113 } from "./chunks/LpScramble-
|
|
203
|
+
import { _ as _113 } from "./chunks/LpScramble-DeT_D36q.js";
|
|
204
204
|
import { useScramble } from "./composables/useScramble.js";
|
|
205
205
|
import { useInView } from "./composables/useInView.js";
|
|
206
206
|
import { SCRAMBLE_GLYPHS, graphemes, planScramble, randomGlyph, scrambleFrame, seededRandom, settledCells } from "./components/scramble.js";
|
|
@@ -217,7 +217,7 @@ import { spotlightPoint, useSpotlight } from "./composables/useSpotlight.js";
|
|
|
217
217
|
import { _ as _119 } from "./chunks/LpCommandScope-CtUhJe8T.js";
|
|
218
218
|
import { createPaletteRegistry, mergePaletteCommands, usePaletteCommands, vPalette } from "./composables/usePaletteCommands.js";
|
|
219
219
|
import { u as u3 } from "./chunks/palette-Co8tSASo.js";
|
|
220
|
-
import { _ as _120 } from "./chunks/LpPaletteTheme-
|
|
220
|
+
import { _ as _120 } from "./chunks/LpPaletteTheme-CWAIjBCi.js";
|
|
221
221
|
const UI_CONFIG_VERSION = 1;
|
|
222
222
|
function serializeConfig(config) {
|
|
223
223
|
const out = {
|
package/package.json
CHANGED
|
@@ -33,6 +33,7 @@ export default { inheritAttrs: false }
|
|
|
33
33
|
*/
|
|
34
34
|
import { computed, onMounted, ref, useId, watch } from "vue"
|
|
35
35
|
import { useLabels } from "../composables/useLpConfig"
|
|
36
|
+
import { useScrollMemory } from "../composables/scrollMemory"
|
|
36
37
|
import LpBottomNav from "./LpBottomNav.vue"
|
|
37
38
|
import LpButton from "./LpButton.vue"
|
|
38
39
|
import LpIcon from "./LpIcon.vue"
|
|
@@ -59,8 +60,18 @@ const props = withDefaults(
|
|
|
59
60
|
* The current route path. Enables the built-in prefix-match active test and
|
|
60
61
|
* the derived page title without the host wiring its own `isActive`. Pass
|
|
61
62
|
* `route.path`. Ignored when a custom `isActive` is provided.
|
|
63
|
+
*
|
|
64
|
+
* A new path also places the page in the shell's scroll region: back and
|
|
65
|
+
* forward return to where it was left, a `hash` lands on that anchor
|
|
66
|
+
* (honouring its `scroll-margin-top`), anything else starts at the top.
|
|
62
67
|
*/
|
|
63
68
|
path?: string
|
|
69
|
+
/**
|
|
70
|
+
* The current route hash (`route.hash`). With `path` it lands a page on
|
|
71
|
+
* its anchor; a new hash on the same path glides there, after a dialog
|
|
72
|
+
* that started the jump has closed.
|
|
73
|
+
*/
|
|
74
|
+
hash?: string
|
|
64
75
|
/**
|
|
65
76
|
* Custom active test (router-driven nav). Overrides `path`/`modelValue`.
|
|
66
77
|
*/
|
|
@@ -177,7 +188,8 @@ const text = useLabels(
|
|
|
177
188
|
/*
|
|
178
189
|
* The page scrolls inside the shell's own region, not the window, so the
|
|
179
190
|
* router's scroll behaviour never reaches it: without this a route change from
|
|
180
|
-
* a scrolled page landed mid-way down the next one.
|
|
191
|
+
* a scrolled page landed mid-way down the next one, and back never returned.
|
|
192
|
+
* A full-bleed page owns its scrolling, so the shell leaves it alone.
|
|
181
193
|
*/
|
|
182
194
|
const scrollArea = ref<{ viewportEl: HTMLElement | null } | null>(null)
|
|
183
195
|
const bleedId = `lp-shell-bleed-${useId()}`
|
|
@@ -195,9 +207,13 @@ watch(
|
|
|
195
207
|
() => props.path,
|
|
196
208
|
() => {
|
|
197
209
|
if (drawerOpen.value) drawerOpen.value = false
|
|
198
|
-
scrollArea.value?.viewportEl?.scrollTo({ top: 0, left: 0, behavior: "instant" })
|
|
199
210
|
},
|
|
200
211
|
)
|
|
212
|
+
useScrollMemory(
|
|
213
|
+
() => (bleeding.value ? null : scrollArea.value?.viewportEl),
|
|
214
|
+
() => props.path,
|
|
215
|
+
() => props.hash,
|
|
216
|
+
)
|
|
201
217
|
|
|
202
218
|
function onSelect(item: SidebarItem) {
|
|
203
219
|
emit("select", item)
|
|
@@ -304,8 +304,10 @@ defineExpose({ resizing })
|
|
|
304
304
|
resizing ? 'overflow-hidden' : '',
|
|
305
305
|
// While the box holds a width its content has outgrown, a flex row would
|
|
306
306
|
// squeeze its children to fit (a button's keys folding into a column)
|
|
307
|
-
// instead of letting the easing edge clip them.
|
|
308
|
-
|
|
307
|
+
// instead of letting the easing edge clip them. A single child that is
|
|
308
|
+
// itself a wrapping row is laid out at the width the box is heading for,
|
|
309
|
+
// or it would break onto a second line until the tween lands.
|
|
310
|
+
resizing && axis !== 'height' ? '[&>*]:shrink-0 [&>*:only-child]:min-w-(--lp-shift-to-w)' : '',
|
|
309
311
|
resizing && anchor === 'end' ? 'justify-end' : '',
|
|
310
312
|
]"
|
|
311
313
|
>
|
|
@@ -8,11 +8,12 @@ export default { inheritAttrs: false }
|
|
|
8
8
|
<script setup lang="ts">
|
|
9
9
|
// Stat tile: dot + caps label, big mono value, optional delta/trend badge and a
|
|
10
10
|
// subtitle. A product pattern, fully token-driven — re-skins with the theme.
|
|
11
|
-
import { computed } from "vue"
|
|
11
|
+
import { computed, ref } from "vue"
|
|
12
12
|
import LpIcon from "./LpIcon.vue"
|
|
13
13
|
import LpNumberFlow from "./LpNumberFlow.vue"
|
|
14
14
|
import LpSkeleton from "./LpSkeleton.vue"
|
|
15
15
|
import LpStatus from "./LpStatus.vue"
|
|
16
|
+
import { useFitScale } from "../composables/useFitScale"
|
|
16
17
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
17
18
|
import { TONES } from "./tone"
|
|
18
19
|
|
|
@@ -124,6 +125,20 @@ const FADE = {
|
|
|
124
125
|
leaveToClass: "opacity-0",
|
|
125
126
|
} as const
|
|
126
127
|
|
|
128
|
+
/*
|
|
129
|
+
* The figure never wraps, so on a narrow tile a long one ("200 h 23 min", a
|
|
130
|
+
* word instead of a number) ran past the edge and was cut mid-letter. It now
|
|
131
|
+
* shrinks to the tile's width, down to `FIT_MIN` of its size, and only past
|
|
132
|
+
* that is it cut, with an ellipsis and the whole value on hover. The line box
|
|
133
|
+
* keeps its height, so a row of tiles stays level whichever of them shrank.
|
|
134
|
+
*/
|
|
135
|
+
const FIT_MIN = 0.6
|
|
136
|
+
const row = ref<HTMLElement | null>(null)
|
|
137
|
+
const figure = ref<HTMLElement | null>(null)
|
|
138
|
+
const fit = useFitScale(row, figure, FIT_MIN)
|
|
139
|
+
const figureStyle = computed(() => (fit.scale.value < 1 ? { fontSize: `calc(var(--text-3xl, 1.875rem) * ${fit.scale.value})`, lineHeight: "calc(var(--text-3xl, 1.875rem) * var(--text-3xl--line-height, 1.2))" } : undefined))
|
|
140
|
+
const figureTitle = computed(() => (fit.clipped.value && !props.loading ? `${props.prefix ?? ""}${props.value}${props.valueSuffix ?? ""}` : undefined))
|
|
141
|
+
|
|
127
142
|
// A stat tile spaces its label and value on a fixed gap; a dense KPI row needs that tighter.
|
|
128
143
|
const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
129
144
|
"flex flex-col gap-2",
|
|
@@ -148,10 +163,16 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
148
163
|
</div>
|
|
149
164
|
<!-- A narrow tile moves the delta under the figure rather than breaking the
|
|
150
165
|
figure itself: "2085 h" split across two lines reads as two values. -->
|
|
151
|
-
<div class="flex flex-wrap items-baseline gap-x-2">
|
|
166
|
+
<div ref="row" class="flex min-w-0 flex-wrap items-baseline gap-x-2">
|
|
152
167
|
<!-- The placeholder sits INSIDE the value's own type size, so its line box
|
|
153
168
|
is the real one: the tile cannot change height when the figure lands. -->
|
|
154
|
-
<span
|
|
169
|
+
<span
|
|
170
|
+
ref="figure"
|
|
171
|
+
class="max-w-full whitespace-nowrap font-mono text-3xl font-medium tracking-tight text-ink"
|
|
172
|
+
:class="fit.clipped.value ? 'inline-block overflow-hidden text-ellipsis align-bottom' : ''"
|
|
173
|
+
:style="figureStyle"
|
|
174
|
+
:title="figureTitle"
|
|
175
|
+
>
|
|
155
176
|
<!-- Each side wrapped in a plain element: LpNumberFlow renders more
|
|
156
177
|
than one root node, which a Transition cannot fade. -->
|
|
157
178
|
<Transition v-bind="FADE">
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { Motion } from "motion-v"
|
|
13
13
|
import { computed, onBeforeUnmount, onMounted, ref, useId, watch } from "vue"
|
|
14
14
|
import { useLabels } from "../composables/useLpConfig"
|
|
15
|
-
import { atScrollEnd, scrollParent } from "../composables/scroll"
|
|
15
|
+
import { atScrollEnd, scrollMarginTop, scrollParent, scrollToElement } from "../composables/scroll"
|
|
16
16
|
import { usePillTransition } from "../composables/usePillTransition"
|
|
17
17
|
|
|
18
18
|
export interface TocLink {
|
|
@@ -170,7 +170,9 @@ function onClick(id: string, ev: MouseEvent) {
|
|
|
170
170
|
ev.preventDefault()
|
|
171
171
|
activeId.value = id // mark immediately so the bar jumps to the clicked item
|
|
172
172
|
suppressSpyUntilScrollEnds(el)
|
|
173
|
-
|
|
173
|
+
// Only the nearest scrolling box moves: scrollIntoView also shifted every
|
|
174
|
+
// overflow-hidden ancestor, the shell itself among them.
|
|
175
|
+
scrollToElement(el, { block: "start", behavior: "smooth", margin: scrollMarginTop(el) })
|
|
174
176
|
// Keep the router's own state: replacing it with null broke scroll
|
|
175
177
|
// restoration and back/forward bookkeeping in vue-router apps.
|
|
176
178
|
history.replaceState(history.state, "", `#${id}`)
|
|
@@ -46,6 +46,11 @@ export interface ScrollToElementOptions {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/** Scroll the nearest scroller, and only it, so that `el` is in view. */
|
|
49
|
+
/** The element's own `scroll-margin-top`, the gap it asks to keep above it when scrolled to. */
|
|
50
|
+
export function scrollMarginTop(el: Element): number {
|
|
51
|
+
return Number.parseFloat(getComputedStyle(el).scrollMarginTop) || 0
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
export function scrollToElement(
|
|
50
55
|
el: Element | null | undefined,
|
|
51
56
|
{ block = "nearest", behavior = "auto", margin = 0 }: ScrollToElementOptions = {},
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { nextTick, onBeforeUnmount, onMounted, watch } from "vue"
|
|
2
|
+
import { scrollMarginTop } from "./scroll"
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Where a page lands when the shell's own scroll region changes page. The
|
|
6
|
+
* region is not the window, so a router's scrollBehavior never reaches it, and
|
|
7
|
+
* the shell has to answer the questions a browser answers for a plain site:
|
|
8
|
+
*
|
|
9
|
+
* - back and forward return to where the page was left;
|
|
10
|
+
* - an address with a hash lands on that anchor, and stays on it while the
|
|
11
|
+
* page is still growing (a lazily loaded body, images), until the reader
|
|
12
|
+
* scrolls or a moment has passed;
|
|
13
|
+
* - a new hash on the same page glides there, once a dialog that started the
|
|
14
|
+
* jump (a palette, a menu) has let go of the page;
|
|
15
|
+
* - anything else starts at the top.
|
|
16
|
+
*
|
|
17
|
+
* The router is not needed: what changed is read from the shell's `path` and
|
|
18
|
+
* `hash` props, history position from `popstate`, and positions are keyed by
|
|
19
|
+
* the address the browser shows.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const SETTLE_MS = 1500
|
|
23
|
+
const DIALOG_WAIT_MS = 2000
|
|
24
|
+
const SETTLE_STOP = ["wheel", "touchstart", "keydown", "pointerdown"] as const
|
|
25
|
+
|
|
26
|
+
const positions = new Map<string, number>()
|
|
27
|
+
|
|
28
|
+
function addressKey(): string {
|
|
29
|
+
return `${location.pathname}${location.search}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function useScrollMemory(
|
|
33
|
+
viewport: () => HTMLElement | null | undefined,
|
|
34
|
+
path: () => string | undefined,
|
|
35
|
+
hash: () => string | undefined,
|
|
36
|
+
): void {
|
|
37
|
+
if (typeof window === "undefined") return
|
|
38
|
+
let current = addressKey()
|
|
39
|
+
let shown = path()
|
|
40
|
+
let travelled = false
|
|
41
|
+
let stopHold: (() => void) | undefined
|
|
42
|
+
let pending = 0
|
|
43
|
+
|
|
44
|
+
const onPop = () => {
|
|
45
|
+
travelled = true
|
|
46
|
+
}
|
|
47
|
+
window.addEventListener("popstate", onPop)
|
|
48
|
+
|
|
49
|
+
function anchor(value: string | undefined): HTMLElement | null {
|
|
50
|
+
if (!value || value === "#") return null
|
|
51
|
+
const id = decodeURIComponent(value.replace(/^#/, ""))
|
|
52
|
+
return document.getElementById(id)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function reach(value: string | undefined, behavior: ScrollBehavior): boolean {
|
|
56
|
+
const view = viewport()
|
|
57
|
+
const target = anchor(value)
|
|
58
|
+
if (!view || !target || !view.contains(target)) return false
|
|
59
|
+
const top = target.getBoundingClientRect().top - view.getBoundingClientRect().top + view.scrollTop - scrollMarginTop(target)
|
|
60
|
+
view.scrollTo({ top: Math.max(0, top), behavior })
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Re-applies a landing while the page below it keeps changing size.
|
|
65
|
+
function hold(land: () => void) {
|
|
66
|
+
stopHold?.()
|
|
67
|
+
const view = viewport()
|
|
68
|
+
const content = view?.firstElementChild
|
|
69
|
+
land()
|
|
70
|
+
if (!content) return
|
|
71
|
+
const watcher = new ResizeObserver(land)
|
|
72
|
+
const timer = window.setTimeout(() => stop(), SETTLE_MS)
|
|
73
|
+
const stop = () => {
|
|
74
|
+
watcher.disconnect()
|
|
75
|
+
window.clearTimeout(timer)
|
|
76
|
+
for (const name of SETTLE_STOP) window.removeEventListener(name, stop, true)
|
|
77
|
+
if (stopHold === stop) stopHold = undefined
|
|
78
|
+
}
|
|
79
|
+
for (const name of SETTLE_STOP) window.addEventListener(name, stop, { capture: true, passive: true })
|
|
80
|
+
watcher.observe(content)
|
|
81
|
+
stopHold = stop
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function arrive() {
|
|
85
|
+
const back = travelled
|
|
86
|
+
travelled = false
|
|
87
|
+
current = addressKey()
|
|
88
|
+
shown = path()
|
|
89
|
+
const view = viewport()
|
|
90
|
+
if (!view) return
|
|
91
|
+
const saved = positions.get(current)
|
|
92
|
+
if (back && saved !== undefined) {
|
|
93
|
+
hold(() => view.scrollTo({ top: saved, behavior: "instant" }))
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
if (hash()) {
|
|
97
|
+
hold(() => {
|
|
98
|
+
if (!reach(hash(), "instant")) view.scrollTo({ top: 0, behavior: "instant" })
|
|
99
|
+
})
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
stopHold?.()
|
|
103
|
+
view.scrollTo({ top: 0, left: 0, behavior: "instant" })
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function afterDialogs(run: () => void) {
|
|
107
|
+
const since = performance.now()
|
|
108
|
+
const mine = ++pending
|
|
109
|
+
const tick = () => {
|
|
110
|
+
if (mine !== pending) return
|
|
111
|
+
const locked = document.querySelector('[role="dialog"]') || getComputedStyle(document.body).overflow === "hidden"
|
|
112
|
+
if (locked && performance.now() - since < DIALOG_WAIT_MS) requestAnimationFrame(tick)
|
|
113
|
+
else run()
|
|
114
|
+
}
|
|
115
|
+
requestAnimationFrame(tick)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
watch(
|
|
119
|
+
path,
|
|
120
|
+
() => {
|
|
121
|
+
const view = viewport()
|
|
122
|
+
if (view) positions.set(current, view.scrollTop)
|
|
123
|
+
void nextTick(() => requestAnimationFrame(arrive))
|
|
124
|
+
},
|
|
125
|
+
{ flush: "pre" },
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
watch(hash, (next, previous) => {
|
|
129
|
+
if (next === previous) return
|
|
130
|
+
if (path() !== shown) return
|
|
131
|
+
afterDialogs(() => {
|
|
132
|
+
travelled = false
|
|
133
|
+
if (!reach(next, "smooth")) viewport()?.scrollTo({ top: 0, behavior: "smooth" })
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
onMounted(() => {
|
|
138
|
+
if (hash()) requestAnimationFrame(() => hold(() => void reach(hash(), "instant")))
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
onBeforeUnmount(() => {
|
|
142
|
+
stopHold?.()
|
|
143
|
+
window.removeEventListener("popstate", onPop)
|
|
144
|
+
})
|
|
145
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { onBeforeUnmount, onMounted, ref, watch, type Ref } from "vue"
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* How much a line that must not wrap has to shrink to fit its box. Text width
|
|
5
|
+
* grows in step with the font size, so the width the content would have at
|
|
6
|
+
* full size is its current width over the current scale, and one measurement
|
|
7
|
+
* gives the answer. The scale stops at `min`: past it the text would be too
|
|
8
|
+
* small to read, and `clipped` says the caller should cut it instead.
|
|
9
|
+
*/
|
|
10
|
+
export function useFitScale(
|
|
11
|
+
box: Ref<HTMLElement | null | undefined>,
|
|
12
|
+
content: Ref<HTMLElement | null | undefined>,
|
|
13
|
+
min = 0.6,
|
|
14
|
+
) {
|
|
15
|
+
const scale = ref(1)
|
|
16
|
+
const clipped = ref(false)
|
|
17
|
+
let observer: ResizeObserver | undefined
|
|
18
|
+
|
|
19
|
+
function measure() {
|
|
20
|
+
const room = box.value?.clientWidth ?? 0
|
|
21
|
+
const width = content.value?.scrollWidth ?? 0
|
|
22
|
+
if (!room || !width) return
|
|
23
|
+
const natural = width / scale.value
|
|
24
|
+
const next = Math.max(min, Math.min(1, Math.floor((room / natural) * 100) / 100))
|
|
25
|
+
if (next !== scale.value) scale.value = next
|
|
26
|
+
clipped.value = natural * next > room + 0.5
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function observe() {
|
|
30
|
+
observer?.disconnect()
|
|
31
|
+
if (typeof ResizeObserver === "undefined") return
|
|
32
|
+
observer = new ResizeObserver(measure)
|
|
33
|
+
if (box.value) observer.observe(box.value)
|
|
34
|
+
if (content.value) observer.observe(content.value)
|
|
35
|
+
measure()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onMounted(observe)
|
|
39
|
+
watch([box, content], observe, { flush: "post" })
|
|
40
|
+
onBeforeUnmount(() => observer?.disconnect())
|
|
41
|
+
|
|
42
|
+
return { scale, clipped }
|
|
43
|
+
}
|
|
@@ -62,6 +62,9 @@ export interface UseShift {
|
|
|
62
62
|
retune: () => void
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/** Set on the box while it eases its width: where that width will land. */
|
|
66
|
+
export const TARGET_WIDTH = "--lp-shift-to-w"
|
|
67
|
+
|
|
65
68
|
/** Kept in step with the `duration-fast` token the transition utilities use. */
|
|
66
69
|
const TWEEN_MS = 160
|
|
67
70
|
|
|
@@ -190,6 +193,8 @@ export function useShift(
|
|
|
190
193
|
if (wantsWidth()) node.style.width = ""
|
|
191
194
|
const toHeight = wantsHeight() ? node.offsetHeight : 0
|
|
192
195
|
const toWidth = wantsWidth() ? node.offsetWidth : 0
|
|
196
|
+
// offsetWidth is rounded, and content that needs 406.4px wraps at 406.
|
|
197
|
+
const exactWidth = wantsWidth() ? Math.ceil(node.getBoundingClientRect().width) : 0
|
|
193
198
|
restoreScroll(tops)
|
|
194
199
|
lastHeight = toHeight
|
|
195
200
|
lastWidth = toWidth
|
|
@@ -215,6 +220,10 @@ export function useShift(
|
|
|
215
220
|
void node.offsetHeight
|
|
216
221
|
if (movesHeight) node.style.height = `${toHeight}px`
|
|
217
222
|
if (movesWidth) node.style.width = `${toWidth}px`
|
|
223
|
+
// The width the box is heading for, for content that would otherwise lay
|
|
224
|
+
// itself out at every in-between width: a wrapping row inside a widening
|
|
225
|
+
// box broke onto a second line for the length of the tween.
|
|
226
|
+
if (movesWidth) node.style.setProperty(TARGET_WIDTH, `${exactWidth}px`)
|
|
218
227
|
restoreScroll(tops)
|
|
219
228
|
|
|
220
229
|
inFlight = true
|
|
@@ -233,6 +242,7 @@ export function useShift(
|
|
|
233
242
|
// clearing it let the box spread to the window's edges.
|
|
234
243
|
if (wantsHeight()) node.style.height = ""
|
|
235
244
|
if (wantsWidth()) node.style.width = ""
|
|
245
|
+
node.style.removeProperty(TARGET_WIDTH)
|
|
236
246
|
// Re-read rather than trusting the target: the layout around may have
|
|
237
247
|
// moved meanwhile, and the next tween has to start from where it sits.
|
|
238
248
|
lastHeight = node.offsetHeight
|