@winkintel/bootstrap-svelte 1.0.4 → 1.0.6

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.
Files changed (81) hide show
  1. package/README.md +1 -1
  2. package/dist/Alert/alert.svelte +4 -2
  3. package/dist/Badge/badge.svelte +6 -4
  4. package/dist/Badge/badge.svelte.d.ts +2 -2
  5. package/dist/Badge/types.d.ts +2 -1
  6. package/dist/Badge/types.js +3 -11
  7. package/dist/Button/button.svelte +29 -9
  8. package/dist/ButtonGroup/button-group.svelte +3 -2
  9. package/dist/ButtonGroup/button-toolbar.svelte +3 -2
  10. package/dist/ButtonGroup/types.contract.d.ts +1 -0
  11. package/dist/ButtonGroup/types.contract.js +15 -0
  12. package/dist/ButtonGroup/types.d.ts +2 -2
  13. package/dist/Carousel/carousel-indicator-button.svelte +8 -1
  14. package/dist/Carousel/carousel-item.svelte +29 -9
  15. package/dist/Carousel/carousel.svelte +12 -5
  16. package/dist/Carousel/carousel.svelte.js +200 -42
  17. package/dist/Col/col.svelte +30 -22
  18. package/dist/Collapse/collapse.svelte +3 -3
  19. package/dist/Collapse/transition.js +78 -15
  20. package/dist/Collapse/types.d.ts +1 -0
  21. package/dist/Dropdown/dropdown-item.svelte +7 -0
  22. package/dist/Dropdown/dropdown.svelte.js +66 -19
  23. package/dist/Form/form-check-input.svelte +6 -6
  24. package/dist/Form/form-color-input.svelte +8 -3
  25. package/dist/Form/form-date-input.svelte +4 -4
  26. package/dist/Form/form-datetime-local-input.svelte +4 -4
  27. package/dist/Form/form-email-input.svelte +4 -4
  28. package/dist/Form/form-file-input.svelte +46 -6
  29. package/dist/Form/form-file-input.svelte.d.ts +3 -2
  30. package/dist/Form/form-hidden-input.svelte +1 -1
  31. package/dist/Form/form-hidden-input.svelte.d.ts +1 -1
  32. package/dist/Form/form-image-input.svelte +1 -1
  33. package/dist/Form/form-image-input.svelte.d.ts +2 -1
  34. package/dist/Form/form-month-input.svelte +4 -4
  35. package/dist/Form/form-number-input.svelte +4 -4
  36. package/dist/Form/form-password-input.svelte +4 -4
  37. package/dist/Form/form-radio-input.svelte +53 -3
  38. package/dist/Form/form-radio-input.svelte.d.ts +3 -2
  39. package/dist/Form/form-range-input.svelte +1 -1
  40. package/dist/Form/form-range-input.svelte.d.ts +2 -1
  41. package/dist/Form/form-search-input.svelte +4 -4
  42. package/dist/Form/form-select.svelte +7 -7
  43. package/dist/Form/form-switch-input.svelte +4 -4
  44. package/dist/Form/form-telephone-input.svelte +4 -4
  45. package/dist/Form/form-text-area.svelte +4 -4
  46. package/dist/Form/form-text-input.svelte +4 -4
  47. package/dist/Form/form-time-input.svelte +4 -4
  48. package/dist/Form/form-url-input.svelte +4 -4
  49. package/dist/Form/form-week-Input.svelte +4 -4
  50. package/dist/Form/types.d.ts +26 -20
  51. package/dist/ListGroup/list-group-item-action.svelte +14 -7
  52. package/dist/Modal/modal-title.svelte +7 -7
  53. package/dist/Modal/modal.svelte +86 -26
  54. package/dist/Modal/modal.svelte.js +15 -0
  55. package/dist/Nav/nav-link.svelte +12 -8
  56. package/dist/Navbar/navbar-collapse.svelte +18 -7
  57. package/dist/Navbar/navbar-collapse.svelte.d.ts +1 -1
  58. package/dist/Navbar/navbar-nav.svelte +1 -1
  59. package/dist/Navbar/navbar-toggler.svelte +9 -7
  60. package/dist/Navbar/navbar-toggler.svelte.d.ts +1 -1
  61. package/dist/Navbar/types.d.ts +3 -2
  62. package/dist/Offcanvas/offcanvas.svelte +38 -7
  63. package/dist/Pagination/pagination-item.svelte +27 -20
  64. package/dist/Pagination/pagination-link.svelte +20 -5
  65. package/dist/Pagination/pagination.svelte.js +28 -8
  66. package/dist/Placeholder/placeholder-item.svelte +7 -2
  67. package/dist/Placeholder/placeholder-item.svelte.d.ts +1 -1
  68. package/dist/Placeholder/types.d.ts +1 -0
  69. package/dist/Portal/portal.svelte +6 -1
  70. package/dist/Progress/progress-bar.svelte +22 -9
  71. package/dist/Row/row.svelte +9 -10
  72. package/dist/Row/types.d.ts +8 -7
  73. package/dist/Scrollspy/scrollspy-attachment.svelte.js +47 -28
  74. package/dist/Tooltip/tooltip.svelte +57 -10
  75. package/dist/common/css.js +96 -24
  76. package/dist/common/navbar-offcanvas.svelte.d.ts +2 -0
  77. package/dist/common/navbar-offcanvas.svelte.js +5 -4
  78. package/dist/common/overlay-stack.d.ts +13 -0
  79. package/dist/common/overlay-stack.js +49 -0
  80. package/dist/common/scrollbar.js +24 -8
  81. package/package.json +3 -1
package/README.md CHANGED
@@ -174,7 +174,7 @@ Interactive components are implemented as Svelte components rather than requirin
174
174
 
175
175
  ## Status and feedback
176
176
 
177
- This package is published as `1.0.4`, but feedback from Svelte developers is still very welcome. Useful feedback includes:
177
+ This package is published as `1.0.6`, but feedback from Svelte developers is still very welcome. Useful feedback includes:
178
178
 
179
179
  - Component API ergonomics
180
180
  - Svelte 5 idioms and runes compatibility
@@ -45,8 +45,10 @@ Bootstrap-styled alert component for displaying messages.
45
45
  import { uniqueClsx } from '../common/css.js';
46
46
  import { noop } from '../common/noop.js';
47
47
  import { fade } from 'svelte/transition';
48
- let { children, class: classValues = 'alert-primary', colorVariant, elementRef = $bindable(null), isDismissible = false, isAnimated = true, isOpen = $bindable(true), onClose = noop, onClosed = noop, ...restOfProps } = $props();
49
- let classes = $derived(uniqueClsx('alert', colorVariant && `alert-${colorVariant}`, {
48
+ let { children, class: classValues, colorVariant, elementRef = $bindable(null), isDismissible = false, isAnimated = true, isOpen = $bindable(true), onClose = noop, onClosed = noop, ...restOfProps } = $props();
49
+ let hasColorVariant = $derived(typeof colorVariant === 'string' && colorVariant.trim().length > 0);
50
+ let hasClassValues = $derived(typeof classValues === 'string' && classValues.trim().length > 0);
51
+ let classes = $derived(uniqueClsx('alert', hasColorVariant ? `alert-${colorVariant}` : !hasClassValues && 'alert-primary', {
50
52
  'alert-dismissible': isDismissible,
51
53
  fade: isAnimated,
52
54
  show: isOpen
@@ -21,20 +21,22 @@ A small count and labeling component that can be used to add context or notifica
21
21
 
22
22
  #### Positioned badges
23
23
  ```svelte
24
- <Badge position="top-right">99+</Badge>
24
+ <Badge position="top-end">99+</Badge>
25
25
  ```
26
26
 
27
27
  ### Props
28
28
  - `class` (string): Optional. CSS classes for styling the badge (default: 'text-bg-primary')
29
29
  - `elementRef` (HTMLElement): Optional. Reference to the badge DOM element
30
30
  - `isPill` (boolean): Optional. Makes the badge more rounded with pill styling
31
- - `position` (string): Optional. Position of the badge when used as a notification ('top-right', 'top-left', etc.)
31
+ - `position` (string): Optional logical position from `top-start` through `bottom-end`.
32
32
  - `colorVariant` (string): Optional. The badge variant style
33
33
  -->
34
34
  <script lang="ts">import { uniqueClsx } from '../common/css.js';
35
35
  import { transformBadgePosition } from './types.js';
36
- let { children, class: classValues = 'text-bg-primary', colorVariant, elementRef = $bindable(null), isPill = false, position, ...restOfProps } = $props();
37
- let classes = $derived(uniqueClsx('badge', colorVariant, { 'rounded-pill': isPill }, position && transformBadgePosition(position), classValues));
36
+ let { children, class: classValues, colorVariant, elementRef = $bindable(null), isPill = false, position, ...restOfProps } = $props();
37
+ let hasColorVariant = $derived(typeof colorVariant === 'string' && colorVariant.trim().length > 0);
38
+ let hasClassValues = $derived(typeof classValues === 'string' && classValues.trim().length > 0);
39
+ let classes = $derived(uniqueClsx('badge', hasColorVariant ? colorVariant : !hasClassValues && 'text-bg-primary', { 'rounded-pill': isPill }, position && transformBadgePosition(position), classValues));
38
40
  </script>
39
41
 
40
42
  <span bind:this={elementRef} class={classes} {...restOfProps}>
@@ -21,14 +21,14 @@ import { type BadgeRootProps } from './types.js';
21
21
  *
22
22
  * #### Positioned badges
23
23
  * ```svelte
24
- * <Badge position="top-right">99+</Badge>
24
+ * <Badge position="top-end">99+</Badge>
25
25
  * ```
26
26
  *
27
27
  * ### Props
28
28
  * - `class` (string): Optional. CSS classes for styling the badge (default: 'text-bg-primary')
29
29
  * - `elementRef` (HTMLElement): Optional. Reference to the badge DOM element
30
30
  * - `isPill` (boolean): Optional. Makes the badge more rounded with pill styling
31
- * - `position` (string): Optional. Position of the badge when used as a notification ('top-right', 'top-left', etc.)
31
+ * - `position` (string): Optional logical position from `top-start` through `bottom-end`.
32
32
  * - `colorVariant` (string): Optional. The badge variant style
33
33
  */
34
34
  declare const Badge: import("svelte").Component<BadgeRootProps, {}, "elementRef">;
@@ -25,4 +25,5 @@ export type BadgeRootProps = SpanElement & {
25
25
  * @param position - The logical position descriptor for the badge
26
26
  * @returns - Bootstrap CSS classes that implement the requested position
27
27
  */
28
- export declare const transformBadgePosition: (position: BadgePosition) => string;
28
+ export declare function transformBadgePosition(position: BadgePosition): string;
29
+ export declare function transformBadgePosition(position: string): string | undefined;
@@ -1,12 +1,4 @@
1
- /**
2
- * Transforms a logical badge position value into the corresponding Bootstrap CSS classes.
3
- * Returns a string with position-absolute class combined with the specific positioning
4
- * and translation classes required for proper badge placement.
5
- *
6
- * @param position - The logical position descriptor for the badge
7
- * @returns - Bootstrap CSS classes that implement the requested position
8
- */
9
- export const transformBadgePosition = (position) => {
1
+ export function transformBadgePosition(position) {
10
2
  // Map logical position names to their corresponding Bootstrap utility classes
11
3
  const positionTypeToClassMap = {
12
4
  'top-start': 'top-0 start-0',
@@ -20,5 +12,5 @@ export const transformBadgePosition = (position) => {
20
12
  'bottom-end': 'top-100 start-100'
21
13
  };
22
14
  const positionClass = positionTypeToClassMap[position];
23
- return `position-absolute ${positionClass} translate-middle`;
24
- };
15
+ return positionClass ? `position-absolute ${positionClass} translate-middle` : undefined;
16
+ }
@@ -56,32 +56,52 @@ Use Bootstrap's custom button styles for actions in forms, dialogs, and more. In
56
56
  -->
57
57
  <script lang="ts">/* eslint-disable @typescript-eslint/no-explicit-any -- `restOfProps` spread targets <svelte:element> which unions <a>/<button>; the union type is not spreadable without `as any` */
58
58
  import { uniqueClsx } from '../common/css.js';
59
+ import { noop } from '../common/noop.js';
59
60
  // Generate a unique ID for the collapse element, in case one is not provided...
60
61
  const uid = $props.id();
61
- let { children, class: classValues, colorVariant, disabled = false, elementRef = $bindable(null), href, id = `btn-${uid}`, size, type = 'button', value = $bindable(undefined), ...restOfProps } = $props();
62
- let isAnchor = $derived(Boolean(href));
63
- let isInput = $derived(Boolean(value));
62
+ let { 'aria-disabled': ariaDisabled, children, class: classValues, colorVariant, disabled = false, elementRef = $bindable(null), href, id = `btn-${uid}`, onclick = noop, role: consumerRole, size, tabindex: consumerTabIndex, type = 'button', value = $bindable(undefined), ...restOfProps } = $props();
63
+ let isAnchor = $derived(href !== undefined);
64
+ let isInput = $derived(!isAnchor && value !== undefined);
64
65
  let elementType = $derived(isAnchor ? 'a' : isInput ? 'input' : 'button');
65
66
  let classes = $derived(uniqueClsx('btn', colorVariant && `btn-${colorVariant}`, size && `btn-${size}`, isAnchor && disabled && 'disabled', classValues));
67
+ const handleClick = (event) => {
68
+ if (disabled) {
69
+ event.preventDefault();
70
+ return;
71
+ }
72
+ (onclick ?? noop)(event);
73
+ };
66
74
  </script>
67
75
 
68
76
  {#if !isInput}
69
77
  <svelte:element
70
78
  this={elementType}
71
- aria-disabled={isAnchor ? disabled : undefined}
79
+ {...restOfProps as any}
80
+ aria-disabled={disabled ? 'true' : isAnchor ? (ariaDisabled ?? 'false') : ariaDisabled}
72
81
  bind:this={elementRef}
73
82
  class={classes}
74
83
  disabled={isAnchor ? undefined : disabled}
75
- href={href && !disabled ? href : undefined}
84
+ href={isAnchor && !disabled ? href : undefined}
76
85
  {id}
77
- role={isAnchor ? 'button' : undefined}
78
- tabindex={isAnchor && disabled ? -1 : 0}
86
+ onclick={handleClick}
87
+ role={isAnchor ? 'button' : consumerRole}
88
+ tabindex={disabled ? -1 : (consumerTabIndex ?? 0)}
79
89
  type={isAnchor ? undefined : type}
80
- {...restOfProps as any}
81
90
  ><!-- using `as Record<string, unknown>` because Svelte doesn't support spreading props on elements with different types -->
82
91
  {@render children?.()}
83
92
  </svelte:element>
84
93
  {:else}
85
94
  <!-- using `as Record<string, unknown>` because Svelte doesn't support spreading props on elements with different types -->
86
- <input bind:this={elementRef} bind:value class={classes} {disabled} tabindex={disabled ? -1 : 0} {type} {...restOfProps as any} />
95
+ <input
96
+ {...restOfProps as any}
97
+ aria-disabled={disabled ? 'true' : ariaDisabled}
98
+ bind:this={elementRef}
99
+ bind:value
100
+ class={classes}
101
+ {disabled}
102
+ {id}
103
+ role={consumerRole}
104
+ tabindex={disabled ? -1 : (consumerTabIndex ?? 0)}
105
+ {type}
106
+ onclick={handleClick} />
87
107
  {/if}
@@ -42,10 +42,11 @@ A component that groups a series of buttons together on a single line or stacked
42
42
  import {} from './types.js';
43
43
  // Generate a unique ID for the collapse element, in case one is not provided...
44
44
  const uid = $props.id();
45
- let { ariaLabel = `Button group ${uid}`, children, class: classValues, elementRef = $bindable(null), id = `btn-group-${uid}`, isVertical = false, size, ...restOfProps } = $props();
45
+ let { 'aria-label': nativeAriaLabel, ariaLabel, children, class: classValues, elementRef = $bindable(null), id = `btn-group-${uid}`, isVertical = false, size, ...restOfProps } = $props();
46
46
  let classes = $derived(uniqueClsx({ 'btn-group-vertical': isVertical }, { 'btn-group': !isVertical }, size && `btn-group-${size}`, classValues));
47
+ let resolvedAriaLabel = $derived(ariaLabel ?? nativeAriaLabel ?? `Button group ${uid}`);
47
48
  </script>
48
49
 
49
- <div aria-label={ariaLabel} bind:this={elementRef} class={classes} {id} role="group" {...restOfProps}>
50
+ <div {...restOfProps} aria-label={resolvedAriaLabel} bind:this={elementRef} class={classes} {id} role="group">
50
51
  {@render children?.()}
51
52
  </div>
@@ -27,10 +27,11 @@ Combine sets of button groups into button toolbars for more complex components.
27
27
  import {} from './types.js';
28
28
  // Generate a unique ID for the collapse element, in case one is not provided...
29
29
  const uid = $props.id();
30
- let { ariaLabel = 'Button toolbar ${uid}', children, class: classValues, elementRef = $bindable(null), id = `btn-toolbar-${uid}`, ...restOfProps } = $props();
30
+ let { 'aria-label': nativeAriaLabel, ariaLabel, children, class: classValues, elementRef = $bindable(null), id = `btn-toolbar-${uid}`, ...restOfProps } = $props();
31
31
  let classes = $derived(uniqueClsx('btn-toolbar', classValues));
32
+ let resolvedAriaLabel = $derived(ariaLabel ?? nativeAriaLabel ?? `Button toolbar ${uid}`);
32
33
  </script>
33
34
 
34
- <div aria-label={ariaLabel} bind:this={elementRef} class={classes} {id} role="toolbar" {...restOfProps}>
35
+ <div {...restOfProps} aria-label={resolvedAriaLabel} bind:this={elementRef} class={classes} {id} role="toolbar">
35
36
  {@render children?.()}
36
37
  </div>
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ const group = { 'aria-label': 'Actions' };
2
+ const toolbar = { 'aria-label': 'Formatting' };
3
+ const invalidGroupRole = {
4
+ // @ts-expect-error ButtonGroup owns its required group role.
5
+ role: 'navigation'
6
+ };
7
+ const invalidToolbarRole = {
8
+ // @ts-expect-error ButtonToolbar owns its required toolbar role.
9
+ role: 'navigation'
10
+ };
11
+ void group;
12
+ void toolbar;
13
+ void invalidGroupRole;
14
+ void invalidToolbarRole;
15
+ export {};
@@ -11,11 +11,11 @@ export type ButtonCheckRootProps = Omit<HTMLInputAttributes, 'class' | 'size' |
11
11
  labelElementRef?: HTMLLabelElement | null;
12
12
  type?: ButtonCheckType;
13
13
  };
14
- export type ButtonGroupRootProps = DivElement & {
14
+ export type ButtonGroupRootProps = Omit<DivElement, 'role'> & {
15
15
  ariaLabel?: string;
16
16
  isVertical?: boolean;
17
17
  size?: ButtonGroupSize;
18
18
  };
19
- export type ButtonToolbarRootProps = DivElement & {
19
+ export type ButtonToolbarRootProps = Omit<DivElement, 'role'> & {
20
20
  ariaLabel?: string;
21
21
  };
@@ -17,10 +17,17 @@ Button for carousel indicators. Should be placed inside a Carousel.Indicators co
17
17
  - `elementRef` (HTMLElement): Optional. Reference to the DOM element.
18
18
  -->
19
19
  <script lang="ts">import { uniqueClsx } from '../common/css.js';
20
+ import { onDestroy, onMount } from 'svelte';
20
21
  import { CarouselIndicatorButtonState, initCarouselIndicatorButtonState } from './carousel.svelte.js';
21
22
  let { ariaLabel, class: classValues, elementRef = $bindable(null), ...restOfProps } = $props();
22
23
  // Initialize indicator button state
23
- const indicatorState = initCarouselIndicatorButtonState({});
24
+ const indicatorState = initCarouselIndicatorButtonState({
25
+ get elementRef() {
26
+ return elementRef;
27
+ }
28
+ });
29
+ onMount(() => indicatorState.root.scheduleRegistrationOrder());
30
+ onDestroy(() => indicatorState.root.unregisterIndicator(indicatorState));
24
31
  let classes = $derived(uniqueClsx({
25
32
  active: indicatorState.isActive || indicatorState.isNextActive
26
33
  }, classValues));
@@ -26,23 +26,41 @@ Represents a slide in the carousel. Should be placed inside a Carousel.Inner.
26
26
  <script lang="ts">import { easeInOut, uniqueClsx } from '../common/css.js';
27
27
  import { noop } from '../common/noop.js';
28
28
  import { linear } from 'svelte/easing';
29
+ import { onDestroy, onMount } from 'svelte';
29
30
  import { fade, fly } from 'svelte/transition';
30
31
  import { CarouselItemState, initCarouselItemState } from './carousel.svelte.js';
31
32
  // Generate a unique ID for the carousel-item element, in case one is not provided
32
33
  const uid = $props.id();
33
- let { children, class: classValues, elementRef = $bindable(null), id = `carousel-item-${uid}`, isActive = false, interval = 5000, onSlide = noop, onSlid = noop, style, ...restOfProps } = $props();
34
+ let { children, class: classValues, elementRef = $bindable(null), id = `carousel-item-${uid}`, isActive = false, interval, onmouseenter: onMouseEnter, onmouseleave: onMouseLeave, onSlide = noop, onSlid = noop, style, ...restOfProps } = $props();
35
+ let orderElementRef = $state(null);
34
36
  // Get the item state after the component is mounted
35
37
  const itemState = initCarouselItemState({
36
38
  get id() {
37
39
  return id;
38
40
  },
41
+ get elementRef() {
42
+ return elementRef;
43
+ },
39
44
  get isActive() {
40
45
  return isActive;
41
46
  },
42
47
  get interval() {
43
48
  return interval;
49
+ },
50
+ get orderElementRef() {
51
+ return orderElementRef;
44
52
  }
45
53
  });
54
+ onMount(() => itemState.root.scheduleRegistrationOrder());
55
+ onDestroy(() => itemState.root.unregisterItem(itemState));
56
+ function handleMouseEnter(event) {
57
+ itemState.root.handleMouseEnter();
58
+ onMouseEnter?.(event);
59
+ }
60
+ function handleMouseLeave(event) {
61
+ itemState.root.handleMouseLeave();
62
+ onMouseLeave?.(event);
63
+ }
46
64
  let flyX = $derived.by(() => {
47
65
  if (itemState.isNext) {
48
66
  return '100%';
@@ -62,6 +80,8 @@ let classes = $derived(uniqueClsx('carousel-item', {
62
80
  let styles = $derived(`transition: transform ${itemState.root.transitionDuration / 1000}s ease-in-out !important;` + (style ? style : ''));
63
81
  </script>
64
82
 
83
+ <span aria-hidden="true" bind:this={orderElementRef} hidden></span>
84
+
65
85
  <!--
66
86
  The slide and crossfade branches use in: (never transition:) — their exit visuals are
67
87
  driven by the carousel-item-start/-end CSS classes during the transition window, and
@@ -83,8 +103,8 @@ let styles = $derived(`transition: transform ${itemState.root.transitionDuration
83
103
  opacity: 1,
84
104
  easing: easeInOut
85
105
  }}
86
- onmouseenter={() => itemState.root.handleMouseEnter()}
87
- onmouseleave={() => itemState.root.handleMouseLeave()}
106
+ onmouseenter={handleMouseEnter}
107
+ onmouseleave={handleMouseLeave}
88
108
  {...restOfProps}>
89
109
  {@render children?.()}
90
110
  </div>
@@ -102,8 +122,8 @@ let styles = $derived(`transition: transform ${itemState.root.transitionDuration
102
122
  duration: itemState.root.transitionDuration / 2,
103
123
  easing: linear
104
124
  }}
105
- onmouseenter={() => itemState.root.handleMouseEnter()}
106
- onmouseleave={() => itemState.root.handleMouseLeave()}
125
+ onmouseenter={handleMouseEnter}
126
+ onmouseleave={handleMouseLeave}
107
127
  {...restOfProps}>
108
128
  {@render children?.()}
109
129
  </div>
@@ -122,8 +142,8 @@ let styles = $derived(`transition: transform ${itemState.root.transitionDuration
122
142
  opacity: 0,
123
143
  easing: easeInOut
124
144
  }}
125
- onmouseenter={() => itemState.root.handleMouseEnter()}
126
- onmouseleave={() => itemState.root.handleMouseLeave()}
145
+ onmouseenter={handleMouseEnter}
146
+ onmouseleave={handleMouseLeave}
127
147
  {...restOfProps}>
128
148
  {@render children?.()}
129
149
  </div>
@@ -136,8 +156,8 @@ let styles = $derived(`transition: transform ${itemState.root.transitionDuration
136
156
  onintrostart={onSlide}
137
157
  onintroend={onSlid}
138
158
  transition:fade={{ duration: 0 }}
139
- onmouseenter={() => itemState.root.handleMouseEnter()}
140
- onmouseleave={() => itemState.root.handleMouseLeave()}
159
+ onmouseenter={handleMouseEnter}
160
+ onmouseleave={handleMouseLeave}
141
161
  {...restOfProps}>
142
162
  {@render children?.()}
143
163
  </div>
@@ -42,11 +42,11 @@ The main container for a carousel component.
42
42
  - `transitionDuration` (number): Optional. The duration of the transition effect in milliseconds. Default is `600`.
43
43
  -->
44
44
  <script lang="ts">import { uniqueClsx } from '../common/css.js';
45
- import { onMount } from 'svelte';
45
+ import { onMount, tick } from 'svelte';
46
46
  import { CarouselRootState, initCarouselRootState } from './carousel.svelte.js';
47
47
  // Generate a unique ID for the carousel element, in case one is not provided
48
48
  const uid = $props.id();
49
- let { animation = CarouselRootState.ANIMATION_DEFAULT, children, class: classValues, elementRef = $bindable(null), id = `carousel-${uid}`, interval = CarouselRootState.INTERNAL_DEFAULT, pause = CarouselRootState.PAUSE_DEFAULT, ride = CarouselRootState.RIDE_DEFAULT, style, transitionDuration = CarouselRootState.TRANSITION_DURATION_DEFAULT, ...restOfProps } = $props();
49
+ let { animation = CarouselRootState.ANIMATION_DEFAULT, children, class: classValues, elementRef = $bindable(null), id = `carousel-${uid}`, interval = CarouselRootState.INTERNAL_DEFAULT, onpointercancel: onPointerCancel, onpointerdown: onPointerDown, onpointerup: onPointerUp, pause = CarouselRootState.PAUSE_DEFAULT, ride = CarouselRootState.RIDE_DEFAULT, style, transitionDuration = CarouselRootState.TRANSITION_DURATION_DEFAULT, ...restOfProps } = $props();
50
50
  // Initialize the carousel state
51
51
  const rootState = initCarouselRootState({
52
52
  get animation() {
@@ -74,14 +74,21 @@ const unset = Symbol('unset');
74
74
  // Handle touch events for swipe gestures
75
75
  function handlePointerDown(pointerEvent) {
76
76
  rootState.handlePointerDown(pointerEvent);
77
+ onPointerDown?.(pointerEvent);
77
78
  }
78
79
  function handlePointerMove(pointerEvent) {
79
80
  rootState.handlePointerMove(pointerEvent);
80
81
  }
81
82
  function handlePointerUp(pointerEvent) {
82
83
  rootState.handlePointerUp(pointerEvent);
84
+ onPointerUp?.(pointerEvent);
85
+ }
86
+ function handlePointerCancel(pointerEvent) {
87
+ rootState.handlePointerCancel();
88
+ onPointerCancel?.(pointerEvent);
83
89
  }
84
90
  onMount(() => {
91
+ tick().then(() => rootState.start());
85
92
  // Cleanup when component is destroyed
86
93
  return () => {
87
94
  rootState.dispose();
@@ -102,7 +109,7 @@ $effect(() => {
102
109
  });
103
110
  $effect(() => {
104
111
  if (previousInterval !== unset && previousInterval !== interval) {
105
- rootState.interval = interval || CarouselRootState.INTERNAL_DEFAULT;
112
+ rootState.interval = interval;
106
113
  }
107
114
  previousInterval = interval;
108
115
  });
@@ -120,7 +127,7 @@ $effect(() => {
120
127
  });
121
128
  $effect(() => {
122
129
  if (previousTransitionDuration !== unset && previousTransitionDuration !== transitionDuration) {
123
- rootState.transitionDuration = transitionDuration || CarouselRootState.TRANSITION_DURATION_DEFAULT;
130
+ rootState.transitionDuration = transitionDuration;
124
131
  }
125
132
  previousTransitionDuration = transitionDuration;
126
133
  });
@@ -133,7 +140,7 @@ $effect(() => {
133
140
  onpointerdown={handlePointerDown}
134
141
  onpointermove={handlePointerMove}
135
142
  onpointerup={handlePointerUp}
136
- onpointercancel={handlePointerUp}
143
+ onpointercancel={handlePointerCancel}
137
144
  style={styles}
138
145
  {...restOfProps}>
139
146
  {@render children?.()}