Skip to content

Upgrade remaining components to Svelte 5 syntax#962

Open
FyreByrd wants to merge 4 commits into
mainfrom
upgrade/svelte-5
Open

Upgrade remaining components to Svelte 5 syntax#962
FyreByrd wants to merge 4 commits into
mainfrom
upgrade/svelte-5

Conversation

@FyreByrd
Copy link
Copy Markdown
Collaborator

@FyreByrd FyreByrd commented May 22, 2026

Closes #819, #890

Summary by CodeRabbit

  • Refactor

    • Updated component architecture to use modern framework patterns
    • Improved asset path handling for more reliable URL resolution across deployment environments
  • Chores

    • Updated development tooling configurations

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

📝 Walkthrough

Walkthrough

This PR completes the Svelte 5 migration by updating 100+ components to use Svelte 5 runes ($props(), $derived, $effect), replacing event directive syntax with raw DOM handlers, and migrating navigation/asset path resolution from the base variable to the asset() and resolve() helpers. Changes span icon components, core UI components, route pages, and configuration.

Changes

Svelte 5 Migration: Runes, Props API, and Asset/Navigation Helpers

Layer / File(s) Summary
Icon components props migration to Svelte 5 runes
src/lib/icons/*, src/lib/icons/audio/*, src/lib/icons/image/*
All ~50+ icon components switch from export let prop declarations to $props() destructuring. size prop defaults normalize from string '24' to numeric 24. SVG rendering logic remains unchanged.
Core UI components: props, reactivity, and event handler migration
src/lib/components/Slider.svelte, src/lib/components/StackView.svelte, src/lib/components/FontList.svelte, src/lib/components/FontSelector.svelte, src/lib/components/HistoryCard.svelte, src/lib/components/ContentCarousel.svelte, src/lib/components/ContentGrid.svelte, src/lib/components/ContentHeading.svelte, src/lib/components/ContentSingle.svelte, src/lib/components/HtmlBookView.svelte, src/lib/components/AudioPlaybackSpeed.svelte, src/lib/components/PlayButton.svelte, src/lib/components/TextAppearanceSelector.svelte
Components migrate to Svelte 5 runes: props from export let to $props() destructuring, reactive statements from $: to $derived/$effect, event handlers from on:click directives to raw onclick attributes. FontList switches to two-way binding via $bindable().
Asset and navigation path helpers: base → asset() and resolve()
src/lib/navigate/index.ts, src/lib/video/index.ts, src/lib/components/ContentCarousel.svelte, src/lib/components/ContentGrid.svelte, src/lib/components/ContentHeading.svelte, src/lib/components/ContentSingle.svelte, src/lib/components/HtmlBookView.svelte, src/lib/components/IconCard.svelte, src/routes/contents/[id]/+page.svelte, src/routes/dev/icons/+page.svelte
Image, audio, video, and script asset URLs now constructed via SvelteKit's asset() helper instead of base path concatenation. Hash-based route navigation uses resolve() instead of base prefix, with updated eslint suppression comments.
Route page data refactoring: $page store → $props().data
src/routes/+page.svelte, src/routes/bookmarks/+page.svelte, src/routes/notes/+page.svelte, src/routes/text/+page.svelte, src/routes/plans/[id]/settings/+page.svelte, src/routes/lexicon/+page.svelte
All route pages remove $page store imports and instead receive typed data: PageData via component $props(). Template references update from page.data.X to data.X with optional chaining where needed.
ESLint configuration and component cleanup
eslint.config.js, src/lib/data/plansData.ts
ESLint rule svelte/no-navigation-without-base is commented out and replaced with navigation-without-resolve suppression comments. Unused base import removed from plansData. ScrolledContent.svelte component deleted.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • sillsdev/appbuilder-pwa#821: Introduces PlayButton and audio icon components for Svelte 5, which this PR refactors further with runes-based props.
  • sillsdev/appbuilder-pwa#889: Migrates annotation route pages (notes, bookmarks) to Svelte 5 $props() state handling, overlapping with the route data refactoring in this PR.
  • sillsdev/appbuilder-pwa#845: Updates src/routes/text/+page.svelte to use Svelte 5 runes and $props().data, directly aligned with this PR's route data refactoring.

Suggested reviewers

  • chrisvire
  • eomerdws

🐰 Hop skip and jump, the refactor's done,
A hundred components—now Svelte 5's the one!
Props and runes and helpers so bright,
From base to resolve, the paths shine right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Upgrade remaining components to Svelte 5 syntax' clearly and directly describes the main objective of this changeset, which comprehensively updates components to Svelte 5 syntax patterns.
Linked Issues check ✅ Passed The pull request successfully addresses issue #819 by migrating remaining components to Svelte 5 syntax, including converting props to $props(), event handlers to onclick, reactive statements to $derived/$effect, and replacing deprecated base imports with resolve/asset helpers.
Out of Scope Changes check ✅ Passed All changes are directly related to Svelte 5 migration objectives: converting component syntax, updating prop declarations, replacing event bindings, modernizing imports, and removing deprecated patterns. No extraneous or unrelated modifications are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch upgrade/svelte-5

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/components/FontSelector.svelte`:
- Around line 13-15: The modal opens with a stale selectedFont value; update
selectedFont from the currentFont store/value before showing the dialog. In the
export function showModal() (and the equivalent open/submit path around the same
modal usage), read the latest currentFont (or $currentFont) and assign it to
selectedFont immediately prior to calling modal.showModal(), ensuring the
selection reflects the currentFont when the modal opens.

In `@src/lib/components/HistoryCard.svelte`:
- Line 55: The inline style on the clickable div using "text-decorationnone;" is
invalid and being ignored; update the div with the correct CSS declaration
(e.g., "text-decoration: none;") or remove the style attribute entirely if not
needed, by editing the element that contains onclick={onHistoryClick} to use a
valid style string or class name so the intended no-text-decoration behavior is
applied.

In `@src/lib/components/StackView.svelte`:
- Around line 118-121: In StackView.svelte change the onclick handler so
insideClick receives the actual clicked element instead of the outer container:
keep e.stopPropagation(), then compute const clicked = (e.target as
HTMLElement).closest('a') ?? e.target and call insideClick(clicked); this
ensures insideClick (used to check data-start-ref or class ref-link) sees the
generated <a> even when wrapped by tooltips or other wrappers.

In `@src/routes/plans/`[id]/settings/+page.svelte:
- Around line 21-24: Compute a single guarded planId from data.planConfig (e.g.
const planId = data.planConfig?.id) and use that in backNavigation and the start
action instead of accessing data.planConfig directly; if planId is missing do an
early return (or show a fallback) to avoid routing to `/plans/undefined` or
throwing on click—update the backNavigation function (which calls
gotoRoute(`/plans/${id}`)) and the other handler around lines 52-54 to use this
guarded planId and return immediately when it’s falsy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 27d0830f-4f46-4c56-9852-9c0442931502

📥 Commits

Reviewing files that changed from the base of the PR and between 24bd165 and 4b5a0e9.

📒 Files selected for processing (93)
  • eslint.config.js
  • src/lib/components/AudioPlaybackSpeed.svelte
  • src/lib/components/ContentCarousel.svelte
  • src/lib/components/ContentGrid.svelte
  • src/lib/components/ContentHeading.svelte
  • src/lib/components/ContentSingle.svelte
  • src/lib/components/FontList.svelte
  • src/lib/components/FontSelector.svelte
  • src/lib/components/HistoryCard.svelte
  • src/lib/components/HtmlBookView.svelte
  • src/lib/components/IconCard.svelte
  • src/lib/components/PlayButton.svelte
  • src/lib/components/ScrolledContent.svelte
  • src/lib/components/Sidebar.svelte
  • src/lib/components/Slider.svelte
  • src/lib/components/StackView.svelte
  • src/lib/components/TextAppearanceSelector.svelte
  • src/lib/data/plansData.ts
  • src/lib/icons/AboutIcon.svelte
  • src/lib/icons/AccountIcon.svelte
  • src/lib/icons/ArrowBackIcon.svelte
  • src/lib/icons/ArrowForwardIcon.svelte
  • src/lib/icons/BibleIcon.svelte
  • src/lib/icons/BookmarkIcon.svelte
  • src/lib/icons/BookmarkOutlineIcon.svelte
  • src/lib/icons/CalendarMonthIcon.svelte
  • src/lib/icons/CheckIcon.svelte
  • src/lib/icons/CheckboxIcon.svelte
  • src/lib/icons/CheckboxOutlineIcon.svelte
  • src/lib/icons/ChevronIcon.svelte
  • src/lib/icons/CopyContentIcon.svelte
  • src/lib/icons/DeleteIcon.svelte
  • src/lib/icons/DeleteSweepIcon.svelte
  • src/lib/icons/DropdownIcon.svelte
  • src/lib/icons/EditIcon.svelte
  • src/lib/icons/HamburgerIcon.svelte
  • src/lib/icons/HighlightIcon.svelte
  • src/lib/icons/HistoryIcon.svelte
  • src/lib/icons/HomeIcon.svelte
  • src/lib/icons/InfoIcon.svelte
  • src/lib/icons/LaunchIcon.svelte
  • src/lib/icons/LineSpacingIcon.svelte
  • src/lib/icons/MoreVertIcon.svelte
  • src/lib/icons/NoteIcon.svelte
  • src/lib/icons/SearchIcon.svelte
  • src/lib/icons/SettingsIcon.svelte
  • src/lib/icons/ShareIcon.svelte
  • src/lib/icons/SideBySideIcon.svelte
  • src/lib/icons/SinglePaneIcon.svelte
  • src/lib/icons/SortIcon.svelte
  • src/lib/icons/TextAppearanceIcon.svelte
  • src/lib/icons/TriangleLeftIcon.svelte
  • src/lib/icons/TriangleRightIcon.svelte
  • src/lib/icons/VerseByVerseIcon.svelte
  • src/lib/icons/audio/PauseIcon.svelte
  • src/lib/icons/audio/PauseOutlineCircleIcon.svelte
  • src/lib/icons/audio/PlayFillCircleIcon.svelte
  • src/lib/icons/audio/PlayIcon.svelte
  • src/lib/icons/audio/PlayOutlineCircleIcon.svelte
  • src/lib/icons/audio/PlayRepeatIcon.svelte
  • src/lib/icons/audio/RepeatIcon.svelte
  • src/lib/icons/image/BlurIcon.svelte
  • src/lib/icons/image/BrightnessIcon.svelte
  • src/lib/icons/image/ContrastIcon.svelte
  • src/lib/icons/image/FontChoiceIcon.svelte
  • src/lib/icons/image/FormatAlignCenterIcon.svelte
  • src/lib/icons/image/FormatAlignLeftIcon.svelte
  • src/lib/icons/image/FormatAlignRightIcon.svelte
  • src/lib/icons/image/FormatBoldIcon.svelte
  • src/lib/icons/image/FormatColorFillIcon.svelte
  • src/lib/icons/image/FormatItalicIcon.svelte
  • src/lib/icons/image/FormatLineSpacingIcon.svelte
  • src/lib/icons/image/ImageSingleIcon.svelte
  • src/lib/icons/image/ImagesIcon.svelte
  • src/lib/icons/image/LetterSpacingIcon.svelte
  • src/lib/icons/image/OpacityIcon.svelte
  • src/lib/icons/image/ReferenceIcon.svelte
  • src/lib/icons/image/ResizeArrowsIcon.svelte
  • src/lib/icons/image/SaturationIcon.svelte
  • src/lib/icons/image/TextGlowIcon.svelte
  • src/lib/icons/image/TextShadowIcon.svelte
  • src/lib/icons/image/TextShadowNoneIcon.svelte
  • src/lib/icons/image/TextWidthIcon.svelte
  • src/lib/navigate/index.ts
  • src/lib/video/index.ts
  • src/routes/+page.svelte
  • src/routes/bookmarks/+page.svelte
  • src/routes/contents/[id]/+page.svelte
  • src/routes/dev/icons/+page.svelte
  • src/routes/lexicon/+page.svelte
  • src/routes/notes/+page.svelte
  • src/routes/plans/[id]/settings/+page.svelte
  • src/routes/text/+page.svelte
💤 Files with no reviewable changes (3)
  • src/lib/data/plansData.ts
  • src/lib/components/ScrolledContent.svelte
  • src/routes/lexicon/+page.svelte

Comment thread src/lib/components/FontSelector.svelte
Comment thread src/lib/components/HistoryCard.svelte
Comment on lines +118 to +121
onclick={(e) => {
e.stopPropagation();
insideClick(e.currentTarget);
}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify mismatch between insideClick expectations and call-site argument.
rg -n -C2 "function insideClick|data-start-ref|classList.contains\\('ref-link'\\)|insideClick\\(e\\.currentTarget\\)" src/lib/components/StackView.svelte

Repository: sillsdev/appbuilder-pwa

Length of output: 823


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/lib/components/StackView.svelte"

echo "== insideClick implementation =="
nl -ba "$FILE" | sed -n '40,110p'

echo
echo "== onclick callsite + surrounding markup =="
nl -ba "$FILE" | sed -n '105,150p'

Repository: sillsdev/appbuilder-pwa

Length of output: 161


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/lib/components/StackView.svelte"

echo "== insideClick implementation =="
cat -n "$FILE" | sed -n '40,110p'

echo
echo "== onclick callsite + surrounding markup =="
cat -n "$FILE" | sed -n '105,150p'

Repository: sillsdev/appbuilder-pwa

Length of output: 4734


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "data-start-ref|data-end-ref|ref-link" src/lib/components/StackView.svelte

Repository: sillsdev/appbuilder-pwa

Length of output: 425


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "data-start-ref" src/lib/components src/lib -S || true
rg -n "ref-link" src/lib/components src/lib -S || true

Repository: sillsdev/appbuilder-pwa

Length of output: 2025


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show how data-start-ref and ref-link are applied
echo "== scripture-reference-utils.ts =="
cat -n src/lib/scripts/scripture-reference-utils.ts | sed -n '1,130p'

echo
echo "== milestoneLinks.ts =="
cat -n src/lib/scripts/milestoneLinks.ts | sed -n '130,220p'

echo
echo "== ScriptureViewSofria.svelte click logic uses e.target =="
cat -n src/lib/components/ScriptureViewSofria.svelte | sed -n '620,700p'

echo
echo "== ScriptureViewSofria.svelte later ref-link handling =="
cat -n src/lib/components/ScriptureViewSofria.svelte | sed -n '1400,1460p'

Repository: sillsdev/appbuilder-pwa

Length of output: 14638


🏁 Script executed:

#!/bin/bash
# Verify mismatch between insideClick expectations and call-site argument.
rg -n -C2 "function insideClick|data-start-ref|classList.contains\\('ref-link'\\)|insideClick\\(e\\.currentTarget\\)" src/lib/components/StackView.svelte

Repository: sillsdev/appbuilder-pwa

Length of output: 823


🏁 Script executed:

#!/bin/bash
# Verify mismatch between insideClick expectations and call-site argument.
rg -n -C2 "function insideClick|data-start-ref|classList.contains\\('ref-link'\\)|insideClick\\(e\\.currentTarget\\)" src/lib/components/StackView.svelte

Repository: sillsdev/appbuilder-pwa

Length of output: 823


🏁 Script executed:

#!/bin/bash
rg -n -C2 "function insideClick|data-start-ref|classList.contains\\('ref-link'\\)|insideClick\\(e\\.currentTarget\\)" src/lib/components/StackView.svelte

Repository: sillsdev/appbuilder-pwa

Length of output: 823


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find how generated anchors are inserted into the HTML that StackView renders
rg -n "generateAnchor\\(" src/lib/scripts/scripture-reference-utils.ts
rg -n "getReferenceLinkHtml\\(" src/lib/scripts/milestoneLinks.ts
rg -n "generateHTML(Main)?\\(" src/lib/scripts/scripture-reference-utils.ts | head

Repository: sillsdev/appbuilder-pwa

Length of output: 731


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/lib/components/StackView.svelte"
rg -n "handleHeaderLinkPressed|footnotes\\.(push|reset)|\\{`@html` item\\}|\\$footnotes" "$FILE"
rg -n "function handleHeaderLinkPressed|async function handleHeaderLinkPressed|handleHeaderLinkPressed\\(" "$FILE"

Repository: sillsdev/appbuilder-pwa

Length of output: 114


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/lib/components/StackView.svelte"
rg -n 'handleHeaderLinkPressed|footnotes\.(push|reset)|\{`@html` item\}|\$footnotes' "$FILE" || true
rg -n 'function handleHeaderLinkPressed|async function handleHeaderLinkPressed|handleHeaderLinkPressed\(' "$FILE" || true

Repository: sillsdev/appbuilder-pwa

Length of output: 576


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/lib/components/StackView.svelte"
cat -n "$FILE" | sed -n '1,220p'

Repository: sillsdev/appbuilder-pwa

Length of output: 5986


🏁 Script executed:

#!/bin/bash
rg -n -C2 "function insideClick|data-start-ref|classList.contains\\('ref-link'\\)|insideClick\\(e\\.currentTarget\\)" src/lib/components/StackView.svelte

Repository: sillsdev/appbuilder-pwa

Length of output: 823


🏁 Script executed:

#!/bin/bash
rg -n -C2 "function insideClick|data-start-ref|classList.contains\\('ref-link'\\)|insideClick\\(e\\.currentTarget\\)" src/lib/components/StackView.svelte

Repository: sillsdev/appbuilder-pwa

Length of output: 823


🏁 Script executed:

#!/bin/bash
# Ensure callsite no longer passes e.currentTarget and insideClick still checks expected markers.
rg -n "insideClick\\(e\\.currentTarget\\)" src/lib/components/StackView.svelte
rg -n "insideClick\\(target\\: HTMLElement\\)|data-start-ref|classList\\.contains\\('ref-link'\\)" src/lib/components/StackView.svelte

Repository: sillsdev/appbuilder-pwa

Length of output: 305


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "async function insideClick\\(target: HTMLElement\\)|data-start-ref|classList\\.contains\\('ref-link'\\)|insideClick\\(e\\.currentTarget\\)" src/lib/components/StackView.svelte
rg -n "setAttribute\\('data-start-ref'|classList\\.add\\('ref-link'\\)" src/lib/scripts/scripture-reference-utils.ts src/lib/scripts/milestoneLinks.ts

Repository: sillsdev/appbuilder-pwa

Length of output: 564


Fix insideClick argument to use the clicked element (not e.currentTarget).

insideClick(target) only works when target has data-start-ref or the ref-link class. data-start-ref is set on the generated <a> by scripture-reference-utils.ts, and ref-link is added to the <a> by milestoneLinks.ts, but StackView.svelte currently calls insideClick(e.currentTarget) (the outer .footnote div), so those branches won’t match.

💡 Proposed fix
             onclick={(e) => {
                 e.stopPropagation();
-                insideClick(e.currentTarget);
+                insideClick(e.target as HTMLElement);
             }}

When the ref-link <a> is wrapped (e.g., tooltip wrapper), prefer passing e.target.closest('a') ?? e.target so clicks on the wrapper still hit the <a>.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onclick={(e) => {
e.stopPropagation();
insideClick(e.currentTarget);
}}
onclick={(e) => {
e.stopPropagation();
insideClick(e.target as HTMLElement);
}}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/components/StackView.svelte` around lines 118 - 121, In
StackView.svelte change the onclick handler so insideClick receives the actual
clicked element instead of the outer container: keep e.stopPropagation(), then
compute const clicked = (e.target as HTMLElement).closest('a') ?? e.target and
call insideClick(clicked); this ensures insideClick (used to check
data-start-ref or class ref-link) sees the generated <a> even when wrapped by
tooltips or other wrappers.

Comment on lines 21 to 24
function backNavigation() {
const id = $page.data.planConfig.id;
const id = data.planConfig?.id;
gotoRoute(`/plans/${id}`);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard planConfig before routing and start action.

Line 22 and Line 53 handle planConfig inconsistently. If planConfig is missing, this can route to /plans/undefined or throw on click. Add a single guarded planId path and early-return fallback.

Suggested fix
 <script lang="ts">
@@
-    function backNavigation() {
-        const id = data.planConfig?.id;
-        gotoRoute(`/plans/${id}`);
-    }
+    const planId = $derived(data.planConfig?.id);
+
+    function backNavigation() {
+        if (!planId) {
+            gotoRoute('/plans');
+            return;
+        }
+        gotoRoute(`/plans/${planId}`);
+    }
@@
-                onclick={async function () {
-                    await startPlan(data.planConfig!.id);
-                }}
+                onclick={async function () {
+                    if (!planId) return;
+                    await startPlan(planId);
+                }}
             >

Also applies to: 52-54

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/plans/`[id]/settings/+page.svelte around lines 21 - 24, Compute a
single guarded planId from data.planConfig (e.g. const planId =
data.planConfig?.id) and use that in backNavigation and the start action instead
of accessing data.planConfig directly; if planId is missing do an early return
(or show a fallback) to avoid routing to `/plans/undefined` or throwing on
click—update the backNavigation function (which calls gotoRoute(`/plans/${id}`))
and the other handler around lines 52-54 to use this guarded planId and return
immediately when it’s falsy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Svelte 5 Migration

1 participant