flowbite-svelte 1.10.9 → 1.10.11

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.
@@ -9,7 +9,21 @@
9
9
 
10
10
  let { children, header, arrowup, arrowdown, open = $bindable(false), activeClass, inactiveClass, transitionType = slide, transitionParams, class: className, classes, headerClass, contentClass }: AccordionItemProps = $props();
11
11
 
12
- themeDeprecated("AccordionItem", { headerClass, contentClass, activeClass, inactiveClass });
12
+ themeDeprecated(
13
+ "AccordionItem",
14
+ {
15
+ headerClass,
16
+ contentClass,
17
+ activeClass,
18
+ inactiveClass
19
+ },
20
+ {
21
+ headerClass: "button",
22
+ contentClass: "content",
23
+ activeClass: "active",
24
+ inactiveClass: "inactive"
25
+ }
26
+ );
13
27
 
14
28
  let styling: typeof classes = $derived(classes ?? { button: headerClass, content: contentClass, active: activeClass, inactive: inactiveClass });
15
29
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  let { children, icon, badgeStatus = $bindable(true), color = "primary", large = false, dismissable = false, class: className, classes, border, href, target, rounded, transition = fade, params, aClass, onclose, ...restProps }: BadgeProps = $props();
9
9
 
10
- themeDeprecated("Badge", { aClass });
10
+ themeDeprecated("Badge", { aClass }, { aClass: "linkClass" });
11
11
 
12
12
  let styling = $derived(classes ?? { linkClass: aClass });
13
13
 
@@ -7,7 +7,8 @@
7
7
 
8
8
  let { children, header, open = $bindable(true), dismissable = true, color = "gray", type, class: className, classes, innerClass, transition = fade, params, closeClass, ...restProps }: BannerProps = $props();
9
9
 
10
- themeDeprecated("Banner", { innerClass, closeClass });
10
+ themeDeprecated("Banner", { innerClass, closeClass }, { innerClass: "insideDiv", closeClass: "dismissable" });
11
+
11
12
  let styling = $derived(classes ?? { insideDiv: innerClass, dismissable: closeClass });
12
13
 
13
14
  // Theme context
@@ -8,7 +8,7 @@
8
8
 
9
9
  let { children, header, position = "fixed", navType = "default", class: className, classes, outerClass, innerClass, activeClass, activeUrl = "", ...restProps }: BottomNavProps = $props();
10
10
 
11
- themeDeprecated("BottomNav", { innerClass, outerClass });
11
+ themeDeprecated("BottomNav", { innerClass, outerClass }, { innerClass: "inner", outerClass: "class" });
12
12
  let styling = $derived(classes ?? { inner: innerClass });
13
13
 
14
14
  // Theme context
@@ -6,7 +6,8 @@
6
6
 
7
7
  let { children, class: className, classes, outerClass, innerClass, ...restProps }: BottomNavHeaderProps = $props();
8
8
 
9
- themeDeprecated("BottomNavHeader", { innerClass, outerClass });
9
+ themeDeprecated("BottomNavHeader", { innerClass, outerClass }, { innerClass: "inner", outerClass: "class" });
10
+
10
11
  let styling = $derived(classes ?? { innerDiv: innerClass });
11
12
 
12
13
  // Theme context
@@ -8,7 +8,7 @@
8
8
 
9
9
  let { children, btnName, appBtnPosition = "middle", activeClass, class: className, classes, btnClass, spanClass, active: manualActive, ...restProps }: BottomNavItemProps = $props();
10
10
 
11
- themeDeprecated("BottomNavItem", { spanClass, btnClass });
11
+ themeDeprecated("BottomNavItem", { spanClass, btnClass }, { spanClass: "span", btnClass: "class" });
12
12
  let styling = $derived(classes ?? { span: spanClass });
13
13
 
14
14
  // Theme context
@@ -6,7 +6,7 @@
6
6
 
7
7
  let { children, solid = false, class: className, classes, olClass, ariaLabel = "Breadcrumb", ...restProps }: BreadcrumbProps = $props();
8
8
 
9
- themeDeprecated("Breadcrumb", { olClass });
9
+ themeDeprecated("Breadcrumb", { olClass }, { olClass: "list" });
10
10
  let styling = $derived(classes ?? { list: olClass });
11
11
 
12
12
  const theme = getTheme("breadcrumb");
@@ -6,7 +6,8 @@
6
6
 
7
7
  let { children, color = "gray", horizontal = false, shadow = "md", reverse = false, img, size = "sm", class: className, classes, imgClass, ...restProps }: CardProps = $props();
8
8
 
9
- themeDeprecated("Card", { imgClass });
9
+ themeDeprecated("Card", { imgClass }, { imgClass: "image" });
10
+
10
11
  let styling = $derived(classes ?? { image: imgClass });
11
12
 
12
13
  const theme = getTheme("card");
@@ -120,10 +120,32 @@
120
120
 
121
121
  function handleInputChangeWithDateFns() {
122
122
  const inputValue = inputElement?.value?.trim();
123
- if (!inputValue) return;
123
+ if (!inputValue) {
124
+ rangeFrom = undefined;
125
+ rangeTo = undefined;
126
+ inputElement?.setCustomValidity("");
127
+ return;
128
+ }
124
129
 
125
130
  inputElement?.setCustomValidity("");
126
131
 
132
+ if (range) {
133
+ const parts = inputValue.split(" - ");
134
+ if (parts.length === 2) {
135
+ const parsedFrom = tryParseDate(parts[0]);
136
+ const parsedTo = tryParseDate(parts[1]);
137
+
138
+ if (parsedFrom && isValid(parsedFrom) && isDateAvailable(parsedFrom) && parsedTo && isValid(parsedTo) && isDateAvailable(parsedTo)) {
139
+ [rangeFrom, rangeTo] = parsedFrom > parsedTo ? [parsedTo, parsedFrom] : [parsedFrom, parsedTo];
140
+ onselect?.({ from: rangeFrom, to: rangeTo });
141
+ return;
142
+ } else {
143
+ inputElement?.setCustomValidity(`Please enter date range in format: ${getDateFormatPattern()} - ${getDateFormatPattern()}`);
144
+ return;
145
+ }
146
+ }
147
+ }
148
+
127
149
  const parsedDate = tryParseDate(inputValue);
128
150
 
129
151
  if (!parsedDate || !isValid(parsedDate)) {
@@ -189,12 +211,9 @@
189
211
 
190
212
  function getDateFormatPattern(): string {
191
213
  const actualLocale = locale === "default" ? navigator.language : locale;
192
-
193
- // Create a test date and format it to understand the pattern
194
214
  const testDate = new Date(2025, 0, 15); // January 15, 2025
195
215
  const formatted = testDate.toLocaleDateString(actualLocale, dateFormat || { year: "numeric", month: "numeric", day: "numeric" });
196
216
 
197
- // Analyze the formatted string to determine the pattern
198
217
  if (formatted.includes(".")) {
199
218
  // German/European format with dots
200
219
  if (formatted.startsWith("15.")) {
@@ -210,7 +229,7 @@
210
229
  } else if (formatted.startsWith("15/")) {
211
230
  return "d/M/yyyy"; // UK format
212
231
  }
213
- // Additional check with different test date
232
+
214
233
  const testDate2 = new Date(2025, 11, 3); // December 3, 2025
215
234
  const formatted2 = testDate2.toLocaleDateString(actualLocale, dateFormat || { year: "numeric", month: "numeric", day: "numeric" });
216
235
  if (formatted2.startsWith("3/") || formatted2.startsWith("03/")) {
@@ -248,7 +267,7 @@
248
267
  }
249
268
  }
250
269
 
251
- // MODIFIED: Use locale for formatting (not translationLocale)
270
+ // Use locale for formatting (not translationLocale)
252
271
  const formatDate = (date?: Date): string => date?.toLocaleDateString(locale, dateFormat) ?? "";
253
272
  const isSameDate = (date1?: Date, date2?: Date): boolean => (date1 && date2 ? isSameDay(date1, date2) : false);
254
273
  const isToday = (day: Date): boolean => isSameDate(day, new Date());
@@ -277,7 +296,16 @@
277
296
  focusedDate = addDay(focusedDate, 7);
278
297
  break;
279
298
  case "Enter":
280
- handleDaySelect(focusedDate);
299
+ if (range) {
300
+ if (rangeFrom && rangeTo) {
301
+ if (autohide && !inline) isOpen = false;
302
+ } else {
303
+ handleDaySelect(focusedDate);
304
+ }
305
+ } else {
306
+ handleDaySelect(focusedDate);
307
+ if (autohide && !inline) isOpen = false;
308
+ }
281
309
  break;
282
310
  case "Escape":
283
311
  isOpen = false;
@@ -293,7 +321,7 @@
293
321
  currentMonth = new Date(focusedDate.getFullYear(), focusedDate.getMonth(), 1);
294
322
  }
295
323
 
296
- // MODIFIED: Use translationLocale for aria-label
324
+ // Use translationLocale for aria-label
297
325
  setTimeout(() => {
298
326
  const focusedButton = calendarRef?.querySelector(`button[aria-label="${focusedDate!.toLocaleDateString(translationLocale, { weekday: "long", year: "numeric", month: "long", day: "numeric" })}"]`) as HTMLButtonElement | null;
299
327
  focusedButton?.focus();
@@ -301,7 +329,13 @@
301
329
  }
302
330
 
303
331
  function handleInputKeydown(event: KeyboardEvent) {
304
- if (event.key === "Enter" || event.key === " ") {
332
+ if (event.key === "Enter") {
333
+ event.preventDefault();
334
+ handleInputChangeWithDateFns();
335
+ if (autohide && !inline) {
336
+ isOpen = false;
337
+ }
338
+ } else if (event.key === " ") {
305
339
  event.preventDefault();
306
340
  isOpen = !isOpen;
307
341
  }
@@ -6,7 +6,8 @@
6
6
 
7
7
  let { children, class: className, classes, divClass, div2Class, div3Class, div4Class, div5Class, div6Class, div7Class, ...restProps }: AndroidProps = $props();
8
8
 
9
- themeDeprecated("Android", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class, div7Class });
9
+ themeDeprecated("Android", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class, div7Class }, { divClass: "class", div2Class: "top", div3Class: "leftTop", div4Class: "leftMid", div5Class: "leftBot", div6Class: "right", div7Class: "slot" });
10
+
10
11
  let styling = $derived(
11
12
  classes ?? {
12
13
  top: div2Class,
@@ -6,7 +6,7 @@
6
6
 
7
7
  let { children, class: className, classes, divClass, div2Class, div3Class, div4Class, div5Class, div6Class, ...restProps }: DefaultMockupProps = $props();
8
8
 
9
- themeDeprecated("DefaultMockup", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class });
9
+ themeDeprecated("DefaultMockup", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class }, { divClass: "class", div2Class: "top", div3Class: "leftTop", div4Class: "leftBot", div5Class: "right", div6Class: "slot" });
10
10
  let styling = $derived(
11
11
  classes ?? {
12
12
  top: div2Class,
@@ -6,7 +6,7 @@
6
6
 
7
7
  let { children, class: className, classes, divClass, div2Class, div3Class, div4Class, ...restProps }: DesktopProps = $props();
8
8
 
9
- themeDeprecated("DesktopMockup", { divClass, div2Class, div3Class, div4Class });
9
+ themeDeprecated("DesktopMockup", { divClass, div2Class, div3Class, div4Class }, { divClass: "class", div2Class: "inner", div3Class: "bot", div4Class: "botUnder" });
10
10
  let styling = $derived(
11
11
  classes ?? {
12
12
  inner: div2Class,
@@ -6,7 +6,7 @@
6
6
 
7
7
  let { children, class: className, classes, divClass, div2Class, div3Class, div4Class, div5Class, div6Class, ...restProps }: IosProps = $props();
8
8
 
9
- themeDeprecated("Ios", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class });
9
+ themeDeprecated("Ios", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class }, { divClass: "class", div2Class: "top", div3Class: "lefttop", div4Class: "leftBot", div5Class: "right", div6Class: "slot" });
10
10
  let styling = $derived(
11
11
  classes ?? {
12
12
  top: div2Class,
@@ -6,7 +6,7 @@
6
6
 
7
7
  let { children, class: className, classes, divClass, div2Class, div3Class, div4Class, ...restProps }: LaptopProps = $props();
8
8
 
9
- themeDeprecated("Laptop", { divClass, div2Class, div3Class, div4Class });
9
+ themeDeprecated("Laptop", { divClass, div2Class, div3Class, div4Class }, { divClass: "class", div2Class: "top", div3Class: "lefttop", div4Class: "leftBot", div5Class: "right", div6Class: "slot" });
10
10
  let styling = $derived(
11
11
  classes ?? {
12
12
  inner: div2Class,
@@ -6,7 +6,7 @@
6
6
 
7
7
  let { children, class: className, classes, divClass, div2Class, div3Class, div4Class, div5Class, div6Class, ...restProps }: SmartwatchProps = $props();
8
8
 
9
- themeDeprecated("Smartwatch", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class });
9
+ themeDeprecated("Smartwatch", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class }, { divClass: "class", div2Class: "top", div3Class: "rightTop", div4Class: "rightBot", div5Class: "bot", div6Class: "slot" });
10
10
  let styling = $derived(
11
11
  classes ?? {
12
12
  top: div2Class,
@@ -6,7 +6,7 @@
6
6
 
7
7
  let { children, class: className, classes, divClass, div2Class, div3Class, div4Class, div5Class, div6Class, ...restProps }: TabletProps = $props();
8
8
 
9
- themeDeprecated("TabletMockup", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class });
9
+ themeDeprecated("TabletMockup", { divClass, div2Class, div3Class, div4Class, div5Class, div6Class }, { divClass: "class", div2Class: "leftTop", div3Class: "leftMid", div4Class: "leftBot", div5Class: "right", div6Class: "slot" });
10
10
  let styling = $derived(
11
11
  classes ?? {
12
12
  leftTop: div2Class,
@@ -11,5 +11,5 @@ export type Classes<T extends {
11
11
  [K in keyof Slots<T>]: ClassValue;
12
12
  }>;
13
13
  };
14
- export declare function themeDeprecated(component: string, names: Record<string, unknown>): void;
14
+ export declare function themeDeprecated(component: string, names: Record<string, unknown>, replacements?: Record<string, unknown>): void;
15
15
  export {};
@@ -1,14 +1,46 @@
1
1
  import {} from "..";
2
2
  import { getContext } from "svelte";
3
+ import { dev } from "$app/environment";
4
+ // add PUBLIC_SHOW_HINT=true to .env to show migration hints in the console during the playwright tests
5
+ import { PUBLIC_SHOW_HINT } from "$env/static/public";
3
6
  export function getTheme(componentKey) {
4
7
  const theme = getContext("theme");
5
8
  return theme?.[componentKey];
6
9
  }
7
- export function themeDeprecated(component, names) {
8
- const nonEmptyNames = Object.keys(names)
9
- .filter((name) => names[name])
10
- .map((name) => `"${name}"`);
10
+ export function themeDeprecated(component, names, replacements) {
11
+ const showHint = dev || PUBLIC_SHOW_HINT === "true";
12
+ if (!showHint)
13
+ return;
14
+ const nonEmptyNames = Object.keys(names).filter((name) => names[name]);
11
15
  if (nonEmptyNames.length === 0)
12
16
  return;
13
- console.warn(`The following "${component}" props are deprecated: ${nonEmptyNames.join(", ")}.\nPlease update your code to use the new "classes" property.`);
17
+ let migrationHint = "";
18
+ const usesClass = nonEmptyNames.some((name) => replacements?.[name] === "class");
19
+ const propText = usesClass ? `"classes" or "class"` : `"classes"`;
20
+ if (replacements) {
21
+ const classProps = [];
22
+ const classesObjectEntries = [];
23
+ for (const name of nonEmptyNames) {
24
+ const newKey = replacements[name];
25
+ const value = names[name];
26
+ if (!newKey || !value)
27
+ continue;
28
+ if (newKey === "class") {
29
+ classProps.push(`class="${value}"`);
30
+ }
31
+ else {
32
+ classesObjectEntries.push(`${newKey}: "${value}"`);
33
+ }
34
+ }
35
+ const hintLines = [];
36
+ if (classProps.length > 0)
37
+ hintLines.push(...classProps);
38
+ if (classesObjectEntries.length > 0) {
39
+ hintLines.push(`classes={{ ${classesObjectEntries.join(", ")} }}`);
40
+ }
41
+ if (hintLines.length > 0) {
42
+ migrationHint = `\nMigration example: ${hintLines.join(" ")}`;
43
+ }
44
+ }
45
+ console.warn(`The following "${component}" props are deprecated: ${nonEmptyNames.map((n) => `"${n}"`).join(", ")}.` + ` Please update your code to use the new ${propText} prop.${migrationHint}`);
14
46
  }
package/dist/types.d.ts CHANGED
@@ -393,7 +393,6 @@ export interface DatepickerProps extends DatepickerVariants, Omit<HTMLAttributes
393
393
  placeholder?: string;
394
394
  disabled?: boolean;
395
395
  required?: boolean;
396
- inputClass?: ClassValue;
397
396
  color?: ButtonProps["color"];
398
397
  inline?: boolean;
399
398
  autohide?: boolean;
@@ -402,9 +401,10 @@ export interface DatepickerProps extends DatepickerVariants, Omit<HTMLAttributes
402
401
  onselect?: (x: DateOrRange) => void;
403
402
  onclear?: () => void;
404
403
  onapply?: (x: DateOrRange) => void;
405
- btnClass?: ClassValue;
406
404
  inputmode?: HTMLInputAttributes["inputmode"];
407
405
  monthColor?: ButtonProps["color"];
406
+ btnClass?: ClassValue;
407
+ inputClass?: ClassValue;
408
408
  monthBtnSelected?: ClassValue;
409
409
  monthBtn?: ClassValue;
410
410
  translationLocale?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowbite-svelte",
3
- "version": "1.10.9",
3
+ "version": "1.10.11",
4
4
  "description": "Flowbite components for Svelte",
5
5
  "main": "dist/index.js",
6
6
  "author": {
@@ -811,7 +811,7 @@
811
811
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
812
812
  "lint": "prettier --check . && eslint .",
813
813
  "format": "prettier --write .",
814
- "test:e2e": "playwright test",
814
+ "test:e2e": "PUBLIC_SHOW_HINT=true playwright test",
815
815
  "test:unit": "vitest",
816
816
  "gen:exports": "svelte-lib-helpers exports",
817
817
  "gen:docspropvalue": "svelte-lib-helpers docspropvalue themesberg/flowbite-svelte",