@leavepulse/ui 0.95.1 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{LpTable-BJjNEvgJ.css → LpTable-DSTuJxRU.css} +37 -37
- package/dist/chunks/{DropzoneLinkField-Ckuh8zFC.js → DropzoneLinkField-D1gkwYOl.js} +2 -2
- package/dist/chunks/{FieldWrapper-CVTPnpoG.js → FieldWrapper-BaYhNT7r.js} +1 -1
- package/dist/chunks/{LpActionBar-43WHmTsM.js → LpActionBar-DuwBawji.js} +2 -2
- package/dist/chunks/{LpAddressInput-C5VIgRp0.js → LpAddressInput-D596mz6j.js} +6 -6
- package/dist/chunks/{LpAlert-Q0h7Gucu.js → LpAlert-CdzeGn72.js} +2 -2
- package/dist/chunks/{LpAppShell-C4b3ySa_.js → LpAppShell-iShI1QtP.js} +4 -4
- package/dist/chunks/{LpAutocomplete-YPxAPHEo.js → LpAutocomplete-C79ZI9mX.js} +1 -1
- package/dist/chunks/{LpBadge-Bh5roBr_.js → LpBadge-D_TB_Iuv.js} +1 -1
- package/dist/chunks/{LpBottomNav-9AqvZlRW.js → LpBottomNav-SMIiebhK.js} +1 -1
- package/dist/chunks/{LpBreadcrumbs-Zv1fn9e_.js → LpBreadcrumbs-CF-qfujt.js} +1 -1
- package/dist/chunks/{LpButton-BvVoF-PO.js → LpButton-78PtrlBs.js} +1 -1
- package/dist/chunks/{LpCard-xXBqLVGo.js → LpCard-C7LmpifA.js} +1 -1
- package/dist/chunks/{LpCheckbox-C9VnPIQf.js → LpCheckbox-BnQcOHbs.js} +2 -2
- package/dist/chunks/{LpCodeBlock-DTU40x8P.js → LpCodeBlock-DVPqlRQx.js} +1 -1
- package/dist/chunks/{LpCodeDisplay-F2hjLb0X.js → LpCodeDisplay-38kLrgH9.js} +4 -4
- package/dist/chunks/{LpColorPicker-KGMG8QEh.js → LpColorPicker-DuuaWRsT.js} +1 -1
- package/dist/chunks/{LpConfirmDialog-DrHcIxRn.js → LpConfirmDialog-CvC-Uxk5.js} +1 -1
- package/dist/chunks/{LpConfirmHost-D0Cd8FA_.js → LpConfirmHost-BAuEU5wp.js} +1 -1
- package/dist/chunks/{LpCopyButton-CiqUS4SX.js → LpCopyButton-CBk_uxSq.js} +1 -1
- package/dist/chunks/{LpCountdown-DVl7vXI1.js → LpCountdown-Db-uzYL_.js} +1 -1
- package/dist/chunks/{LpDataList-Cit9fOSp.js → LpDataList-DReLDsdm.js} +1 -1
- package/dist/chunks/{LpDatePicker-Dlyvgsan.js → LpDatePicker-DawYC7Pg.js} +2 -2
- package/dist/chunks/{LpDateRangePicker-DRBB8z6t.js → LpDateRangePicker-DNTj2SDa.js} +1 -1
- package/dist/chunks/{LpEditable-DfRUAGkA.js → LpEditable-CtulE7dP.js} +2 -2
- package/dist/chunks/{LpFileTree-gVjF_b6r.js → LpFileTree-CLpVoqzu.js} +3 -3
- package/dist/chunks/{LpFileTreeNode-CC48DbT5.js → LpFileTreeNode-DkjdwSni.js} +3 -3
- package/dist/chunks/{LpFormField-jbM7K1Hg.js → LpFormField-mIq_9UWb.js} +1 -1
- package/dist/chunks/{LpHintLayer-nuMqfzvy.js → LpHintLayer-BG4cgJNr.js} +2 -2
- package/dist/chunks/{LpHints-ByAd3a76.js → LpHints-DuisuI5J.js} +3 -3
- package/dist/chunks/{LpInfraNode-tD5x5YOy.js → LpInfraNode-CFSOir_N.js} +2 -2
- package/dist/chunks/{LpInput-DGMpxrcg.js → LpInput-BOI2XFq_.js} +1 -1
- package/dist/chunks/{LpInspector-DSL1lINx.js → LpInspector-f93FmxCP.js} +1 -1
- package/dist/chunks/{LpLightbox--EwvQGe-.js → LpLightbox-DAxV5Yvn.js} +3 -3
- package/dist/chunks/{LpLoader-Bf1yZwaU.js → LpLoader-2tO499NO.js} +1 -1
- package/dist/chunks/{LpLogInspector-BhJTJIst.js → LpLogInspector-DPZWN5Ev.js} +1 -1
- package/dist/chunks/{LpLogViewer-DSq9e8mT.js → LpLogViewer-Gftt0yf5.js} +4 -4
- package/dist/chunks/{LpMapPicker-V0Lybi10.js → LpMapPicker-DACiiuSY.js} +1 -1
- package/dist/chunks/{LpMediaGallery-DlYJf3DS.js → LpMediaGallery-BqEdUKhA.js} +1 -1
- package/dist/chunks/{LpModalNav-Cj02cfhL.js → LpModalNav-Ga6u3bbf.js} +2 -2
- package/dist/chunks/{LpNotificationBell-DNGijtmW.js → LpNotificationBell-CbBOWxEa.js} +3 -3
- package/dist/chunks/{LpNotificationFeed-BoovbtfL.js → LpNotificationFeed-DDWNr7vY.js} +2 -2
- package/dist/chunks/{LpNumberField-C0LSu-tl.js → LpNumberField-BtVJ0pT4.js} +1 -1
- package/dist/chunks/{LpOtpInput-C14XagVB.js → LpOtpInput-DTX1w62e.js} +1 -1
- package/dist/chunks/{LpPaletteTheme-_FwkJO2o.js → LpPaletteTheme-DJT8_7yH.js} +3 -3
- package/dist/chunks/{LpPasswordInput-BBDz2zyU.js → LpPasswordInput-B716mvni.js} +2 -2
- package/dist/chunks/{LpPhoneInput-BdglZsGH.js → LpPhoneInput-VtPE_Ipa.js} +1 -1
- package/dist/chunks/{LpPie-CtC4XdhC.js → LpPie-Ffg1F7As.js} +2 -2
- package/dist/chunks/{LpPipeline-aCALaUY8.js → LpPipeline-CyCgP9_y.js} +2 -2
- package/dist/chunks/{LpRadioGroup-Cr_fmrBY.js → LpRadioGroup-VJUwOA08.js} +1 -1
- package/dist/chunks/{LpRangeSlider-DbaITHtC.js → LpRangeSlider-CsAeqpK4.js} +1 -1
- package/dist/chunks/{LpRepeater-C0rns2xW.js → LpRepeater-BRuVEF2M.js} +3 -3
- package/dist/chunks/{LpScramble-DsE77iVp.js → LpScramble-DdP1aF0m.js} +1 -1
- package/dist/chunks/{LpSecretField-C9vwMFQ6.js → LpSecretField-B04cdcB8.js} +6 -6
- package/dist/chunks/{LpSegmented-DzFYP0ZF.js → LpSegmented-Dws26WdN.js} +1 -1
- package/dist/chunks/{LpSelect-Dffg5r4I.js → LpSelect-Crzu6LUQ.js} +1 -1
- package/dist/chunks/{LpShift-DAgS_d2x.js → LpShift-ta3RpuH8.js} +30 -13
- package/dist/chunks/{LpSidebar-DPri9uyz.js → LpSidebar-WQuItmR1.js} +2 -2
- package/dist/chunks/{LpSidebarNav-CV1rU6La.js → LpSidebarNav-C1glQiiz.js} +2 -2
- package/dist/chunks/{LpSidebarRow-C5jXpcRL.js → LpSidebarRow-D9WaZsrT.js} +1 -1
- package/dist/chunks/{LpSlider-DUd4gXnw.js → LpSlider-Cdfz-6mn.js} +1 -1
- package/dist/chunks/{LpStat-SyVb5JXm.js → LpStat-QhKwBDs9.js} +1 -1
- package/dist/chunks/{LpStatus-C6GqSHJj.js → LpStatus-CbPi3oxy.js} +2 -2
- package/dist/chunks/{LpStepMark-CPGVj1XG.js → LpStepMark-CUawCMEq.js} +1 -1
- package/dist/chunks/{LpStepper-DBNRA6Q2.js → LpStepper-Beyt0G17.js} +1 -1
- package/dist/chunks/{LpSwap-M7nFeW3C.js → LpSwap-qCOwgde2.js} +1 -1
- package/dist/chunks/{LpSwitch-D-mcaA6C.js → LpSwitch-CNOw_N5u.js} +2 -2
- package/dist/chunks/{LpTabFace-uoZgD_SN.js → LpTabFace-0ZdqEZMe.js} +1 -1
- package/dist/chunks/{LpTableFilter-CILHffC1.js → LpTableFilter-C6Wt5mUr.js} +3 -3
- package/dist/chunks/{LpTagsInput-DD8-xe3F.js → LpTagsInput-CJCyr2p3.js} +2 -2
- package/dist/chunks/{LpTextarea-CQg-dVxN.js → LpTextarea-B0U99u5R.js} +1 -1
- package/dist/chunks/{LpThemeStudio-yiEdFJQL.js → LpThemeStudio-B6ZDjqiv.js} +4 -4
- package/dist/chunks/{LpThemeSwitcher-DKkCFaFk.js → LpThemeSwitcher-FJLcLfjq.js} +2 -2
- package/dist/chunks/{LpTimeField-Dio7Tj9A.js → LpTimeField-BHM_MEPZ.js} +1 -1
- package/dist/chunks/{LpToaster-C7hHkGOA.js → LpToaster-DjkgZepp.js} +1 -1
- package/dist/chunks/{LpTopologyCanvas-B1YFfMaq.js → LpTopologyCanvas-DKn0Xcz4.js} +4 -4
- package/dist/chunks/{LpTour-BGUKUxSZ.js → LpTour-iZNl_vdy.js} +1 -1
- package/dist/chunks/{LpTruncate-DEHWL1OA.js → LpTruncate-BCbRf7G5.js} +1 -1
- package/dist/chunks/{LpUptimeBar-CXgzU5ym.js → LpUptimeBar-CDctaMWR.js} +2 -2
- package/dist/chunks/{LpVideoCompress-CvxNdyjp.js → LpVideoCompress-Cg0g2-S0.js} +2 -2
- package/dist/chunks/{LpVideoPlayer-FMuxTAU8.js → LpVideoPlayer-B624umtt.js} +3 -3
- package/dist/chunks/{LpWorkspaceSwitcher-CrUVSI7x.js → LpWorkspaceSwitcher-CyD9tXvM.js} +2 -2
- package/dist/chunks/{RevealToggle-D9Vs88kM.js → RevealToggle-O2lhG5Be.js} +1 -1
- package/dist/chunks/{TourCard-yrLqv4Oz.js → TourCard-CCHkCcWP.js} +3 -3
- package/dist/chunks/{VideoVolume-CzL5mZPE.js → VideoVolume-wsbvgXKK.js} +2 -2
- 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.js +1 -1
- package/dist/components/LpAutocomplete.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/LpColorPicker.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/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.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/LpInspector.vue.js +1 -1
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLoader.vue.js +1 -1
- package/dist/components/LpLogInspector.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/LpNotificationFeed.vue.js +1 -1
- package/dist/components/LpNumberField.vue.js +1 -1
- package/dist/components/LpOtpInput.vue.js +1 -1
- package/dist/components/LpPaletteTheme.vue.js +1 -1
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpPhoneInput.vue.js +1 -1
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPipeline.vue.js +1 -1
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpRangeSlider.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/LpSegmented.vue.js +1 -1
- package/dist/components/LpSelect.vue.js +1 -1
- package/dist/components/LpShift.vue.d.ts +1 -3
- 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/LpSlider.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 +14 -12
- package/dist/components/LpTableFilter.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/LpTimeField.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/LpVideoCompress.vue.js +1 -1
- package/dist/components/LpVideoPlayer.vue.js +1 -1
- package/dist/components/LpVideoTrim.vue.js +3 -3
- package/dist/components/LpWorkspaceSwitcher.vue.js +1 -1
- package/dist/components/RevealToggle.vue.js +1 -1
- package/dist/components/TourCard.vue.js +1 -1
- package/dist/components/VideoVolume.vue.js +1 -1
- package/dist/composables/useAppUpdate.js +12 -1
- package/dist/index.js +74 -74
- package/package.json +1 -1
- package/src/components/LpShift.vue +52 -17
- package/src/components/LpTable.vue +13 -2
- package/src/composables/useAppUpdate.ts +16 -1
|
@@ -24,9 +24,14 @@
|
|
|
24
24
|
*
|
|
25
25
|
* The mechanism — measure the natural size, pin it in pixels, tween — lives in
|
|
26
26
|
* `useShift`, and LpModal drives its panel with the same composable.
|
|
27
|
+
*
|
|
28
|
+
* Whether a tween is holding the box (`resizing`) is read through a ref to the
|
|
29
|
+
* component (`defineExpose`), not from the slot: a slot prop is read by this
|
|
30
|
+
* component's render, which would render the whole content again at both ends
|
|
31
|
+
* of every tween. See docs/migrations/lpshift-resizing-slot.md.
|
|
27
32
|
*/
|
|
28
33
|
import { isElement, isHTMLElement, nodeWindow } from "../composables/useView"
|
|
29
|
-
import { computed, onBeforeUnmount, watch } from "vue"
|
|
34
|
+
import { computed, onBeforeUnmount, onUpdated, watch } from "vue"
|
|
30
35
|
import { prefersReducedMotion } from "../composables/easing"
|
|
31
36
|
import { useShift, type ShiftAxis } from "../composables/useShift"
|
|
32
37
|
|
|
@@ -289,6 +294,48 @@ onBeforeUnmount(() => {
|
|
|
289
294
|
clearTimeout(rememberTimer)
|
|
290
295
|
})
|
|
291
296
|
|
|
297
|
+
/*
|
|
298
|
+
* The tween's classes go onto the box from here, not from the template. A
|
|
299
|
+
* render that read `tweening` or `resizing` would run again at the start and
|
|
300
|
+
* the end of every tween, and the slot runs inside that render: the whole
|
|
301
|
+
* content re-rendered twice per resize for two classes on one element. A
|
|
302
|
+
* table's sixty rows were each rendered again, and TransitionGroup measured
|
|
303
|
+
* every one of them again, for nothing in the rows having changed.
|
|
304
|
+
*
|
|
305
|
+
* Applied after every render too: a class bound by the parent replaces the
|
|
306
|
+
* element's whole class attribute when it changes, and these are put back.
|
|
307
|
+
*/
|
|
308
|
+
const shiftClasses = computed(() => {
|
|
309
|
+
const on = [
|
|
310
|
+
tweening.value && !props.disabled
|
|
311
|
+
? `${transitionClass.value} duration-fast ease-[var(--ease-emphasized)] motion-reduce:transition-none`
|
|
312
|
+
: "",
|
|
313
|
+
resizing.value ? "overflow-hidden" : "",
|
|
314
|
+
// While the box holds a width its content has outgrown, a flex row would
|
|
315
|
+
// squeeze its children to fit (a button's keys folding into a column)
|
|
316
|
+
// instead of letting the easing edge clip them.
|
|
317
|
+
resizing.value && props.axis !== "height" ? "[&>*]:shrink-0" : "",
|
|
318
|
+
resizing.value && props.anchor === "end" ? "justify-end" : "",
|
|
319
|
+
]
|
|
320
|
+
return on.join(" ").split(" ").filter(Boolean)
|
|
321
|
+
})
|
|
322
|
+
let applied: readonly string[] = []
|
|
323
|
+
function applyShiftClasses() {
|
|
324
|
+
const box = el.value
|
|
325
|
+
if (!box) return
|
|
326
|
+
const next = shiftClasses.value
|
|
327
|
+
for (const name of applied) if (!next.includes(name)) box.classList.remove(name)
|
|
328
|
+
for (const name of next) box.classList.add(name)
|
|
329
|
+
applied = next
|
|
330
|
+
}
|
|
331
|
+
watch(shiftClasses, applyShiftClasses, { flush: "post" })
|
|
332
|
+
onUpdated(() => {
|
|
333
|
+
// The parent's class binding may have rewritten the attribute: what was
|
|
334
|
+
// applied is gone from the element, so all of it goes back on.
|
|
335
|
+
applied = []
|
|
336
|
+
applyShiftClasses()
|
|
337
|
+
})
|
|
338
|
+
|
|
292
339
|
defineExpose({ resizing })
|
|
293
340
|
</script>
|
|
294
341
|
|
|
@@ -297,21 +344,9 @@ defineExpose({ resizing })
|
|
|
297
344
|
smaller than the content it already holds, and without the clip that
|
|
298
345
|
content spills past the easing edge. Dropped once settled, so nothing
|
|
299
346
|
that legitimately overflows — a dropdown, a focus ring — is clipped at
|
|
300
|
-
rest.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
tweening && !disabled
|
|
305
|
-
? `${transitionClass} duration-fast ease-[var(--ease-emphasized)] motion-reduce:transition-none`
|
|
306
|
-
: '',
|
|
307
|
-
resizing ? 'overflow-hidden' : '',
|
|
308
|
-
// While the box holds a width its content has outgrown, a flex row would
|
|
309
|
-
// squeeze its children to fit (a button's keys folding into a column)
|
|
310
|
-
// instead of letting the easing edge clip them.
|
|
311
|
-
resizing && axis !== 'height' ? '[&>*]:shrink-0' : '',
|
|
312
|
-
resizing && anchor === 'end' ? 'justify-end' : '',
|
|
313
|
-
]"
|
|
314
|
-
>
|
|
315
|
-
<slot :resizing="resizing" />
|
|
347
|
+
rest. The classes are put on in script (`applyShiftClasses`), so a
|
|
348
|
+
tween starting or ending never renders the content again. -->
|
|
349
|
+
<div ref="el">
|
|
350
|
+
<slot />
|
|
316
351
|
</div>
|
|
317
352
|
</template>
|
|
@@ -1736,6 +1736,17 @@ const motionIds = computed(() => (headerless.value ? allEntries.value : viewEntr
|
|
|
1736
1736
|
let shownIds: readonly string[] = []
|
|
1737
1737
|
const bigSwap = computed(() => rowChanges(shownIds, motionIds.value) > ROW_MOTION_LIMIT)
|
|
1738
1738
|
let settleFlip = false
|
|
1739
|
+
/*
|
|
1740
|
+
* Whether the rows carry their own enter, leave and move transitions, read by
|
|
1741
|
+
* the templates through these two computeds and never as `animating` itself:
|
|
1742
|
+
* the motion window closing flips `animating` 600 ms after every change, and
|
|
1743
|
+
* a template reading it re-renders the whole table for it. TransitionGroup then
|
|
1744
|
+
* measures every row again (it records positions on each render), sixty forced
|
|
1745
|
+
* reads for a switch that, after a big swap, was off already. A computed whose
|
|
1746
|
+
* value does not change does not re-render anything.
|
|
1747
|
+
*/
|
|
1748
|
+
const rowMotion = computed(() => animating.value && !props.virtualRowHeight && !bigSwap.value)
|
|
1749
|
+
const cardMotion = computed(() => animating.value && !bigSwap.value)
|
|
1739
1750
|
watch(
|
|
1740
1751
|
motionIds,
|
|
1741
1752
|
(ids) => {
|
|
@@ -2131,7 +2142,7 @@ usePaletteCommands(() => {
|
|
|
2131
2142
|
<TransitionGroup
|
|
2132
2143
|
tag="tbody"
|
|
2133
2144
|
name="lp-row"
|
|
2134
|
-
:css="
|
|
2145
|
+
:css="rowMotion"
|
|
2135
2146
|
:move-class="bigSwap ? 'lp-row-still' : undefined"
|
|
2136
2147
|
:class="busy && displayRows.length ? 'opacity-60 transition-opacity' : 'transition-opacity'"
|
|
2137
2148
|
:aria-busy="busy || undefined"
|
|
@@ -2296,7 +2307,7 @@ usePaletteCommands(() => {
|
|
|
2296
2307
|
:key="activeLayout"
|
|
2297
2308
|
tag="div"
|
|
2298
2309
|
name="lp-row"
|
|
2299
|
-
:css="
|
|
2310
|
+
:css="cardMotion"
|
|
2300
2311
|
:move-class="bigSwap ? 'lp-row-still' : undefined"
|
|
2301
2312
|
v-bind="scrollAttrs"
|
|
2302
2313
|
class="min-h-0 transition-opacity"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { onScopeDispose, readonly, ref, type Ref } from "vue"
|
|
2
|
+
import { prefersReducedMotion } from "./easing"
|
|
2
3
|
|
|
3
4
|
/*
|
|
4
5
|
* A new build is out and every open tab should run it, without anyone losing
|
|
@@ -20,6 +21,10 @@ import { onScopeDispose, readonly, ref, type Ref } from "vue"
|
|
|
20
21
|
* window scroll position, and anything the app already keeps in storage, such
|
|
21
22
|
* as form drafts. After the reload `restored` is true for the app to say
|
|
22
23
|
* "updated" if it wants to.
|
|
24
|
+
*
|
|
25
|
+
* A visible reload does not blink: the page fades out before it and fades back
|
|
26
|
+
* in after it, so the swap reads as one change rather than a flash of blank.
|
|
27
|
+
* Under reduced motion, and in a hidden tab, it simply reloads.
|
|
23
28
|
*/
|
|
24
29
|
|
|
25
30
|
export interface AppUpdateOptions {
|
|
@@ -51,6 +56,8 @@ export interface AppUpdate {
|
|
|
51
56
|
const OVERLAY = '[role="dialog"], [role="alertdialog"], [role="menu"], [role="listbox"], [data-state="open"][data-side]'
|
|
52
57
|
const INPUT_EVENTS = ["pointerdown", "keydown", "wheel", "touchstart", "input"] as const
|
|
53
58
|
const CARRY_MS = 60_000
|
|
59
|
+
const FADE_OUT_MS = 220
|
|
60
|
+
const FADE_IN_MS = 320
|
|
54
61
|
|
|
55
62
|
interface Carried {
|
|
56
63
|
href: string
|
|
@@ -94,6 +101,9 @@ export function useAppUpdate(options: AppUpdateOptions): AppUpdate {
|
|
|
94
101
|
const carried = readCarried(key)
|
|
95
102
|
if (carried && carried.href === location.href && Date.now() - carried.at < CARRY_MS) {
|
|
96
103
|
restored.value = true
|
|
104
|
+
if (!prefersReducedMotion()) {
|
|
105
|
+
document.documentElement.animate([{ opacity: 0 }, { opacity: 1 }], { duration: FADE_IN_MS, easing: "cubic-bezier(0.2, 0, 0, 1)" })
|
|
106
|
+
}
|
|
97
107
|
const top = carried.top
|
|
98
108
|
const restore = () => window.scrollTo({ top, behavior: "instant" })
|
|
99
109
|
requestAnimationFrame(() => requestAnimationFrame(restore))
|
|
@@ -106,7 +116,12 @@ export function useAppUpdate(options: AppUpdateOptions): AppUpdate {
|
|
|
106
116
|
} catch {
|
|
107
117
|
// Storage off: the reload still happens, only the scroll is lost.
|
|
108
118
|
}
|
|
109
|
-
|
|
119
|
+
if (document.hidden || prefersReducedMotion()) {
|
|
120
|
+
location.reload()
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
const fade = document.documentElement.animate([{ opacity: 1 }, { opacity: 0 }], { duration: FADE_OUT_MS, easing: "ease-in", fill: "forwards" })
|
|
124
|
+
fade.finished.then(() => location.reload(), () => location.reload())
|
|
110
125
|
}
|
|
111
126
|
|
|
112
127
|
function safe(): boolean {
|