mithril-materialized 3.9.0 → 3.11.0

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.
package/dist/index.esm.js CHANGED
@@ -505,6 +505,106 @@ const Autocomplete = () => {
505
505
  };
506
506
  };
507
507
 
508
+ /**
509
+ * Badge component
510
+ *
511
+ * Displays a badge anchored to a child element. Commonly used for notifications,
512
+ * counts, or status indicators. Supports flexible positioning, colors, and variants.
513
+ *
514
+ * @example
515
+ * ```typescript
516
+ * // Basic notification badge
517
+ * m(Badge, { badgeContent: 5 },
518
+ * m('button.btn', 'Messages')
519
+ * )
520
+ *
521
+ * // Dot badge on avatar
522
+ * m(Badge, {
523
+ * variant: 'dot',
524
+ * color: 'green',
525
+ * overlap: 'circular'
526
+ * },
527
+ * m('img.circle', { src: 'avatar.jpg' })
528
+ * )
529
+ * ```
530
+ */
531
+ const Badge = () => {
532
+ return {
533
+ view: ({ attrs, children }) => {
534
+ const { badgeContent, max, anchorOrigin = { vertical: 'top', horizontal: 'right' }, overlap = 'rectangular', variant = 'standard', color = 'red', colorIntensity, invisible = false, showZero = false, 'aria-label': ariaLabel, badgeClassName = '', className = '' } = attrs, params = __rest(attrs, ["badgeContent", "max", "anchorOrigin", "overlap", "variant", "color", "colorIntensity", "invisible", "showZero", 'aria-label', "badgeClassName", "className"]);
535
+ // === VALIDATION: Single child element ===
536
+ const childArray = Array.isArray(children) ? children : children ? [children] : [];
537
+ if (childArray.length === 0) {
538
+ console.warn('Badge component requires a child element');
539
+ return null;
540
+ }
541
+ if (childArray.length > 1) {
542
+ console.warn('Badge component should only wrap a single child element. Using first child only.');
543
+ }
544
+ const child = childArray[0];
545
+ // === VISIBILITY LOGIC ===
546
+ // Hide badge if:
547
+ // 1. invisible prop is true, OR
548
+ // 2. For standard variant: badgeContent is undefined/null OR (badgeContent is 0 AND !showZero)
549
+ const shouldHideBadge = invisible ||
550
+ (variant === 'standard' &&
551
+ (badgeContent === undefined ||
552
+ badgeContent === null ||
553
+ (badgeContent === 0 && !showZero)));
554
+ // === BADGE CONTENT FORMATTING ===
555
+ // Apply max capping: if badgeContent > max, show "max+"
556
+ const getDisplayContent = () => {
557
+ if (variant === 'dot')
558
+ return '';
559
+ if (typeof badgeContent === 'number' && max !== undefined && badgeContent > max) {
560
+ return `${max}+`;
561
+ }
562
+ return String(badgeContent !== null && badgeContent !== void 0 ? badgeContent : '');
563
+ };
564
+ const displayContent = getDisplayContent();
565
+ // === CSS CLASS ASSEMBLY ===
566
+ // Wrapper classes
567
+ const wrapperClasses = ['badge-wrapper', className].filter(Boolean).join(' ').trim() || undefined;
568
+ // Badge element classes - using m-badge prefix to avoid Materialize conflicts
569
+ const positionClass = `m-badge--${anchorOrigin.vertical}-${anchorOrigin.horizontal}`;
570
+ const badgeClasses = [
571
+ 'm-badge',
572
+ `m-badge--${variant}`,
573
+ positionClass,
574
+ `m-badge--${overlap}`,
575
+ `m-badge--${color}`,
576
+ colorIntensity ? `m-badge--${colorIntensity}` : '',
577
+ shouldHideBadge ? 'm-badge--invisible' : '',
578
+ badgeClassName,
579
+ ]
580
+ .filter(Boolean)
581
+ .join(' ')
582
+ .trim();
583
+ // === ARIA ATTRIBUTES ===
584
+ const badgeAriaLabel = ariaLabel ||
585
+ (variant === 'dot'
586
+ ? 'notification indicator'
587
+ : displayContent
588
+ ? `${displayContent} notifications`
589
+ : 'notification badge');
590
+ // === RENDER ===
591
+ return m('.badge-wrapper', Object.assign(Object.assign({}, params), { className: wrapperClasses }), [
592
+ // Child element
593
+ child,
594
+ // Badge element - only render if not hidden
595
+ !shouldHideBadge
596
+ ? m('span', {
597
+ className: badgeClasses,
598
+ 'aria-label': badgeAriaLabel,
599
+ role: 'status',
600
+ 'aria-live': 'polite',
601
+ }, variant === 'standard' ? displayContent : null)
602
+ : null,
603
+ ]);
604
+ },
605
+ };
606
+ };
607
+
508
608
  /**
509
609
  * A simple material icon, defined by its icon name.
510
610
  *
@@ -8189,33 +8289,75 @@ class Toast {
8189
8289
  _createToast() {
8190
8290
  const toast = document.createElement('div');
8191
8291
  toast.classList.add('toast');
8192
- // Add custom classes
8193
- if (this.options.classes) {
8194
- toast.classList.add(...this.options.classes.split(' '));
8195
- }
8196
- // Set content
8292
+ // Add custom classes (prefer className over deprecated classes)
8293
+ const customClasses = this.options.className || this.options.classes;
8294
+ if (customClasses) {
8295
+ toast.classList.add(...customClasses.split(' ').filter((c) => c));
8296
+ }
8297
+ // Create content wrapper
8298
+ const contentWrapper = document.createElement('div');
8299
+ contentWrapper.style.cssText = 'display: flex; align-items: center; gap: 12px;';
8300
+ // Set message content
8301
+ const messageEl = document.createElement('div');
8302
+ messageEl.style.flex = '1';
8197
8303
  const message = this.options.html;
8198
8304
  if (typeof message === 'object' && message && 'nodeType' in message) {
8199
- toast.appendChild(message);
8305
+ messageEl.appendChild(message);
8200
8306
  }
8201
8307
  else {
8202
- toast.innerHTML = message;
8308
+ messageEl.innerHTML = message;
8309
+ }
8310
+ contentWrapper.appendChild(messageEl);
8311
+ // Add action button if provided
8312
+ if (this.options.action) {
8313
+ const action = this.options.action;
8314
+ const actionBtn = document.createElement('button');
8315
+ actionBtn.className = 'btn-flat toast-action';
8316
+ actionBtn.style.cssText = 'margin: 0; padding: 0 8px; min-width: auto; height: 36px;';
8317
+ if (action.variant === 'icon' && action.icon) {
8318
+ // Icon button variant
8319
+ actionBtn.innerHTML = `<i class="material-icons">${action.icon}</i>`;
8320
+ actionBtn.setAttribute('aria-label', action.label || action.icon);
8321
+ }
8322
+ else {
8323
+ // Flat button variant (default)
8324
+ if (action.icon) {
8325
+ actionBtn.innerHTML = `<i class="material-icons left">${action.icon}</i>${action.label || ''}`;
8326
+ }
8327
+ else {
8328
+ actionBtn.textContent = action.label || '';
8329
+ }
8330
+ }
8331
+ actionBtn.onclick = (e) => {
8332
+ e.stopPropagation();
8333
+ action.onclick();
8334
+ this.dismiss();
8335
+ };
8336
+ contentWrapper.appendChild(actionBtn);
8203
8337
  }
8338
+ toast.appendChild(contentWrapper);
8204
8339
  // Store reference
8205
8340
  toast.M_Toast = this;
8341
+ // Measure natural width BEFORE appending to avoid interference from other toasts
8342
+ // Temporarily append to body in an isolated position
8343
+ toast.style.cssText = 'position: absolute; visibility: hidden; left: -9999px; display: flex;';
8344
+ document.body.appendChild(toast);
8345
+ // Force layout and measure
8346
+ const naturalWidth = toast.offsetWidth;
8347
+ // Remove from body
8348
+ document.body.removeChild(toast);
8349
+ // Lock the width to prevent changes based on other toasts
8350
+ toast.style.cssText = `width: ${naturalWidth}px;`;
8206
8351
  // Append to container
8207
8352
  Toast._container.appendChild(toast);
8208
8353
  return toast;
8209
8354
  }
8210
8355
  _animateIn() {
8211
- // Simple CSS animation since we don't have anime.js
8212
- this.el.style.cssText = `
8213
- transform: translateY(35px);
8214
- opacity: 0;
8215
- transition: transform ${this.options.inDuration}ms cubic-bezier(0.215, 0.61, 0.355, 1),
8216
- opacity ${this.options.inDuration}ms cubic-bezier(0.215, 0.61, 0.355, 1);
8217
- `;
8218
- // Trigger animation
8356
+ // Width is already locked from _createToast
8357
+ // Set initial animation state (transitions are defined in CSS)
8358
+ this.el.style.transform = 'translateY(35px)';
8359
+ this.el.style.opacity = '0';
8360
+ // Trigger animation after a brief delay to ensure styles are applied
8219
8361
  setTimeout(() => {
8220
8362
  this.el.style.transform = 'translateY(0)';
8221
8363
  this.el.style.opacity = '1';
@@ -8239,17 +8381,34 @@ class Toast {
8239
8381
  }
8240
8382
  const activationDistance = this.el.offsetWidth * this.options.activationPercent;
8241
8383
  if (this.state.wasSwiped) {
8384
+ // Override transition temporarily for swipe
8242
8385
  this.el.style.transition = 'transform .05s, opacity .05s';
8243
8386
  this.el.style.transform = `translateX(${activationDistance}px)`;
8244
8387
  this.el.style.opacity = '0';
8388
+ // Reset transition after swipe animation
8389
+ setTimeout(() => {
8390
+ this.el.style.transition = `opacity ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8391
+ max-height ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8392
+ margin-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8393
+ padding-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8394
+ padding-bottom ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1)`;
8395
+ }, 50);
8245
8396
  }
8246
- // Animate out
8247
- this.el.style.cssText += `
8248
- transition: opacity ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8249
- margin-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1);
8250
- opacity: 0;
8251
- margin-top: -40px;
8252
- `;
8397
+ else {
8398
+ // Set collapse transition timing
8399
+ this.el.style.transition = `opacity ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8400
+ max-height ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8401
+ margin-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8402
+ padding-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8403
+ padding-bottom ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1)`;
8404
+ }
8405
+ // Animate out - collapse height smoothly
8406
+ this.el.style.opacity = '0';
8407
+ this.el.style.maxHeight = '0';
8408
+ this.el.style.marginTop = '0';
8409
+ this.el.style.paddingTop = '0';
8410
+ this.el.style.paddingBottom = '0';
8411
+ this.el.style.overflow = 'hidden';
8253
8412
  setTimeout(() => {
8254
8413
  // Call completion callback
8255
8414
  if (this.options.completeCallback) {
@@ -8278,8 +8437,10 @@ Toast.defaults = {
8278
8437
  inDuration: 300,
8279
8438
  outDuration: 375,
8280
8439
  classes: '',
8440
+ className: '',
8281
8441
  completeCallback: undefined,
8282
8442
  activationPercent: 0.8,
8443
+ action: undefined,
8283
8444
  };
8284
8445
  Toast._onDragStart = (e) => {
8285
8446
  const target = e.target;
@@ -11028,4 +11189,4 @@ const isValidationError = (result) => !isValidationSuccess(result);
11028
11189
  // ============================================================================
11029
11190
  // All types are already exported via individual export declarations above
11030
11191
 
11031
- export { AnalogClock, AnchorItem, Autocomplete, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CircularProgress, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, DataTable, DatePicker, DigitalClock, DoubleRangeSlider, Dropdown, EmailInput, FileInput, FileUpload, FlatButton, FloatingActionButton, HelperText, Icon, IconButton, ImageList, InputCheckbox, Label, LargeButton, LinearProgress, ListItem, Mandatory, Masonry, MaterialBox, MaterialIcon, ModalPanel, NumberInput, Options, OptionsList, Pagination, PaginationControls, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, Rating, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SingleRangeSlider, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, TimeRangePicker, Timeline, Toast, ToastComponent, ToggleGroup, Tooltip, TooltipComponent, TreeView, UrlInput, Wizard, addLeadingZero, clearPortal, createBreadcrumb, formatTime, generateHourOptions, generateMinuteOptions, getDropdownStyles, getPortalContainer, initPushpins, initTooltips, isNumeric, isTimeDisabled, isValidationError, isValidationSuccess, padLeft, parseTime, range, releasePortalContainer, renderToPortal, scrollToValue, snapToNearestItem, sortOptions, timeToMinutes, toast, uniqueId, uuid4 };
11192
+ export { AnalogClock, AnchorItem, Autocomplete, Badge, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CircularProgress, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, DataTable, DatePicker, DigitalClock, DoubleRangeSlider, Dropdown, EmailInput, FileInput, FileUpload, FlatButton, FloatingActionButton, HelperText, Icon, IconButton, ImageList, InputCheckbox, Label, LargeButton, LinearProgress, ListItem, Mandatory, Masonry, MaterialBox, MaterialIcon, ModalPanel, NumberInput, Options, OptionsList, Pagination, PaginationControls, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, Rating, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SingleRangeSlider, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, TimeRangePicker, Timeline, Toast, ToastComponent, ToggleGroup, Tooltip, TooltipComponent, TreeView, UrlInput, Wizard, addLeadingZero, clearPortal, createBreadcrumb, formatTime, generateHourOptions, generateMinuteOptions, getDropdownStyles, getPortalContainer, initPushpins, initTooltips, isNumeric, isTimeDisabled, isValidationError, isValidationSuccess, padLeft, parseTime, range, releasePortalContainer, renderToPortal, scrollToValue, snapToNearestItem, sortOptions, timeToMinutes, toast, uniqueId, uuid4 };
package/dist/index.js CHANGED
@@ -507,6 +507,106 @@ const Autocomplete = () => {
507
507
  };
508
508
  };
509
509
 
510
+ /**
511
+ * Badge component
512
+ *
513
+ * Displays a badge anchored to a child element. Commonly used for notifications,
514
+ * counts, or status indicators. Supports flexible positioning, colors, and variants.
515
+ *
516
+ * @example
517
+ * ```typescript
518
+ * // Basic notification badge
519
+ * m(Badge, { badgeContent: 5 },
520
+ * m('button.btn', 'Messages')
521
+ * )
522
+ *
523
+ * // Dot badge on avatar
524
+ * m(Badge, {
525
+ * variant: 'dot',
526
+ * color: 'green',
527
+ * overlap: 'circular'
528
+ * },
529
+ * m('img.circle', { src: 'avatar.jpg' })
530
+ * )
531
+ * ```
532
+ */
533
+ const Badge = () => {
534
+ return {
535
+ view: ({ attrs, children }) => {
536
+ const { badgeContent, max, anchorOrigin = { vertical: 'top', horizontal: 'right' }, overlap = 'rectangular', variant = 'standard', color = 'red', colorIntensity, invisible = false, showZero = false, 'aria-label': ariaLabel, badgeClassName = '', className = '' } = attrs, params = __rest(attrs, ["badgeContent", "max", "anchorOrigin", "overlap", "variant", "color", "colorIntensity", "invisible", "showZero", 'aria-label', "badgeClassName", "className"]);
537
+ // === VALIDATION: Single child element ===
538
+ const childArray = Array.isArray(children) ? children : children ? [children] : [];
539
+ if (childArray.length === 0) {
540
+ console.warn('Badge component requires a child element');
541
+ return null;
542
+ }
543
+ if (childArray.length > 1) {
544
+ console.warn('Badge component should only wrap a single child element. Using first child only.');
545
+ }
546
+ const child = childArray[0];
547
+ // === VISIBILITY LOGIC ===
548
+ // Hide badge if:
549
+ // 1. invisible prop is true, OR
550
+ // 2. For standard variant: badgeContent is undefined/null OR (badgeContent is 0 AND !showZero)
551
+ const shouldHideBadge = invisible ||
552
+ (variant === 'standard' &&
553
+ (badgeContent === undefined ||
554
+ badgeContent === null ||
555
+ (badgeContent === 0 && !showZero)));
556
+ // === BADGE CONTENT FORMATTING ===
557
+ // Apply max capping: if badgeContent > max, show "max+"
558
+ const getDisplayContent = () => {
559
+ if (variant === 'dot')
560
+ return '';
561
+ if (typeof badgeContent === 'number' && max !== undefined && badgeContent > max) {
562
+ return `${max}+`;
563
+ }
564
+ return String(badgeContent !== null && badgeContent !== void 0 ? badgeContent : '');
565
+ };
566
+ const displayContent = getDisplayContent();
567
+ // === CSS CLASS ASSEMBLY ===
568
+ // Wrapper classes
569
+ const wrapperClasses = ['badge-wrapper', className].filter(Boolean).join(' ').trim() || undefined;
570
+ // Badge element classes - using m-badge prefix to avoid Materialize conflicts
571
+ const positionClass = `m-badge--${anchorOrigin.vertical}-${anchorOrigin.horizontal}`;
572
+ const badgeClasses = [
573
+ 'm-badge',
574
+ `m-badge--${variant}`,
575
+ positionClass,
576
+ `m-badge--${overlap}`,
577
+ `m-badge--${color}`,
578
+ colorIntensity ? `m-badge--${colorIntensity}` : '',
579
+ shouldHideBadge ? 'm-badge--invisible' : '',
580
+ badgeClassName,
581
+ ]
582
+ .filter(Boolean)
583
+ .join(' ')
584
+ .trim();
585
+ // === ARIA ATTRIBUTES ===
586
+ const badgeAriaLabel = ariaLabel ||
587
+ (variant === 'dot'
588
+ ? 'notification indicator'
589
+ : displayContent
590
+ ? `${displayContent} notifications`
591
+ : 'notification badge');
592
+ // === RENDER ===
593
+ return m('.badge-wrapper', Object.assign(Object.assign({}, params), { className: wrapperClasses }), [
594
+ // Child element
595
+ child,
596
+ // Badge element - only render if not hidden
597
+ !shouldHideBadge
598
+ ? m('span', {
599
+ className: badgeClasses,
600
+ 'aria-label': badgeAriaLabel,
601
+ role: 'status',
602
+ 'aria-live': 'polite',
603
+ }, variant === 'standard' ? displayContent : null)
604
+ : null,
605
+ ]);
606
+ },
607
+ };
608
+ };
609
+
510
610
  /**
511
611
  * A simple material icon, defined by its icon name.
512
612
  *
@@ -8191,33 +8291,75 @@ class Toast {
8191
8291
  _createToast() {
8192
8292
  const toast = document.createElement('div');
8193
8293
  toast.classList.add('toast');
8194
- // Add custom classes
8195
- if (this.options.classes) {
8196
- toast.classList.add(...this.options.classes.split(' '));
8197
- }
8198
- // Set content
8294
+ // Add custom classes (prefer className over deprecated classes)
8295
+ const customClasses = this.options.className || this.options.classes;
8296
+ if (customClasses) {
8297
+ toast.classList.add(...customClasses.split(' ').filter((c) => c));
8298
+ }
8299
+ // Create content wrapper
8300
+ const contentWrapper = document.createElement('div');
8301
+ contentWrapper.style.cssText = 'display: flex; align-items: center; gap: 12px;';
8302
+ // Set message content
8303
+ const messageEl = document.createElement('div');
8304
+ messageEl.style.flex = '1';
8199
8305
  const message = this.options.html;
8200
8306
  if (typeof message === 'object' && message && 'nodeType' in message) {
8201
- toast.appendChild(message);
8307
+ messageEl.appendChild(message);
8202
8308
  }
8203
8309
  else {
8204
- toast.innerHTML = message;
8310
+ messageEl.innerHTML = message;
8311
+ }
8312
+ contentWrapper.appendChild(messageEl);
8313
+ // Add action button if provided
8314
+ if (this.options.action) {
8315
+ const action = this.options.action;
8316
+ const actionBtn = document.createElement('button');
8317
+ actionBtn.className = 'btn-flat toast-action';
8318
+ actionBtn.style.cssText = 'margin: 0; padding: 0 8px; min-width: auto; height: 36px;';
8319
+ if (action.variant === 'icon' && action.icon) {
8320
+ // Icon button variant
8321
+ actionBtn.innerHTML = `<i class="material-icons">${action.icon}</i>`;
8322
+ actionBtn.setAttribute('aria-label', action.label || action.icon);
8323
+ }
8324
+ else {
8325
+ // Flat button variant (default)
8326
+ if (action.icon) {
8327
+ actionBtn.innerHTML = `<i class="material-icons left">${action.icon}</i>${action.label || ''}`;
8328
+ }
8329
+ else {
8330
+ actionBtn.textContent = action.label || '';
8331
+ }
8332
+ }
8333
+ actionBtn.onclick = (e) => {
8334
+ e.stopPropagation();
8335
+ action.onclick();
8336
+ this.dismiss();
8337
+ };
8338
+ contentWrapper.appendChild(actionBtn);
8205
8339
  }
8340
+ toast.appendChild(contentWrapper);
8206
8341
  // Store reference
8207
8342
  toast.M_Toast = this;
8343
+ // Measure natural width BEFORE appending to avoid interference from other toasts
8344
+ // Temporarily append to body in an isolated position
8345
+ toast.style.cssText = 'position: absolute; visibility: hidden; left: -9999px; display: flex;';
8346
+ document.body.appendChild(toast);
8347
+ // Force layout and measure
8348
+ const naturalWidth = toast.offsetWidth;
8349
+ // Remove from body
8350
+ document.body.removeChild(toast);
8351
+ // Lock the width to prevent changes based on other toasts
8352
+ toast.style.cssText = `width: ${naturalWidth}px;`;
8208
8353
  // Append to container
8209
8354
  Toast._container.appendChild(toast);
8210
8355
  return toast;
8211
8356
  }
8212
8357
  _animateIn() {
8213
- // Simple CSS animation since we don't have anime.js
8214
- this.el.style.cssText = `
8215
- transform: translateY(35px);
8216
- opacity: 0;
8217
- transition: transform ${this.options.inDuration}ms cubic-bezier(0.215, 0.61, 0.355, 1),
8218
- opacity ${this.options.inDuration}ms cubic-bezier(0.215, 0.61, 0.355, 1);
8219
- `;
8220
- // Trigger animation
8358
+ // Width is already locked from _createToast
8359
+ // Set initial animation state (transitions are defined in CSS)
8360
+ this.el.style.transform = 'translateY(35px)';
8361
+ this.el.style.opacity = '0';
8362
+ // Trigger animation after a brief delay to ensure styles are applied
8221
8363
  setTimeout(() => {
8222
8364
  this.el.style.transform = 'translateY(0)';
8223
8365
  this.el.style.opacity = '1';
@@ -8241,17 +8383,34 @@ class Toast {
8241
8383
  }
8242
8384
  const activationDistance = this.el.offsetWidth * this.options.activationPercent;
8243
8385
  if (this.state.wasSwiped) {
8386
+ // Override transition temporarily for swipe
8244
8387
  this.el.style.transition = 'transform .05s, opacity .05s';
8245
8388
  this.el.style.transform = `translateX(${activationDistance}px)`;
8246
8389
  this.el.style.opacity = '0';
8390
+ // Reset transition after swipe animation
8391
+ setTimeout(() => {
8392
+ this.el.style.transition = `opacity ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8393
+ max-height ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8394
+ margin-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8395
+ padding-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8396
+ padding-bottom ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1)`;
8397
+ }, 50);
8247
8398
  }
8248
- // Animate out
8249
- this.el.style.cssText += `
8250
- transition: opacity ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8251
- margin-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1);
8252
- opacity: 0;
8253
- margin-top: -40px;
8254
- `;
8399
+ else {
8400
+ // Set collapse transition timing
8401
+ this.el.style.transition = `opacity ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8402
+ max-height ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8403
+ margin-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8404
+ padding-top ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1),
8405
+ padding-bottom ${this.options.outDuration}ms cubic-bezier(0.165, 0.84, 0.44, 1)`;
8406
+ }
8407
+ // Animate out - collapse height smoothly
8408
+ this.el.style.opacity = '0';
8409
+ this.el.style.maxHeight = '0';
8410
+ this.el.style.marginTop = '0';
8411
+ this.el.style.paddingTop = '0';
8412
+ this.el.style.paddingBottom = '0';
8413
+ this.el.style.overflow = 'hidden';
8255
8414
  setTimeout(() => {
8256
8415
  // Call completion callback
8257
8416
  if (this.options.completeCallback) {
@@ -8280,8 +8439,10 @@ Toast.defaults = {
8280
8439
  inDuration: 300,
8281
8440
  outDuration: 375,
8282
8441
  classes: '',
8442
+ className: '',
8283
8443
  completeCallback: undefined,
8284
8444
  activationPercent: 0.8,
8445
+ action: undefined,
8285
8446
  };
8286
8447
  Toast._onDragStart = (e) => {
8287
8448
  const target = e.target;
@@ -11033,6 +11194,7 @@ const isValidationError = (result) => !isValidationSuccess(result);
11033
11194
  exports.AnalogClock = AnalogClock;
11034
11195
  exports.AnchorItem = AnchorItem;
11035
11196
  exports.Autocomplete = Autocomplete;
11197
+ exports.Badge = Badge;
11036
11198
  exports.Breadcrumb = Breadcrumb;
11037
11199
  exports.BreadcrumbManager = BreadcrumbManager;
11038
11200
  exports.Button = Button;