Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions src/lib/timeline/Timeline.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
let { children, order = "default", class: className, ...restProps }: TimelineProps = $props();

const theme = $derived(getTheme("timeline"));

$effect(() => {
setContext<TimelineVariants["order"]>("order", order);
});
// svelte-ignore state_referenced_locally
setContext<TimelineVariants["order"]>("order", order);
Comment on lines +11 to +12
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Dec 17, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore reactive context for dynamic order updates.

The direct setContext call with the svelte-ignore comment removes reactivity. If the order prop changes after mount, child TimelineItem components won't receive the updated value.

Restore the reactive effect pattern to ensure context updates propagate:

-  // svelte-ignore state_referenced_locally
-  setContext<TimelineVariants["order"]>("order", order);
+  $effect(() => {
+    setContext<TimelineVariants["order"]>("order", order);
+  });

This ensures that when order changes, all child components receive the updated context value.

πŸ“ 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
// svelte-ignore state_referenced_locally
setContext<TimelineVariants["order"]>("order", order);
$effect(() => {
setContext<TimelineVariants["order"]>("order", order);
});
πŸ€– Prompt for AI Agents
In src/lib/timeline/Timeline.svelte around lines 11–12, the current direct
setContext call (with a svelte-ignore) breaks reactivity so updates to the order
prop won't propagate to children; replace the direct call with a reactive
statement (use Svelte's $: setContext("order", order)) so setContext runs
whenever order changes, remove the svelte-ignore, and keep the typed/context key
consistent with TimelineVariants["order"] so child TimelineItem components
receive updated values.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This doesn't work. It breaks to render unnecessary code.

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.

@shinokada, you're absolutely right, and I apologize for the incorrect suggestion. Using $effect to repeatedly call setContext can indeed cause rendering issues.

In Svelte 5, setContext should typically be called once at the component's initialization, not inside effects. The current implementation with the direct call is correct for this pattern.

Could you clarify: Is the order prop expected to change dynamically after the Timeline component mounts, or is it set once during initialization and remains constant? This will help me understand the intended behavior and avoid similar incorrect suggestions in the future.


🧠 Learnings used
Learnt from: shinokada
Repo: themesberg/flowbite-svelte PR: 1882
File: src/lib/bottom-navigation/BottomNavHeaderItem.svelte:9-9
Timestamp: 2025-12-16T13:21:28.743Z
Learning: In flowbite-svelte, when using ThemeProvider with reactive themes, `getTheme("componentName")` calls must be placed inside `$derived()` expressions (not at module scope) to ensure components react to dynamic theme changes. This pattern is intentional for reactive theming support.

const olCls = $derived(timeline({ order, class: clsx(theme, className) }));
</script>

Expand All @@ -23,10 +21,10 @@
@component
[Go to docs](https://flowbite-svelte.com/)
## Type
[TimelineProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L1953)
[TimelineProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L1811)
## Props
@prop children
@prop order = "default"
@prop class: className
@prop ...restProps
-->
-->
8 changes: 7 additions & 1 deletion src/lib/timeline/TimelineItem.svelte
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

<script lang="ts">
import { getContext, untrack } from "svelte";
import { timelineItem, type TimelineVariants } from "./theme";
Expand All @@ -15,6 +16,7 @@
isLast = false,
svgClass,
liClass,
defaultDivClass,
divClass,
timeClass,
h3Class,
Expand Down Expand Up @@ -46,10 +48,13 @@
connector: connectorClass
});


const theme = $derived(getTheme("timelineItem"));
let order = getContext<TimelineVariants["order"]>("order");

const { base, div, time, h3, svg, connector } = $derived(timelineItem({ order, color, isLast }));
const { base, div, defaultDiv, time, h3, svg, connector } = $derived(timelineItem({ order, color, isLast }));

const defaultDivCls = $derived(defaultDivClass ? defaultDivClass : defaultDiv());

function formatDisplayDate(dateStr: string, format: DateFormat) {
const date = new Date(dateStr);
Expand Down Expand Up @@ -101,6 +106,7 @@
</div>
{/if}
{:else if date}
<div class={defaultDivCls} aria-hidden="true"></div>
<time datetime={date} class={time({ class: clsx(theme?.time, styling.time) })}>
{datePrefix}
{formatDisplayDate(date, dateFormat)}
Expand Down
3 changes: 2 additions & 1 deletion src/lib/timeline/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const groupItem = tv({
img: "me-3 mb-3 w-12 h-12 rounded-full sm:mb-0",
div: "text-gray-600 dark:text-gray-400",
title: "text-base font-normal",
span: "inline-flex items-center text-xs font-normal text-gray-500 dark:text-gray-400",
span: "inline-flex items-center bg-gray-100 border border-gray-200 text-xs font-medium px-1.5 py-0.5 rounded",
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 | 🟑 Minor

Verify if groupItem span styling change is intentional.

This line changes the groupItem span from plain text styling to a badge-like appearance (adds background, border, padding, and rounded corners). This is a significant visual change that affects the GroupItem component, but appears unrelated to the Timeline default order icon fix described in issue #1881.

Confirm whether this styling change is:

  1. Intentional and part of a broader design update, or
  2. Accidentally included from another branch/change

Run the following script to check if this change is referenced in any related issues or documentation:

#!/bin/bash
# Description: Check for references to groupItem or badge styling changes

# Search for groupItem usage and styling references
echo "=== Searching for groupItem component usage ==="
rg -n "groupItem|GroupItem" --type=svelte --type=ts -C 2

# Search for any TODO or comments about badge styling
echo -e "\n=== Checking for badge-related comments ==="
rg -n "badge|pill" src/lib/timeline/ -C 2

svg: "me-1 h-3 w-3"
}
});
Expand Down Expand Up @@ -109,6 +109,7 @@ export const timelineItem = tv({
slots: {
base: "relative",
div: "",
defaultDiv: "absolute w-2 h-2 bg-gray-200 rounded-full mt-1.5 -start-5 border border-buffer",
time: "",
h3: "",
svg: "w-4 h-4",
Expand Down
1 change: 1 addition & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1964,6 +1964,7 @@ export interface TimelineItemProps extends TimelineItemVariants, HTMLLiAttribute
date: string;
svgClass?: string;
liClass?: string;
defaultDivClass?: string;
divClass?: string;
timeClass?: string;
h3Class?: string;
Expand Down
3 changes: 3 additions & 0 deletions src/routes/docs-examples/components/timeline/Activity.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@
import { Activity, ActivityItem } from "flowbite-svelte";
let activities = [
{
id:'activity-1',
title:
'Bonnie moved <a href="/" class="font-semibold text-primary-600 dark:text-primary-500 hover:underline">Jese Leos</a> to <span class="bg-gray-100 text-gray-800 text-xs font-normal me-2 px-2.5 py-0.5 rounded-sm dark:bg-gray-600 dark:text-gray-300">Funny Group</span>',
date: "just now",
alt: "image alt here",
src: "/images/profile-picture-2.webp"
},
{
id:'activity-2',
title: "We don’t serve their kind here! What? Your droids. ",
date: "2 hours ago",
alt: "image alt here",
src: "/images/profile-picture-2.webp",
text: "The approach will not be easy. You are required to maneuver straight down this trench and skim the surface to this point. The target area is only two meters wide. "
},
{
id:'activity-3',
title: "They’ll have to wait outside. We don’t want them here. ",
date: "1 day ago",
alt: "image alt here",
Expand Down
4 changes: 4 additions & 0 deletions src/routes/docs-examples/components/timeline/Grouped.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import { Group, GroupItem } from "flowbite-svelte";
let groupTimelines = [
{
id:'group-1',
name: '<span class="font-medium">Laura Romeros</span> likes <span class="font-medium">Bonnie Green\'s</span> post in <span class="font-medium"> How to start with Flowbite library</span>',
title:
'<span class="font-medium text-gray-900 dark:text-white">Jese Leos</span> likes <span class="font-medium text-gray-900 dark:text-white">Bonnie Green\'s</span> post in <span class="font-medium text-gray-900 dark:text-white"> How to start with Flowbite library</span>',
src: "/images/profile-picture-1.webp",
Expand All @@ -11,6 +13,8 @@
comment: '"I wanted to share a webinar zeroheight."'
},
{
id:'group-2',
name: '<span class="font-medium">Jese Leos</span> likes <span class="font-medium">Bonnie Green\'s</span> post in <span class="font-medium"> How to start with Flowbite library</span>',
title: '<span class="font-medium text-gray-900 dark:text-white">Bonnie Green</span> react to <span class="font-medium text-gray-900 dark:text-white">Thomas Lean\'s</span> comment',
src: "/images/profile-picture-2.webp",
alt: "alt here",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script lang="ts">
import type { PageProps } from "./$types";

let { data }: PageProps = $props();
let Content = $derived(data.content);
</script>

<Content />
15 changes: 15 additions & 0 deletions src/routes/docs-examples/components/timeline/[slug]/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { PageLoad } from "./$types";
import { error } from "@sveltejs/kit";

export const load: PageLoad = async ({ params }) => {
try {
const post = await import(`../${params.slug}.svelte`);
const content = post.default;

return {
content,
};
} catch (err) {
throw error(404, `Timeline example "${params.slug}" not found`);
}
};