Migrates to svelte 5
This commit is contained in:
@@ -6,12 +6,30 @@
|
||||
The progress bar will show during navigation if loading takes more than `displayThresholdMs`
|
||||
and will hide when navigation is complete.
|
||||
-->
|
||||
<svelte:options runes={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import { afterNavigate, beforeNavigate } from "$app/navigation";
|
||||
import { beforeNavigate } from "$app/navigation";
|
||||
|
||||
// This component is a modified version of the component from the following repo:
|
||||
// https://github.com/saibotsivad/svelte-progress-bar
|
||||
|
||||
let {
|
||||
id = undefined,
|
||||
viewTransitionName = "sveltekit-progress-bar",
|
||||
busy = $bindable(false),
|
||||
color = "currentColor",
|
||||
class: textColorClass = "",
|
||||
zIndex = 1,
|
||||
minimum: defaultMinimum = 0.08,
|
||||
maximum = 0.994,
|
||||
settleTime: defaultSettleTime = 700,
|
||||
intervalTime = 700,
|
||||
stepSizes = [0, 0.005, 0.01, 0.02],
|
||||
displayThresholdMs = 150,
|
||||
noNavigationProgress = false,
|
||||
}: Props = $props();
|
||||
|
||||
// Towards the end of the progress bar animation, we want to shorten the increment
|
||||
// step size, to give it the appearance of slowing down. This indicates to the user
|
||||
// that progress is still happening, but not as fast as they might like.
|
||||
@@ -24,83 +42,111 @@
|
||||
};
|
||||
|
||||
// Internal private state.
|
||||
let running: boolean = false;
|
||||
let updater: ReturnType<typeof setInterval> | null = null;
|
||||
let completed = false;
|
||||
let width: number = 0;
|
||||
let running = $state(false);
|
||||
let updater = $state<ReturnType<typeof setInterval> | null>(null);
|
||||
let completed = $state(false);
|
||||
let width = $state(0);
|
||||
|
||||
/** If set, an ID for the progress bar on the HTML page.
|
||||
* This ID must be unique on the page to avoid conflicts.
|
||||
*
|
||||
* Might be used with another element to signal to assistive technologies that
|
||||
* progress is ongoing.
|
||||
*
|
||||
* @example
|
||||
* <ProgressBar id="my-progress-bar" bind:busy />
|
||||
* <div aria-busy={busy} aria-describedby="my-progress-bar">
|
||||
* A div that is currently loading...
|
||||
* </div>
|
||||
*/
|
||||
export let id: string | undefined = undefined;
|
||||
/** Will be set to true when the progress bar is running. */
|
||||
export let busy: boolean = false;
|
||||
$: running = busy;
|
||||
/**
|
||||
* The CSS color to use to style the progress bar.
|
||||
*
|
||||
* If you're using Tailwind or Windi CSS, leave this to the default
|
||||
* and set the `class` attribute to a `text-` class instead.
|
||||
*/
|
||||
export let color: string = "currentColor";
|
||||
/**
|
||||
* A Tailwind/Windi `text-` class to use to color the Progress Bar.
|
||||
*
|
||||
* This prop will be ignored if the `color` prop is set to something other than `currentColor`.
|
||||
*
|
||||
* **WARNING**: Do not set this prop with something other than a `text-` class,
|
||||
* as it could interfere with the styling of the Progress Bar.
|
||||
*
|
||||
* @example text-green-500
|
||||
*/
|
||||
let textColorClass: `text-${string}` | "" = "";
|
||||
export { textColorClass as class };
|
||||
// Update the busy prop when the internal `running` variable changes.
|
||||
$effect.pre(() => {
|
||||
busy = running;
|
||||
});
|
||||
|
||||
/**
|
||||
* The `z-index` CSS property value to use for the progress bar.
|
||||
* Be aware that the glowing effect on the bar will use this `zIndex` + 1.
|
||||
*/
|
||||
export let zIndex: number = 1;
|
||||
interface Props {
|
||||
/** If set, an ID for the progress bar on the HTML page.
|
||||
* This ID must be unique on the page to avoid conflicts.
|
||||
*
|
||||
* Might be used with another element to signal to assistive technologies that
|
||||
* progress is ongoing.
|
||||
*
|
||||
* @example
|
||||
* <ProgressBar id="my-progress-bar" bind:busy />
|
||||
* <div aria-busy={busy} aria-describedby="my-progress-bar">
|
||||
* A div that is currently loading...
|
||||
* </div>
|
||||
*/
|
||||
id?: string | undefined;
|
||||
/**
|
||||
* The name of the CSS view transition to use for the progress bar.
|
||||
* Sets the `view-transition-name` CSS property on the progress bar and leader elements.
|
||||
*
|
||||
* @default "sveltekit-progress-bar"
|
||||
* @see https://developer.chrome.com/docs/web-platform/view-transitions/
|
||||
* @see https://svelte.dev/blog/view-transitions
|
||||
*/
|
||||
viewTransitionName?: string;
|
||||
/** Will be set to true when the progress bar is running. */
|
||||
busy?: boolean;
|
||||
/**
|
||||
* The CSS color to use to style the progress bar.
|
||||
*
|
||||
* If you're using Tailwind or Windi CSS, leave this to the default
|
||||
* and set the `class` attribute to a `text-` class instead.
|
||||
*/
|
||||
color?: string;
|
||||
/**
|
||||
* A Tailwind/Windi `text-` class to use to color the Progress Bar.
|
||||
*
|
||||
* This prop will be ignored if the `color` prop is set to something other than `currentColor`.
|
||||
*
|
||||
* **WARNING**: Do not set this prop with something other than a `text-` class,
|
||||
* as it could interfere with the styling of the Progress Bar.
|
||||
*
|
||||
* @example text-green-500
|
||||
*/
|
||||
class?: `text-${string}` | "";
|
||||
|
||||
// These are defaults that you shouldn't need to change, but are exposed here in case you do.
|
||||
/**
|
||||
* The starting percent width use when the bar starts.
|
||||
* Starting at 0 doesn't usually look very good.
|
||||
* @default 0.08
|
||||
*/
|
||||
let defaultMinimum = 0.08;
|
||||
export { defaultMinimum as minimum };
|
||||
/**
|
||||
* The maximum percent width value to use when the bar is at the end but not marked as complete.
|
||||
* Letting the bar stay at 100% width for a while doesn't usually look very good either.
|
||||
* @default 0.994
|
||||
*/
|
||||
export let maximum = 0.994;
|
||||
/**
|
||||
* Milliseconds to wait after the complete method is called to hide the progress bar.
|
||||
* Letting it sit at 100% width for a very short time makes it feel more fluid.
|
||||
* @default 700
|
||||
*/
|
||||
let defaultSettleTime = 700;
|
||||
export { defaultSettleTime as settleTime };
|
||||
/**
|
||||
* Milliseconds to wait between incrementing bar width when using
|
||||
* the `start` (auto-increment) method.
|
||||
* @default 700
|
||||
*/
|
||||
export let intervalTime = 700;
|
||||
export let stepSizes = [0, 0.005, 0.01, 0.02];
|
||||
/**
|
||||
* The `z-index` CSS property value to use for the progress bar.
|
||||
* Be aware that the glowing effect on the bar will use this `zIndex` + 1.
|
||||
*/
|
||||
zIndex?: number;
|
||||
|
||||
// These are defaults that you shouldn't need to change, but are exposed here in case you do.
|
||||
/**
|
||||
* The starting percent width use when the bar starts.
|
||||
* Starting at 0 doesn't usually look very good.
|
||||
* @default 0.08
|
||||
*/
|
||||
minimum?: number;
|
||||
|
||||
/**
|
||||
* The maximum percent width value to use when the bar is at the end but not marked as complete.
|
||||
* Letting the bar stay at 100% width for a while doesn't usually look very good either.
|
||||
* @default 0.994
|
||||
*/
|
||||
maximum?: number;
|
||||
/**
|
||||
* Milliseconds to wait after the complete method is called to hide the progress bar.
|
||||
* Letting it sit at 100% width for a very short time makes it feel more fluid.
|
||||
* @default 700
|
||||
*/
|
||||
settleTime?: number;
|
||||
|
||||
/**
|
||||
* Milliseconds to wait between incrementing bar width when using
|
||||
* the `start` (auto-increment) method.
|
||||
* @default 700
|
||||
*/
|
||||
intervalTime?: number;
|
||||
|
||||
/** Reset the progress bar back to the beginning, leaving it in a running state. */
|
||||
stepSizes?: any;
|
||||
|
||||
/** When navigating, this is the threshold duration in milliseconds
|
||||
* that the progress bar will wait before showing.
|
||||
*
|
||||
* This means that if the navigation takes less than this amount of time,
|
||||
* the progress bar will not be shown. This is to prevent the progress bar
|
||||
* from flashing in and out on the screen.
|
||||
*
|
||||
* @default 150 ms
|
||||
*/
|
||||
displayThresholdMs?: number;
|
||||
/** Set to `true` to disable the showing of the progress bar on navigation. */
|
||||
noNavigationProgress?: boolean;
|
||||
}
|
||||
|
||||
/** Reset the progress bar back to the beginning, leaving it in a running state. */
|
||||
export const reset = (minimum = defaultMinimum) => {
|
||||
width = minimum;
|
||||
running = true;
|
||||
@@ -186,32 +232,21 @@
|
||||
};
|
||||
};
|
||||
|
||||
let barStyle: string;
|
||||
$: barStyle =
|
||||
const barStyle = $derived(
|
||||
(color ? `background-color: ${color};` : "") +
|
||||
(width && width * 100 ? `width: ${width * 100}%;` : "") +
|
||||
`z-index: ${zIndex};`;
|
||||
(width && width * 100 ? `width: ${width * 100}%;` : "") +
|
||||
`z-index: ${zIndex};` +
|
||||
`view-transition-name: ${viewTransitionName}-bar;`,
|
||||
);
|
||||
// the box shadow of the leader bar uses `color` to set its shadow color
|
||||
let leaderColorStyle: string;
|
||||
$: leaderColorStyle =
|
||||
const leaderColorStyle = $derived(
|
||||
(color ? `background-color: ${color}; color: ${color};` : "") +
|
||||
`z-index: ${zIndex + 1};`;
|
||||
|
||||
/** When navigating, this is the threshold duration in milliseconds
|
||||
* that the progress bar will wait before showing.
|
||||
*
|
||||
* This means that if the navigation takes less than this amount of time,
|
||||
* the progress bar will not be shown. This is to prevent the progress bar
|
||||
* from flashing in and out on the screen.
|
||||
*
|
||||
* @default 150 ms
|
||||
*/
|
||||
export let displayThresholdMs = 150;
|
||||
|
||||
/** Set to `true` to disable the showing of the progress bar on navigation. */
|
||||
export let noNavigationProgress = false;
|
||||
`z-index: ${zIndex + 1};` +
|
||||
`view-transition-name: ${viewTransitionName}-leader;`,
|
||||
);
|
||||
|
||||
let progressBarStartTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
beforeNavigate((nav) => {
|
||||
if (progressBarStartTimeout) {
|
||||
clearTimeout(progressBarStartTimeout);
|
||||
@@ -229,15 +264,15 @@
|
||||
displayThresholdMs,
|
||||
);
|
||||
} else start();
|
||||
}
|
||||
});
|
||||
|
||||
afterNavigate(() => {
|
||||
if (progressBarStartTimeout) {
|
||||
clearTimeout(progressBarStartTimeout);
|
||||
progressBarStartTimeout = null;
|
||||
nav.complete.catch().finally(() => {
|
||||
if (progressBarStartTimeout) {
|
||||
clearTimeout(progressBarStartTimeout);
|
||||
progressBarStartTimeout = null;
|
||||
}
|
||||
complete();
|
||||
});
|
||||
}
|
||||
complete();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -254,7 +289,7 @@
|
||||
style={barStyle}
|
||||
>
|
||||
{#if running}
|
||||
<div class="svelte-progress-bar-leader" style={leaderColorStyle} />
|
||||
<div class="svelte-progress-bar-leader" style={leaderColorStyle}></div>
|
||||
{/if}
|
||||
</output>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user