@dynamic-framework/ui-react 2.7.0 → 2.9.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.
Files changed (58) hide show
  1. package/dist/css/dynamic-ui.css +276 -22
  2. package/dist/css/dynamic-ui.min.css +2 -2
  3. package/dist/index.esm.js +677 -298
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +683 -297
  6. package/dist/index.js.map +1 -1
  7. package/dist/types/components/DDropdown/DDropdown.d.ts +10 -2
  8. package/dist/types/components/DInputCheck/DInputCheck.d.ts +1 -0
  9. package/dist/types/components/DInputSwitch/DInputSwitch.d.ts +2 -1
  10. package/dist/types/components/DModal/components/DModalHeader.d.ts +5 -1
  11. package/dist/types/components/DOffcanvas/components/DOffcanvasHeader.d.ts +5 -1
  12. package/dist/types/components/DOtp/DOtp.d.ts +1 -0
  13. package/dist/types/components/DOtp/components/OtpCountdown.d.ts +3 -2
  14. package/dist/types/components/DTooltip/DTooltip.d.ts +38 -3
  15. package/dist/types/components/DVoucher/DVoucher.d.ts +3 -1
  16. package/dist/types/components/DVoucher/hooks/useScreenshotDownload.d.ts +1 -1
  17. package/dist/types/components/DVoucher/hooks/useScreenshotDownload.spec.d.ts +1 -0
  18. package/dist/types/components/DVoucher/hooks/useScreenshotWebShare.d.ts +1 -1
  19. package/dist/types/components/DVoucher/hooks/useScreenshotWebShare.spec.d.ts +1 -0
  20. package/dist/types/components/DVoucher/index.d.ts +3 -0
  21. package/dist/types/components/index.d.ts +1 -1
  22. package/dist/types/hooks/index.d.ts +3 -0
  23. package/dist/types/hooks/tests/useCountdown.spec.d.ts +1 -0
  24. package/dist/types/hooks/useCountdown.d.ts +14 -0
  25. package/dist/types/hooks/useInputCurrency.d.ts +1 -6
  26. package/dist/types/hooks/useOtp.d.ts +98 -0
  27. package/dist/types/utils/buildUrl.d.ts +32 -0
  28. package/dist/types/utils/index.d.ts +2 -0
  29. package/dist/types/utils/sanitizeHref.d.ts +37 -0
  30. package/dist/types/utils/tests/buildUrl.spec.d.ts +1 -0
  31. package/dist/types/utils/tests/sanitizeHref.spec.d.ts +1 -0
  32. package/package.json +9 -6
  33. package/src/style/_shame.scss +1 -5
  34. package/src/style/abstracts/variables/_+import.scss +2 -0
  35. package/src/style/abstracts/variables/_box.scss +7 -0
  36. package/src/style/abstracts/variables/_forms.scss +1 -3
  37. package/src/style/abstracts/variables/_input-currency.scss +1 -0
  38. package/src/style/abstracts/variables/_shadow.scss +12 -1
  39. package/src/style/base/_+import.scss +0 -1
  40. package/src/style/base/_form-check.scss +4 -2
  41. package/src/style/components/_+import.scss +7 -0
  42. package/src/style/components/_d-box-file.scss +5 -0
  43. package/src/style/components/_d-box.scss +5 -5
  44. package/src/style/components/_d-close.scss +1 -0
  45. package/src/style/components/_d-confirm-modal.scss +17 -0
  46. package/src/style/components/_d-data-state-wrapper.scss +47 -0
  47. package/src/style/components/_d-datepicker.scss +11 -0
  48. package/src/style/components/_d-error-boundary.scss +7 -0
  49. package/src/style/components/_d-input-currency.scss +5 -0
  50. package/src/style/components/_d-otp.scss +54 -0
  51. package/src/style/components/_d-password-strength-meter.scss +76 -0
  52. package/src/style/components/_d-popover.scss +4 -0
  53. package/src/style/components/_d-stepper.scss +8 -0
  54. package/src/style/components/_d-tabs.scss +18 -0
  55. package/src/style/components/_d-voucher.scss +30 -0
  56. package/dist/types/components/DOtp/DOtpspec.d.ts +0 -0
  57. package/dist/types/components/DOtp/hooks/useCountdown.d.ts +0 -4
  58. package/src/style/base/_form-text.scss +0 -12
package/dist/index.esm.js CHANGED
@@ -563,12 +563,12 @@ function DIcon(_a) {
563
563
  return (jsx(DIconBase, Object.assign({ icon: resolvedIcon, familyClass: propFamilyClass !== null && propFamilyClass !== void 0 ? propFamilyClass : familyClass, familyPrefix: propFamilyPrefix !== null && propFamilyPrefix !== void 0 ? propFamilyPrefix : familyPrefix, materialStyle: propMaterialStyle !== null && propMaterialStyle !== void 0 ? propMaterialStyle : materialStyle }, props)));
564
564
  }
565
565
 
566
- function DAlert({ color = 'success', icon: iconProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle = false, iconClose: iconCloseProp, iconCloseFamilyClass, iconCloseFamilyPrefix, iconCloseMaterialStyle = false, showClose, onClose, children, id, className, style, dataAttributes, }) {
567
- const { iconMap: { alert, xLg, }, } = useDContext();
566
+ function DAlert({ color = 'success', icon: iconProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle, iconClose: iconCloseProp, iconCloseFamilyClass, iconCloseFamilyPrefix, iconCloseMaterialStyle, showClose, onClose, children, id, className, style, dataAttributes, }) {
567
+ const { icon: { materialStyle, familyClass, familyPrefix, }, iconMap: { alert, xLg, }, } = useDContext();
568
568
  const icon = useMemo(() => iconProp || alert[color], [alert, iconProp, color]);
569
569
  const iconClose = useMemo(() => (iconCloseProp || xLg), [iconCloseProp, xLg]);
570
570
  const generateClasses = useMemo(() => (Object.assign({ alert: true, [`alert-${color}`]: true, 'fade show': !!showClose }, className && { [className]: true })), [color, showClose, className]);
571
- return (jsxs("div", Object.assign({ className: classNames(generateClasses), style: style, role: "alert", id: id }, dataAttributes, { children: [icon && (jsx(DIcon, { className: "alert-icon", icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })), jsx("div", { className: "alert-text", children: children }), showClose && (jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: onClose, children: jsx(DIcon, { icon: iconClose, familyClass: iconCloseFamilyClass, familyPrefix: iconCloseFamilyPrefix, materialStyle: iconCloseMaterialStyle }) }))] })));
571
+ return (jsxs("div", Object.assign({ className: classNames(generateClasses), style: style, role: "alert", id: id }, dataAttributes, { children: [icon && (jsx(DIcon, { className: "alert-icon", icon: icon, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyle })), jsx("div", { className: "alert-text", children: children }), showClose && (jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: onClose, children: jsx(DIcon, { icon: iconClose, familyClass: iconCloseFamilyClass !== null && iconCloseFamilyClass !== void 0 ? iconCloseFamilyClass : familyClass, familyPrefix: iconCloseFamilyPrefix !== null && iconCloseFamilyPrefix !== void 0 ? iconCloseFamilyPrefix : familyPrefix, materialStyle: iconCloseMaterialStyle !== null && iconCloseMaterialStyle !== void 0 ? iconCloseMaterialStyle : materialStyle }) }))] })));
572
572
  }
573
573
 
574
574
  function DAvatar({ id, size, image, name: nameProp, useNameAsInitials = false, className, style, dataAttributes, }) {
@@ -590,6 +590,7 @@ function DAvatar({ id, size, image, name: nameProp, useNameAsInitials = false, c
590
590
 
591
591
  function DBadge(props) {
592
592
  const { text, soft = false, color = 'primary', id, rounded, className, size, style, iconStart, iconEnd, iconMaterialStyle, iconFamilyClass, iconFamilyPrefix, dataAttributes, } = props;
593
+ const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
593
594
  // Responsive size resolution using useResponsiveProp
594
595
  const { responsivePropValue } = useResponsiveProp(true);
595
596
  const resolvedSize = useMemo(() => {
@@ -606,7 +607,7 @@ function DBadge(props) {
606
607
  'rounded-pill': !!rounded,
607
608
  [`badge-${resolvedSize}`]: !!resolvedSize,
608
609
  }), [rounded, soft, color, resolvedSize]);
609
- return (jsxs("span", Object.assign({ className: classNames(generateClasses, className), style: style }, id && { id }, dataAttributes, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })), jsx("span", { children: text }), iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle }))] })));
610
+ return (jsxs("span", Object.assign({ className: classNames(generateClasses, className), style: style }, id && { id }, dataAttributes, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyle })), jsx("span", { children: text }), iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyle }))] })));
610
611
  }
611
612
 
612
613
  function DBox({ className, style, children, dataAttributes, }) {
@@ -638,6 +639,7 @@ function DInput(_a, ref) {
638
639
  const inputRef = useProvidedRefOrCreate(ref);
639
640
  const innerId = useId();
640
641
  const id = useMemo(() => idProp || innerId, [idProp, innerId]);
642
+ const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
641
643
  const handleOnChange = useCallback((event) => {
642
644
  onChange === null || onChange === void 0 ? void 0 : onChange(event.currentTarget.value);
643
645
  }, [onChange]);
@@ -700,7 +702,7 @@ function DInput(_a, ref) {
700
702
  [`input-group-${size}`]: !!size,
701
703
  'input-group': true,
702
704
  'has-validation': invalid || valid,
703
- }), children: [!!inputStart && (jsx("div", { className: "input-group-text", id: `${id}InputStart`, children: inputStart })), iconStart && (onIconStartClick ? (jsx("button", { type: "button", className: "input-group-text", id: `${id}Start`, onClick: handleOnIconStartClick, disabled: disabled || loading || iconStartDisabled, "aria-label": iconStartAriaLabel || (typeof iconStart === 'string' ? iconStart : 'start icon'), tabIndex: iconStartTabIndex, children: jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle }) })) : (jsx("div", { className: "input-group-text", id: `${id}Start`, "aria-hidden": "true", tabIndex: -1, children: jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle }) }))), dynamicComponent, (iconEnd && !loading) && (onIconEndClick ? (jsx("button", { type: "button", className: "input-group-text", id: `${id}End`, onClick: handleOnIconEndClick, disabled: disabled || loading || iconEndDisabled, "aria-label": iconEndAriaLabel || (typeof iconEnd === 'string' ? iconEnd : 'end icon'), tabIndex: iconEndTabIndex, children: jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }) })) : (jsx("div", { className: "input-group-text", id: `${id}End`, "aria-hidden": "true", tabIndex: -1, children: jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }) }))), loading && (jsx("div", { className: "input-group-text", id: `${id}Loading`, children: jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", "data-testid": "loading-spinner", children: jsx("span", { className: "visually-hidden", children: "Loading..." }) }) })), !!inputEnd && (jsx("div", { className: "input-group-text", id: `${id}InputEnd`, children: inputEnd }))] }), hint && (jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
705
+ }), children: [!!inputStart && (jsx("div", { className: "input-group-text", id: `${id}InputStart`, children: inputStart })), iconStart && (onIconStartClick ? (jsx("button", { type: "button", className: "input-group-text", id: `${id}Start`, onClick: handleOnIconStartClick, disabled: disabled || loading || iconStartDisabled, "aria-label": iconStartAriaLabel || (typeof iconStart === 'string' ? iconStart : 'start icon'), tabIndex: iconStartTabIndex, children: jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass !== null && iconStartFamilyClass !== void 0 ? iconStartFamilyClass : familyClass, familyPrefix: iconStartFamilyPrefix !== null && iconStartFamilyPrefix !== void 0 ? iconStartFamilyPrefix : familyPrefix, materialStyle: iconStartMaterialStyle !== null && iconStartMaterialStyle !== void 0 ? iconStartMaterialStyle : materialStyle }) })) : (jsx("div", { className: "input-group-text", id: `${id}Start`, "aria-hidden": "true", tabIndex: -1, children: jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass !== null && iconStartFamilyClass !== void 0 ? iconStartFamilyClass : familyClass, familyPrefix: iconStartFamilyPrefix !== null && iconStartFamilyPrefix !== void 0 ? iconStartFamilyPrefix : familyPrefix, materialStyle: iconStartMaterialStyle !== null && iconStartMaterialStyle !== void 0 ? iconStartMaterialStyle : materialStyle }) }))), dynamicComponent, (iconEnd && !loading) && (onIconEndClick ? (jsx("button", { type: "button", className: "input-group-text", id: `${id}End`, onClick: handleOnIconEndClick, disabled: disabled || loading || iconEndDisabled, "aria-label": iconEndAriaLabel || (typeof iconEnd === 'string' ? iconEnd : 'end icon'), tabIndex: iconEndTabIndex, children: jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass !== null && iconEndFamilyClass !== void 0 ? iconEndFamilyClass : familyClass, familyPrefix: iconEndFamilyPrefix !== null && iconEndFamilyPrefix !== void 0 ? iconEndFamilyPrefix : familyPrefix, materialStyle: iconEndMaterialStyle !== null && iconEndMaterialStyle !== void 0 ? iconEndMaterialStyle : materialStyle }) })) : (jsx("div", { className: "input-group-text", id: `${id}End`, "aria-hidden": "true", tabIndex: -1, children: jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass !== null && iconEndFamilyClass !== void 0 ? iconEndFamilyClass : familyClass, familyPrefix: iconEndFamilyPrefix !== null && iconEndFamilyPrefix !== void 0 ? iconEndFamilyPrefix : familyPrefix, materialStyle: iconEndMaterialStyle !== null && iconEndMaterialStyle !== void 0 ? iconEndMaterialStyle : materialStyle }) }))), loading && (jsx("div", { className: "input-group-text", id: `${id}Loading`, children: jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", "data-testid": "loading-spinner", children: jsx("span", { className: "visually-hidden", children: "Loading..." }) }) })), !!inputEnd && (jsx("div", { className: "input-group-text", id: `${id}InputEnd`, children: inputEnd }))] }), hint && (jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
704
706
  }
705
707
  const ForwardedDInput = forwardRef(DInput);
706
708
  ForwardedDInput.displayName = 'DInput';
@@ -1096,7 +1098,7 @@ function useDBoxFile(props) {
1096
1098
 
1097
1099
  function DBoxFile(_a) {
1098
1100
  var { icon: iconProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle, children, className, style, dataAttributes } = _a, props = __rest(_a, ["icon", "iconFamilyClass", "iconFamilyPrefix", "iconMaterialStyle", "children", "className", "style", "dataAttributes"]);
1099
- const { iconMap: { upload } } = useDContext();
1101
+ const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { upload }, } = useDContext();
1100
1102
  const icon = useMemo(() => iconProp || upload, [iconProp, upload]);
1101
1103
  const { inputRef, rootRef, isDragValid, isDragInvalid, acceptAttr, files, handleFileSelect, handleDrop, handleDragEnter, handleDragLeave, handleClick, handleKeyDown, handleRemoveFile, openFileDialog, } = useDBoxFile(props);
1102
1104
  return (jsxs(Fragment, { children: [jsx("section", Object.assign({ className: classNames('d-box-file', {
@@ -1104,13 +1106,14 @@ function DBoxFile(_a) {
1104
1106
  'd-box-file-disabled': props.disabled,
1105
1107
  'd-box-file-valid': isDragValid,
1106
1108
  'd-box-file-invalid': isDragInvalid,
1107
- }, className), style: style }, dataAttributes, { children: jsxs("div", Object.assign({ className: "d-box-file-dropzone", ref: rootRef, onDragEnter: handleDragEnter, onDragOver: (e) => e.preventDefault(), onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: handleClick, onKeyDown: handleKeyDown }, (!props.disabled && !props.noKeyboard ? { tabIndex: 0 } : {}), { role: "presentation", children: [jsx("input", { type: "file", multiple: props.multiple, style: { display: 'none' }, ref: inputRef, disabled: props.disabled, onChange: handleFileSelect, onClick: (e) => e.stopPropagation(), tabIndex: -1, accept: acceptAttr }), icon && iconProp !== false && (jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })), jsx("div", { className: "d-box-content", children: typeof children === 'function'
1109
+ }, className), style: style }, dataAttributes, { children: jsxs("div", Object.assign({ className: "d-box-file-dropzone", ref: rootRef, onDragEnter: handleDragEnter, onDragOver: (e) => e.preventDefault(), onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: handleClick, onKeyDown: handleKeyDown }, (!props.disabled && !props.noKeyboard ? { tabIndex: 0 } : {}), { role: "presentation", children: [jsx("input", { type: "file", multiple: props.multiple, style: { display: 'none' }, ref: inputRef, disabled: props.disabled, onChange: handleFileSelect, onClick: (e) => e.stopPropagation(), tabIndex: -1, accept: acceptAttr }), icon && iconProp !== false && (jsx(DIcon, { icon: icon, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyle })), jsx("div", { className: "d-box-content", children: typeof children === 'function'
1108
1110
  ? children(openFileDialog)
1109
- : children || (jsx("p", { className: "text-center m-0", children: "Drag and drop some files here, or click to select files" })) })] })) })), !!files.length && (jsx("ul", { className: "d-box-files", children: files.map((file, index) => (jsx(ForwardedDInput, { value: file.name, iconStart: "Paperclip", iconEnd: "Trash", readOnly: true, onIconEndClick: () => handleRemoveFile(index) }, `${file.name} ${index}`))) }))] }));
1111
+ : children || (jsx("p", { className: "d-box-file-empty-text", children: "Drag and drop some files here, or click to select files" })) })] })) })), !!files.length && (jsx("ul", { className: "d-box-files", children: files.map((file, index) => (jsx(ForwardedDInput, { value: file.name, iconStart: "Paperclip", iconEnd: "Trash", readOnly: true, onIconEndClick: () => handleRemoveFile(index) }, `${file.name} ${index}`))) }))] }));
1110
1112
  }
1111
1113
 
1112
1114
  const DButton = forwardRef((props, ref) => {
1113
1115
  const { color = 'primary', size, variant = 'solid', text, children, iconStart, iconStartFamilyClass, iconStartFamilyPrefix, iconStartMaterialStyle, iconEnd, iconEndFamilyClass, iconEndFamilyPrefix, iconEndMaterialStyle, loading = false, loadingText, loadingAriaLabel, disabled = false, className, style, dataAttributes, onClick, type = 'button', target, rel, href, 'aria-label': ariaLabelProp } = props, rest = __rest(props, ["color", "size", "variant", "text", "children", "iconStart", "iconStartFamilyClass", "iconStartFamilyPrefix", "iconStartMaterialStyle", "iconEnd", "iconEndFamilyClass", "iconEndFamilyPrefix", "iconEndMaterialStyle", "loading", "loadingText", "loadingAriaLabel", "disabled", "className", "style", "dataAttributes", "onClick", "type", "target", "rel", "href", 'aria-label']);
1116
+ const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
1114
1117
  // Responsive size resolution using useResponsiveProp
1115
1118
  const { responsivePropValue } = useResponsiveProp(true);
1116
1119
  const resolvedSize = useMemo(() => {
@@ -1164,7 +1167,7 @@ const DButton = forwardRef((props, ref) => {
1164
1167
  ref.current = node;
1165
1168
  }, className: classNames(classes, className), style: Object.assign(Object.assign({}, style), (loading && buttonWidth
1166
1169
  ? { minWidth: `${buttonWidth}px` }
1167
- : undefined)), "aria-label": ariaLabel, "aria-busy": loading, "aria-disabled": isDisabled, onClick: handleClick }, dataAttributes, { children: [loading && (jsxs("span", { className: "btn-loading", children: [jsx("span", { className: "spinner-border spinner-border-sm", "aria-hidden": "true" }), loadingText && jsx("span", { role: "status", children: loadingText })] })), !loading && (jsxs(Fragment, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle })), content, iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }))] }))] })));
1170
+ : undefined)), "aria-label": ariaLabel, "aria-busy": loading, "aria-disabled": isDisabled, onClick: handleClick }, dataAttributes, { children: [loading && (jsxs("span", { className: "btn-loading", children: [jsx("span", { className: "spinner-border spinner-border-sm", "aria-hidden": "true" }), loadingText && jsx("span", { role: "status", children: loadingText })] })), !loading && (jsxs(Fragment, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass !== null && iconStartFamilyClass !== void 0 ? iconStartFamilyClass : familyClass, familyPrefix: iconStartFamilyPrefix !== null && iconStartFamilyPrefix !== void 0 ? iconStartFamilyPrefix : familyPrefix, materialStyle: iconStartMaterialStyle !== null && iconStartMaterialStyle !== void 0 ? iconStartMaterialStyle : materialStyle })), content, iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass !== null && iconEndFamilyClass !== void 0 ? iconEndFamilyClass : familyClass, familyPrefix: iconEndFamilyPrefix !== null && iconEndFamilyPrefix !== void 0 ? iconEndFamilyPrefix : familyPrefix, materialStyle: iconEndMaterialStyle !== null && iconEndMaterialStyle !== void 0 ? iconEndMaterialStyle : materialStyle }))] }))] })));
1168
1171
  }
1169
1172
  return (jsxs("button", Object.assign({ ref: (node) => {
1170
1173
  buttonRef.current = node;
@@ -1178,12 +1181,13 @@ const DButton = forwardRef((props, ref) => {
1178
1181
  // eslint-disable-next-line react/button-has-type
1179
1182
  type: type, className: classNames(classes, className), style: Object.assign(Object.assign({}, style), (loading && buttonWidth
1180
1183
  ? { minWidth: `${buttonWidth}px` }
1181
- : undefined)), disabled: isDisabled, "aria-label": ariaLabel, "aria-busy": loading, "aria-disabled": isDisabled, onClick: handleClick }, dataAttributes, rest, { children: [loading && (jsxs("span", { className: "btn-loading", children: [jsx("span", { className: "spinner-border spinner-border-sm", "aria-hidden": "true" }), loadingText && jsx("span", { role: "status", children: loadingText })] })), !loading && (jsxs(Fragment, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle })), content, iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }))] }))] })));
1184
+ : undefined)), disabled: isDisabled, "aria-label": ariaLabel, "aria-busy": loading, "aria-disabled": isDisabled, onClick: handleClick }, dataAttributes, rest, { children: [loading && (jsxs("span", { className: "btn-loading", children: [jsx("span", { className: "spinner-border spinner-border-sm", "aria-hidden": "true" }), loadingText && jsx("span", { role: "status", children: loadingText })] })), !loading && (jsxs(Fragment, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass !== null && iconStartFamilyClass !== void 0 ? iconStartFamilyClass : familyClass, familyPrefix: iconStartFamilyPrefix !== null && iconStartFamilyPrefix !== void 0 ? iconStartFamilyPrefix : familyPrefix, materialStyle: iconStartMaterialStyle !== null && iconStartMaterialStyle !== void 0 ? iconStartMaterialStyle : materialStyle })), content, iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass !== null && iconEndFamilyClass !== void 0 ? iconEndFamilyClass : familyClass, familyPrefix: iconEndFamilyPrefix !== null && iconEndFamilyPrefix !== void 0 ? iconEndFamilyPrefix : familyPrefix, materialStyle: iconEndMaterialStyle !== null && iconEndMaterialStyle !== void 0 ? iconEndMaterialStyle : materialStyle }))] }))] })));
1182
1185
  });
1183
1186
  DButton.displayName = 'DButton';
1184
1187
 
1185
1188
  function DButtonIcon(_a) {
1186
1189
  var { id, icon, size, className, variant, state, loadingAriaLabel, iconMaterialStyle, disabled = false, color = 'primary', loading = false, href, target, rel, stopPropagationEnabled = true, style, iconFamilyClass, iconFamilyPrefix, dataAttributes, onClick, 'aria-label': ariaLabelProp } = _a, rest = __rest(_a, ["id", "icon", "size", "className", "variant", "state", "loadingAriaLabel", "iconMaterialStyle", "disabled", "color", "loading", "href", "target", "rel", "stopPropagationEnabled", "style", "iconFamilyClass", "iconFamilyPrefix", "dataAttributes", "onClick", 'aria-label']);
1190
+ const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
1187
1191
  const generateClasses = useMemo(() => {
1188
1192
  const variantClass = !variant || variant === 'solid'
1189
1193
  ? `btn-${color}`
@@ -1207,11 +1211,11 @@ function DButtonIcon(_a) {
1207
1211
  if (href) {
1208
1212
  return (jsx("a", Object.assign({ id: id, href: href, target: target, rel: rel, className: classNames(generateClasses, className), style: style, onClick: clickHandler, "aria-label": ariaLabel, "aria-disabled": isDisabled }, dataAttributes, { children: loading
1209
1213
  ? (jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsx("span", { className: "visually-hidden", children: "Loading..." }) }))
1210
- : (jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })) })));
1214
+ : (jsx(DIcon, { icon: icon, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyle })) })));
1211
1215
  }
1212
1216
  return (jsx("button", Object.assign({ className: classNames(generateClasses, className), style: style, disabled: state === 'disabled' || loading, onClick: clickHandler, "aria-label": ariaLabel }, dataAttributes, rest, { children: loading
1213
1217
  ? (jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsx("span", { className: "visually-hidden", children: "Loading..." }) }))
1214
- : (jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })) })));
1218
+ : (jsx(DIcon, { icon: icon, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyle })) })));
1215
1219
  }
1216
1220
 
1217
1221
  function DCardHeader({ className, style, children, }) {
@@ -1274,12 +1278,12 @@ function DChip({ color = 'primary', text, icon, iconFamilyClass, iconFamilyPrefi
1274
1278
  'd-chip': true,
1275
1279
  [`d-chip-${color}`]: !!color,
1276
1280
  }), [color]);
1277
- const { iconMap: { xLg, }, } = useDContext();
1281
+ const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { xLg, }, } = useDContext();
1278
1282
  const iconClose = useMemo(() => iconCloseProp || xLg, [iconCloseProp, xLg]);
1279
- return (jsxs("span", Object.assign({ className: classNames(generateClasses, className), style: style }, dataAttributes, { children: [icon && (jsx("div", { className: "d-chip-icon-container", children: jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle }) })), jsx("span", { children: text }), showClose && (jsx("button", { type: "button", className: "d-chip-icon-container", onClick: onClose, "aria-label": closeAriaLabel, children: jsx(DIcon, { icon: iconClose, familyClass: iconCloseFamilyClass, familyPrefix: iconCloseFamilyPrefix, materialStyle: iconCloseMaterialStyle }) }))] })));
1283
+ return (jsxs("span", Object.assign({ className: classNames(generateClasses, className), style: style }, dataAttributes, { children: [icon && (jsx("div", { className: "d-chip-icon-container", children: jsx(DIcon, { icon: icon, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyle }) })), jsx("span", { children: text }), showClose && (jsx("button", { type: "button", className: "d-chip-icon-container", onClick: onClose, "aria-label": closeAriaLabel, children: jsx(DIcon, { icon: iconClose, familyClass: iconCloseFamilyClass !== null && iconCloseFamilyClass !== void 0 ? iconCloseFamilyClass : familyClass, familyPrefix: iconCloseFamilyPrefix !== null && iconCloseFamilyPrefix !== void 0 ? iconCloseFamilyPrefix : familyPrefix, materialStyle: iconCloseMaterialStyle !== null && iconCloseMaterialStyle !== void 0 ? iconCloseMaterialStyle : materialStyle }) }))] })));
1280
1284
  }
1281
1285
 
1282
- function DCollapse({ id, className, style, Component, defaultCollapsed = true, onChange, children, iconOpen: iconOpenProp, iconClose: iconCloseProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle = false, dataAttributes, }) {
1286
+ function DCollapse({ id, className, style, Component, defaultCollapsed = true, onChange, children, iconOpen: iconOpenProp, iconClose: iconCloseProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle, dataAttributes, }) {
1283
1287
  const [collapsed, setCollapsed] = useState(defaultCollapsed);
1284
1288
  const onChangeCollapse = () => {
1285
1289
  setCollapsed((prev) => {
@@ -1293,10 +1297,10 @@ function DCollapse({ id, className, style, Component, defaultCollapsed = true, o
1293
1297
  useEffect(() => {
1294
1298
  setCollapsed(defaultCollapsed);
1295
1299
  }, [defaultCollapsed]);
1296
- const { iconMap: { chevronDown, chevronUp, }, } = useDContext();
1300
+ const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { chevronDown, chevronUp, }, } = useDContext();
1297
1301
  const iconOpen = useMemo(() => iconOpenProp || chevronDown, [chevronDown, iconOpenProp]);
1298
1302
  const iconClose = useMemo(() => iconCloseProp || chevronUp, [chevronUp, iconCloseProp]);
1299
- return (jsxs("div", Object.assign({ id: id, className: classNames('collapse-container', className), style: style }, dataAttributes, { children: [jsxs("button", { className: "collapse-button", type: "button", onClick: onChangeCollapse, children: [jsx("div", { className: "flex-grow-1", children: Component }), jsx(DIcon, { color: "primary", size: "1.25rem", icon: collapsed ? iconOpen : iconClose, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })] }), jsx("div", { className: classNames('collapse-body-wrapper', {
1303
+ return (jsxs("div", Object.assign({ id: id, className: classNames('collapse-container', className), style: style }, dataAttributes, { children: [jsxs("button", { className: "collapse-button", type: "button", onClick: onChangeCollapse, children: [jsx("div", { className: "flex-grow-1", children: Component }), jsx(DIcon, { className: "collapse-icon", color: "primary", size: "1.25rem", icon: collapsed ? iconOpen : iconClose, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyle })] }), jsx("div", { className: classNames('collapse-body-wrapper', {
1300
1304
  show: !collapsed,
1301
1305
  }), children: jsx("div", { className: "collapse-body", children: children }) })] })));
1302
1306
  }
@@ -1482,9 +1486,9 @@ function DDatePickerHeaderSelector({ date, changeYear, changeMonth, decreaseMont
1482
1486
  return (jsxs("div", { className: classNames('react-datepicker__header-selector react-datepicker__header-year-selector', className), style: style, children: [jsx(DButtonIcon, { icon: iconPrev || chevronLeft, size: iconSize, variant: "link", onClick: decreaseYear, disabled: prevYearButtonDisabled, "aria-label": prevYearAriaLabel, className: "header-button" }), jsx("p", { children: `${startYear} - ${endYear}` }), jsx(DButtonIcon, { icon: iconNext || chevronRight, size: iconSize, variant: "link", onClick: increaseYear, disabled: nextYearButtonDisabled, "aria-label": nextYearAriaLabel, className: "header-button" })] }));
1483
1487
  }
1484
1488
  if (pickerType === PickerType.Quarter || pickerType === PickerType.Month) {
1485
- return (jsxs("div", { className: classNames(`react-datepicker__header-selector react-datepicker__header-${pickerType}-selector`, className), style: style, children: [jsx(DButtonIcon, { icon: iconPrev || chevronLeft, size: iconSize, variant: "link", onClick: decreaseYear, disabled: prevMonthButtonDisabled, "aria-label": prevMonthAriaLabel, className: "header-button", style: { visibility: customHeaderCount === 0 ? 'visible' : 'hidden' } }), jsx("div", { className: "d-flex justify-content-center flex-grow-1", children: showHeaderSelectors ? (jsx(DSelect$1, { options: years, value: defaultYear, defaultValue: defaultYear, onChange: (year) => changeYear(Number(year === null || year === void 0 ? void 0 : year.value)), searchable: false })) : (jsx("p", { children: defaultYear === null || defaultYear === void 0 ? void 0 : defaultYear.label })) }), jsx(DButtonIcon, { icon: iconNext || chevronRight, size: iconSize, variant: "link", onClick: increaseYear, disabled: nextMonthButtonDisabled, "aria-label": nextMonthAriaLabel, className: "header-button", style: { visibility: customHeaderCount === monthsShown - 1 ? 'visible' : 'hidden' } })] }));
1489
+ return (jsxs("div", { className: classNames(`react-datepicker__header-selector react-datepicker__header-${pickerType}-selector`, className), style: style, children: [jsx(DButtonIcon, { icon: iconPrev || chevronLeft, size: iconSize, variant: "link", onClick: decreaseYear, disabled: prevMonthButtonDisabled, "aria-label": prevMonthAriaLabel, className: "header-button", style: { visibility: customHeaderCount === 0 ? 'visible' : 'hidden' } }), jsx("div", { className: "react-datepicker__header-year-selector", children: showHeaderSelectors ? (jsx(DSelect$1, { options: years, value: defaultYear, defaultValue: defaultYear, onChange: (year) => changeYear(Number(year === null || year === void 0 ? void 0 : year.value)), searchable: false })) : (jsx("p", { children: defaultYear === null || defaultYear === void 0 ? void 0 : defaultYear.label })) }), jsx(DButtonIcon, { icon: iconNext || chevronRight, size: iconSize, variant: "link", onClick: increaseYear, disabled: nextMonthButtonDisabled, "aria-label": nextMonthAriaLabel, className: "header-button", style: { visibility: customHeaderCount === monthsShown - 1 ? 'visible' : 'hidden' } })] }));
1486
1490
  }
1487
- return (jsxs(Fragment, { children: [jsxs("div", { className: "datepicker-top-header", children: [showHeaderSelectors && (jsx(DSelect$1, { options: years, value: defaultYear, defaultValue: defaultYear, onChange: (year) => changeYear(Number(year === null || year === void 0 ? void 0 : year.value)), searchable: false, className: "custom-year-selector" })), jsx("h4", { className: "mb-0 fw-normal", children: format(monthDate, formatHeaderDate, { locale }) })] }), jsxs("div", { className: classNames('react-datepicker__header-selector react-datepicker__header-day-selector', className), style: style, children: [jsx(DButtonIcon, { icon: iconPrev || chevronLeft, size: iconSize, variant: "link", onClick: decreaseMonth, disabled: prevMonthButtonDisabled, "aria-label": prevMonthAriaLabel, className: "header-button", style: { visibility: customHeaderCount === 0 ? 'visible' : 'hidden' } }), showHeaderSelectors ? (jsx(DSelect$1, { options: months, value: defaultMonth, defaultValue: defaultMonth, onChange: (month) => changeMonth((month === null || month === void 0 ? void 0 : month.value) || 0), searchable: false, className: "custom-month-selector" })) : (jsx("p", { children: `${defaultMonth.label} ${defaultYear === null || defaultYear === void 0 ? void 0 : defaultYear.label}` })), jsx(DButtonIcon, { icon: iconNext || chevronRight, size: iconSize, variant: "link", onClick: increaseMonth, disabled: nextMonthButtonDisabled, "aria-label": nextMonthAriaLabel, className: "header-button", style: { visibility: customHeaderCount === monthsShown - 1 ? 'visible' : 'hidden' } })] })] }));
1491
+ return (jsxs(Fragment, { children: [jsxs("div", { className: "datepicker-top-header", children: [showHeaderSelectors && (jsx(DSelect$1, { options: years, value: defaultYear, defaultValue: defaultYear, onChange: (year) => changeYear(Number(year === null || year === void 0 ? void 0 : year.value)), searchable: false, className: "custom-year-selector" })), jsx("h4", { className: "datepicker-top-header-title", children: format(monthDate, formatHeaderDate, { locale }) })] }), jsxs("div", { className: classNames('react-datepicker__header-selector react-datepicker__header-day-selector', className), style: style, children: [jsx(DButtonIcon, { icon: iconPrev || chevronLeft, size: iconSize, variant: "link", onClick: decreaseMonth, disabled: prevMonthButtonDisabled, "aria-label": prevMonthAriaLabel, className: "header-button", style: { visibility: customHeaderCount === 0 ? 'visible' : 'hidden' } }), showHeaderSelectors ? (jsx(DSelect$1, { options: months, value: defaultMonth, defaultValue: defaultMonth, onChange: (month) => changeMonth((month === null || month === void 0 ? void 0 : month.value) || 0), searchable: false, className: "custom-month-selector" })) : (jsx("p", { children: `${defaultMonth.label} ${defaultYear === null || defaultYear === void 0 ? void 0 : defaultYear.label}` })), jsx(DButtonIcon, { icon: iconNext || chevronRight, size: iconSize, variant: "link", onClick: increaseMonth, disabled: nextMonthButtonDisabled, "aria-label": nextMonthAriaLabel, className: "header-button", style: { visibility: customHeaderCount === monthsShown - 1 ? 'visible' : 'hidden' } })] })] }));
1488
1492
  }
1489
1493
 
1490
1494
  function DDatePicker(_a) {
@@ -1619,11 +1623,24 @@ function formatValue(value, currencyOptions) {
1619
1623
  }
1620
1624
  return currency(value, Object.assign(Object.assign({}, currencyOptions), { symbol: '' })).format();
1621
1625
  }
1622
- function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref) {
1626
+ function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref, minValue, maxValue) {
1623
1627
  const inputRef = useProvidedRefOrCreate(ref);
1628
+ const clampValue = useCallback((newValue) => {
1629
+ if (newValue === undefined) {
1630
+ return newValue;
1631
+ }
1632
+ let clampedValue = newValue;
1633
+ if (minValue !== undefined) {
1634
+ clampedValue = Math.max(clampedValue, minValue);
1635
+ }
1636
+ if (maxValue !== undefined) {
1637
+ clampedValue = Math.min(clampedValue, maxValue);
1638
+ }
1639
+ return clampedValue;
1640
+ }, [minValue, maxValue]);
1624
1641
  const [innerType, setInnerType] = useState('text');
1625
- const [innerNumber, setInnerNumber] = useState(value);
1626
- const [innerString, setInnerString] = useState(formatValue(value, currencyOptions));
1642
+ const [innerNumber, setInnerNumber] = useState(clampValue(value));
1643
+ const [innerString, setInnerString] = useState(formatValue(clampValue(value), currencyOptions));
1627
1644
  const handleOnFocus = useCallback((event) => {
1628
1645
  event.stopPropagation();
1629
1646
  setInnerType('number');
@@ -1632,15 +1649,14 @@ function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref
1632
1649
  const handleOnBlur = useCallback((event) => {
1633
1650
  event.stopPropagation();
1634
1651
  setInnerType('text');
1652
+ const clampedNumber = clampValue(innerNumber);
1653
+ if (clampedNumber !== innerNumber) {
1654
+ setInnerNumber(clampedNumber);
1655
+ setInnerString(formatValue(clampedNumber, currencyOptions));
1656
+ onChange === null || onChange === void 0 ? void 0 : onChange(clampedNumber);
1657
+ }
1635
1658
  onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
1636
- }, [onBlur]);
1637
- const generateStyleVariables = useMemo(() => ({
1638
- [`--${PREFIX_BS}input-currency-component-symbol-color`]: `var(--${PREFIX_BS}secondary)`,
1639
- [`--${PREFIX_BS}input-currency-symbol-color`]: `var(--${PREFIX_BS}input-currency-component-symbol-color)`,
1640
- }), []);
1641
- const generateSymbolStyleVariables = useMemo(() => ({
1642
- color: `var(--${PREFIX_BS}input-currency-symbol-color)`,
1643
- }), []);
1659
+ }, [onBlur, innerNumber, clampValue, currencyOptions, onChange]);
1644
1660
  const handleOnChange = useCallback((newValue) => {
1645
1661
  const newNumber = (newValue === undefined || newValue === '') ? undefined : Number(newValue);
1646
1662
  if (newNumber !== innerNumber) {
@@ -1649,7 +1665,12 @@ function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref
1649
1665
  onChange === null || onChange === void 0 ? void 0 : onChange(newNumber);
1650
1666
  }
1651
1667
  }, [currencyOptions, onChange, innerNumber]);
1668
+ const isMountedRef = useRef(false);
1652
1669
  useEffect(() => {
1670
+ if (!isMountedRef.current) {
1671
+ isMountedRef.current = true;
1672
+ return;
1673
+ }
1653
1674
  if (value !== innerNumber) {
1654
1675
  setInnerNumber(value);
1655
1676
  setInnerString(formatValue(value, currencyOptions));
@@ -1663,8 +1684,6 @@ function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref
1663
1684
  handleOnFocus,
1664
1685
  handleOnChange,
1665
1686
  handleOnBlur,
1666
- generateStyleVariables,
1667
- generateSymbolStyleVariables,
1668
1687
  };
1669
1688
  }
1670
1689
 
@@ -1769,6 +1788,149 @@ function useConfirmModal(config) {
1769
1788
  return { open };
1770
1789
  }
1771
1790
 
1791
+ /**
1792
+ * Generic seconds-based countdown hook.
1793
+ *
1794
+ * Starts counting down from `seconds` to `0` and exposes `restartCountdown`
1795
+ * to reset and restart the timer (e.g. for "resend code in Xs" patterns,
1796
+ * session-expiry banners, or any other cooldown/throttle UI).
1797
+ *
1798
+ * @example
1799
+ * const { secondsLeft, restartCountdown } = useCountdown(30);
1800
+ */
1801
+ function useCountdown(seconds) {
1802
+ const [secondsLeft, setSecondsLeft] = useState(seconds);
1803
+ const [isActive, setIsActive] = useState(true);
1804
+ const resetCountdown = useCallback((newSeconds = seconds) => {
1805
+ setIsActive(false);
1806
+ setSecondsLeft(newSeconds);
1807
+ }, [seconds]);
1808
+ const restartCountdown = useCallback(() => {
1809
+ resetCountdown(seconds);
1810
+ setIsActive(true);
1811
+ }, [resetCountdown, seconds]);
1812
+ useEffect(() => {
1813
+ if (!isActive) {
1814
+ return () => { };
1815
+ }
1816
+ const interval = setInterval(() => {
1817
+ setSecondsLeft((prevSeconds) => {
1818
+ const newSeconds = prevSeconds - 1;
1819
+ if (newSeconds <= 0) {
1820
+ clearInterval(interval);
1821
+ setIsActive(false);
1822
+ return 0;
1823
+ }
1824
+ return newSeconds;
1825
+ });
1826
+ }, 1000);
1827
+ return () => clearInterval(interval);
1828
+ }, [isActive]);
1829
+ return { secondsLeft, restartCountdown };
1830
+ }
1831
+
1832
+ /**
1833
+ * Headless hook exposing the same OTP logic used internally by `DOtp`
1834
+ * (code state, length + correctness validation, submit action and resend
1835
+ * countdown), without any bundled markup/styles.
1836
+ *
1837
+ * Use this when the default `DOtp` component doesn't match your design and
1838
+ * you need to build a fully custom UI while reusing the same behavior.
1839
+ *
1840
+ * Internally composes `useCountdown` for the resend timer and re-exposes
1841
+ * `secondsLeft`/`restartCountdown`, so there is no need to call
1842
+ * `useCountdown` separately.
1843
+ *
1844
+ * `invalid` becomes `true` both when the OTP is shorter than `otpSize` and
1845
+ * when `action` throws/rejects (e.g. the backend rejected the entered code
1846
+ * as incorrect). In the latter case, the thrown value is exposed as `error`
1847
+ * so custom UIs can render an appropriate message (e.g. "Invalid code" vs.
1848
+ * "Enter all digits"). `invalid`/`error` are cleared automatically as soon
1849
+ * as the user edits the code via `setOtp`.
1850
+ *
1851
+ * @example
1852
+ * function CustomOtp() {
1853
+ * const {
1854
+ * otp,
1855
+ * setOtp,
1856
+ * invalid,
1857
+ * error,
1858
+ * submit,
1859
+ * isLoading,
1860
+ * secondsLeft,
1861
+ * restartCountdown,
1862
+ * } = useOtp({ action: async () => verifyOtp(otp), otpSize: 6, seconds: 15 });
1863
+ *
1864
+ * return (
1865
+ * <>
1866
+ * <MyCustomPinInput value={otp} onChange={setOtp} invalid={invalid} />
1867
+ * {invalid && <span>{error ? 'Invalid code' : 'Enter all digits'}</span>}
1868
+ * <button disabled={isLoading} onClick={() => { submit().catch(() => {}); }}>
1869
+ * {isLoading ? 'Submitting...' : 'Submit'}
1870
+ * </button>
1871
+ * <button disabled={secondsLeft > 0} onClick={restartCountdown}>
1872
+ * Resend {secondsLeft > 0 ? `(${secondsLeft}s)` : ''}
1873
+ * </button>
1874
+ * </>
1875
+ * );
1876
+ * }
1877
+ */
1878
+ function useOtp({ action, otpSize = 6, seconds = 15, }) {
1879
+ const [otp, setOtpValue] = useState('');
1880
+ const [invalid, setInvalid] = useState(false);
1881
+ const [error, setError] = useState(null);
1882
+ const [isLoading, setIsLoading] = useState(false);
1883
+ const { secondsLeft, restartCountdown } = useCountdown(seconds);
1884
+ const setOtp = useCallback((value) => {
1885
+ setOtpValue((prevOtp) => {
1886
+ // Guard against no-op calls (e.g. DInputPin re-notifying the same
1887
+ // value when its onChange reference changes) so we don't wipe out
1888
+ // an `invalid`/`error` state that was just set by submit().
1889
+ if (prevOtp === value) {
1890
+ return prevOtp;
1891
+ }
1892
+ setInvalid(false);
1893
+ setError(null);
1894
+ return value;
1895
+ });
1896
+ }, []);
1897
+ const submit = useCallback(async () => {
1898
+ if (otp.length < otpSize) {
1899
+ setInvalid(true);
1900
+ setError(null);
1901
+ return;
1902
+ }
1903
+ setIsLoading(true);
1904
+ try {
1905
+ await action();
1906
+ setInvalid(false);
1907
+ setError(null);
1908
+ }
1909
+ catch (err) {
1910
+ setInvalid(true);
1911
+ setError(err);
1912
+ throw err;
1913
+ }
1914
+ finally {
1915
+ setIsLoading(false);
1916
+ }
1917
+ }, [
1918
+ otp.length,
1919
+ action,
1920
+ otpSize,
1921
+ ]);
1922
+ return {
1923
+ otp,
1924
+ setOtp,
1925
+ invalid,
1926
+ error,
1927
+ submit,
1928
+ isLoading,
1929
+ secondsLeft,
1930
+ restartCountdown,
1931
+ };
1932
+ }
1933
+
1772
1934
  function DInputCounter(_a, ref) {
1773
1935
  var { minValue, maxValue, value = minValue, invalid, iconStart: iconStartProp, iconEnd: iconEndProp, iconStartAriaLabel = 'decrease action', iconEndAriaLabel = 'increase action', style, onChange } = _a, props = __rest(_a, ["minValue", "maxValue", "value", "invalid", "iconStart", "iconEnd", "iconStartAriaLabel", "iconEndAriaLabel", "style", "onChange"]);
1774
1936
  const { handleOnWheel, } = useDisableInputWheel(ref);
@@ -1811,8 +1973,8 @@ function DInputCurrency(_a, ref) {
1811
1973
  var { value, minValue, maxValue, currencyCode, onFocus, onBlur, onChange } = _a, props = __rest(_a, ["value", "minValue", "maxValue", "currencyCode", "onFocus", "onBlur", "onChange"]);
1812
1974
  const { currency: currencyOptions } = useDContext();
1813
1975
  const { handleOnWheel, } = useDisableInputWheel(ref);
1814
- const { inputRef, innerValue, innerType, handleOnFocus, handleOnChange, handleOnBlur, generateStyleVariables, generateSymbolStyleVariables, } = useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref);
1815
- return (jsx(ForwardedDInput, Object.assign({ ref: inputRef, value: innerValue, onChange: handleOnChange, style: generateStyleVariables, inputMode: "decimal", type: innerType, onFocus: handleOnFocus, onBlur: handleOnBlur, onWheel: handleOnWheel, inputStart: (jsx("span", { slot: "input-start", style: generateSymbolStyleVariables, children: currencyCode || currencyOptions.symbol })) }, props)));
1976
+ const { inputRef, innerValue, innerType, handleOnFocus, handleOnChange, handleOnBlur, } = useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref, minValue, maxValue);
1977
+ return (jsx(ForwardedDInput, Object.assign({ ref: inputRef, value: innerValue, onChange: handleOnChange, inputMode: "decimal", type: innerType, onFocus: handleOnFocus, onBlur: handleOnBlur, onWheel: handleOnWheel, inputStart: (jsx("span", { slot: "input-start", className: "d-input-currency-symbol", children: currencyCode || currencyOptions.symbol })) }, props)));
1816
1978
  }
1817
1979
  const ForwardedDInputCurrency = forwardRef(DInputCurrency);
1818
1980
  ForwardedDInputCurrency.displayName = 'DInputCurrency';
@@ -1834,26 +1996,25 @@ ForwardedDInputPassword.displayName = 'DInputPassword';
1834
1996
 
1835
1997
  function PasswordCheckItem({ password, regex, text, }) {
1836
1998
  const isValid = regex.test(password);
1837
- return (jsxs("li", { className: "d-flex gap-2 align-items-start small text-gray-600", children: [jsx(DIcon, { className: classNames('flex-shrink-0', isValid ? 'text-success' : 'text-gray-300'), icon: isValid ? 'CircleCheck' : 'Circle', size: "16px" }), jsx("span", { className: classNames({ 'text-success': isValid }), children: text })] }));
1999
+ return (jsxs("li", { className: `d-password-check-item${isValid ? ' is-valid' : ''}`, children: [jsx(DIcon, { className: "d-password-check-item-icon", icon: isValid ? 'CircleCheck' : 'Circle', size: "16px" }), jsx("span", { children: text })] }));
1838
2000
  }
1839
2001
 
1840
- const getColorClass = (strength, total) => {
2002
+ const getStrengthModifier = (strength, total) => {
1841
2003
  const percentage = total > 0 ? strength / total : 0;
1842
2004
  if (percentage === 0)
1843
- return 'bg-gray-200';
2005
+ return 'is-empty';
1844
2006
  if (percentage <= 0.25)
1845
- return 'bg-danger';
2007
+ return 'is-weak';
1846
2008
  if (percentage <= 0.5)
1847
- return 'bg-warning';
2009
+ return 'is-fair';
1848
2010
  if (percentage <= 0.75)
1849
- return 'bg-info';
1850
- return 'bg-success';
2011
+ return 'is-good';
2012
+ return 'is-strong';
1851
2013
  };
1852
2014
  function PasswordStrengthBar({ strength, total }) {
1853
2015
  const percentage = total > 0 ? (strength / total) * 100 : 0;
1854
- return (jsx("div", { className: "w-100 rounded-3 overflow-hidden bg-gray-100 mb-2", style: { height: '8px' }, children: jsx("div", { className: `h-100 ${getColorClass(strength, total)}`, style: {
2016
+ return (jsx("div", { className: "d-password-strength-bar", children: jsx("div", { className: `d-password-strength-bar-fill ${getStrengthModifier(strength, total)}`, style: {
1855
2017
  width: `${percentage}%`,
1856
- transition: 'width 0.3s ease-in-out',
1857
2018
  } }) }));
1858
2019
  }
1859
2020
 
@@ -1889,7 +2050,7 @@ function PasswordChecksList({ password, validationMessages, enabledChecks, }) {
1889
2050
  const passwordChecks = allChecks.filter((check) => enabledChecks.includes(check.key));
1890
2051
  const passed = passwordChecks.filter((r) => r.regex.test(password)).length;
1891
2052
  const total = passwordChecks.length;
1892
- return (jsxs("div", { className: "mt-2", children: [jsx(PasswordStrengthBar, { strength: passed, total: total }), jsx("ul", { className: "list-unstyled m-0 d-flex flex-column gap-2", children: passwordChecks.map(({ key, regex, text }) => (jsx(PasswordCheckItem, { password: password, regex: regex, text: text }, key))) })] }));
2053
+ return (jsxs("div", { className: "d-password-strength-meter", children: [jsx(PasswordStrengthBar, { strength: passed, total: total }), jsx("ul", { className: "d-password-check-list", children: passwordChecks.map(({ key, regex, text }) => (jsx(PasswordCheckItem, { password: password, regex: regex, text: text }, key))) })] }));
1893
2054
  }
1894
2055
 
1895
2056
  const DEFAULT_VALIDATION_MESSAGES = {
@@ -1930,9 +2091,9 @@ function DInputCheck(_a) {
1930
2091
  ]);
1931
2092
  useEffect(() => {
1932
2093
  if (innerRef.current) {
1933
- innerRef.current.indeterminate = Boolean(indeterminate);
2094
+ innerRef.current.indeterminate = type === 'checkbox' && Boolean(indeterminate);
1934
2095
  }
1935
- }, [indeterminate]);
2096
+ }, [indeterminate, type]);
1936
2097
  useEffect(() => {
1937
2098
  if (innerRef.current) {
1938
2099
  innerRef.current.checked = checked;
@@ -2125,10 +2286,18 @@ function DInputSelect({ id: idProp, name, label = '', className, style, options
2125
2286
  }), children: [iconStart && (jsx("button", { type: "button", className: "input-group-text", id: `${id}Start`, onClick: iconStartClickHandler, disabled: disabled || loading, "aria-label": iconStartAriaLabel, children: iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix })) })), dynamicComponent, iconEnd && !loading && (jsx("button", { type: "button", className: "input-group-text", id: `${id}End`, onClick: iconEndClickHandler, disabled: disabled || loading, "aria-label": iconEndAriaLabel, children: iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix })) })), loading && (jsx("div", { className: "input-group-text form-control-icon loading", children: jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsx("span", { className: "visually-hidden", children: "Loading..." }) }) }))] }), hint && (jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
2126
2287
  }
2127
2288
 
2128
- function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, invalid = false, valid = false, readonly, className, style, dataAttributes, inputClassName, onChange, }) {
2289
+ function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, invalid = false, valid = false, hint, readonly, className, style, dataAttributes, inputClassName, onChange, }) {
2129
2290
  const innerId = useId();
2130
2291
  const id = useMemo(() => idProp || innerId, [idProp, innerId]);
2131
2292
  const [internalIsChecked, setInternalIsChecked] = useState(checked);
2293
+ const ariaDescribedby = useMemo(() => ([
2294
+ !!hint && `${id}Hint`,
2295
+ ]
2296
+ .filter(Boolean)
2297
+ .join(' ')), [
2298
+ id,
2299
+ hint,
2300
+ ]);
2132
2301
  useEffect(() => {
2133
2302
  setInternalIsChecked(checked);
2134
2303
  }, [checked]);
@@ -2137,10 +2306,10 @@ function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, i
2137
2306
  setInternalIsChecked(value);
2138
2307
  onChange === null || onChange === void 0 ? void 0 : onChange(value);
2139
2308
  }, [onChange]);
2140
- return (jsxs("div", Object.assign({ className: classNames('form-check form-switch', className) }, dataAttributes, { children: [jsx("input", { id: id, name: name, onChange: readonly ? () => false : changeHandler, className: classNames('form-check-input', {
2309
+ return (jsxs("div", Object.assign({ className: classNames('form-check form-switch', className) }, dataAttributes, { children: [jsx("input", Object.assign({ id: id, name: name, onChange: readonly ? () => false : changeHandler, className: classNames('form-check-input', {
2141
2310
  'is-invalid': invalid,
2142
2311
  'is-valid': valid,
2143
- }, inputClassName), style: style, type: "checkbox", role: "switch", checked: internalIsChecked, disabled: disabled, "aria-label": ariaLabel }), label && (jsx("label", { className: "form-check-label", htmlFor: id, children: label }))] })));
2312
+ }, inputClassName), style: style, type: "checkbox", role: "switch", checked: internalIsChecked, disabled: disabled, "aria-label": ariaLabel }, ariaDescribedby && { 'aria-describedby': ariaDescribedby })), label && (jsx("label", { className: "form-check-label", htmlFor: id, children: label })), hint && (jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
2144
2313
  }
2145
2314
 
2146
2315
  function DInputRange(_a, ref) {
@@ -2181,6 +2350,7 @@ const ForwardedDInputRange = forwardRef(DInputRange);
2181
2350
  ForwardedDInputRange.displayName = 'DInputRange';
2182
2351
 
2183
2352
  function DListGroupItem({ as = 'li', action: actionProp, active, disabled, href, onClick, color, iconStart, iconStartFamilyClass, iconStartFamilyPrefix, iconStartMaterialStyle, iconEnd, iconEndFamilyClass, iconEndFamilyPrefix, iconEndMaterialStyle, children, className, style, dataAttributes, }) {
2353
+ const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
2184
2354
  const Tag = useMemo(() => {
2185
2355
  if (href) {
2186
2356
  return 'a';
@@ -2209,7 +2379,7 @@ function DListGroupItem({ as = 'li', action: actionProp, active, disabled, href,
2209
2379
  }
2210
2380
  return Object.assign(Object.assign({}, active && { 'aria-current': true }), disabled && { 'aria-disabled': true });
2211
2381
  }, [Tag, active, disabled]);
2212
- return (jsxs(Tag, Object.assign({ className: classNames(generateClasses, className), style: style }, Tag === 'a' && href && { href }, onClick && { onClick }, ariaAttributes, dataAttributes, Tag === 'button' && { type: 'button' }, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle })), children, iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle, className: "ms-auto" }))] })));
2382
+ return (jsxs(Tag, Object.assign({ className: classNames(generateClasses, className), style: style }, Tag === 'a' && href && { href }, onClick && { onClick }, ariaAttributes, dataAttributes, Tag === 'button' && { type: 'button' }, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass !== null && iconStartFamilyClass !== void 0 ? iconStartFamilyClass : familyClass, familyPrefix: iconStartFamilyPrefix !== null && iconStartFamilyPrefix !== void 0 ? iconStartFamilyPrefix : familyPrefix, materialStyle: iconStartMaterialStyle !== null && iconStartMaterialStyle !== void 0 ? iconStartMaterialStyle : materialStyle })), children, iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass !== null && iconEndFamilyClass !== void 0 ? iconEndFamilyClass : familyClass, familyPrefix: iconEndFamilyPrefix !== null && iconEndFamilyPrefix !== void 0 ? iconEndFamilyPrefix : familyPrefix, materialStyle: iconEndMaterialStyle !== null && iconEndMaterialStyle !== void 0 ? iconEndMaterialStyle : materialStyle, className: "ms-auto" }))] })));
2213
2383
  }
2214
2384
 
2215
2385
  function DListGroup({ as = 'ul', numbered, flush, horizontal, children, className, style, dataAttributes, }) {
@@ -2236,10 +2406,11 @@ var DListGroup$1 = Object.assign(DListGroup, {
2236
2406
  Item: DListGroupItem,
2237
2407
  });
2238
2408
 
2239
- function DModalHeader({ showCloseButton, onClose, children, className, style, iconFamilyClass, iconFamilyPrefix, icon: iconProp, materialStyle = false, }) {
2240
- const { iconMap: { xLg, }, } = useDContext();
2409
+ function DModalHeader({ showCloseButton, onClose, children, className, style, iconFamilyClass, iconFamilyPrefix, icon: iconProp, iconMaterialStyle, materialStyle: materialStyleProp, }) {
2410
+ var _a;
2411
+ const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { xLg, }, } = useDContext();
2241
2412
  const icon = useMemo(() => iconProp || xLg, [iconProp, xLg]);
2242
- return (jsxs(Fragment, { children: [jsxs("div", { className: classNames('modal-header', className), style: style, children: [jsx("div", { children: children }), showCloseButton && (jsx("button", { type: "button", className: "d-close align-self-center", "aria-label": "Close", onClick: onClose, children: jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: materialStyle }) }))] }), jsx("div", { className: "d-modal-separator" })] }));
2413
+ return (jsxs(Fragment, { children: [jsxs("div", { className: classNames('modal-header', className), style: style, children: [jsx("div", { children: children }), showCloseButton && (jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: onClose, children: jsx(DIcon, { icon: icon, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: (_a = iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyleProp) !== null && _a !== void 0 ? _a : materialStyle }) }))] }), jsx("div", { className: "d-modal-separator" })] }));
2243
2414
  }
2244
2415
 
2245
2416
  function DModalBody({ children, className, style, }) {
@@ -2280,10 +2451,11 @@ var DModal$1 = Object.assign(DModal, {
2280
2451
  Footer: DModalFooter,
2281
2452
  });
2282
2453
 
2283
- function DOffcanvasHeader({ showCloseButton, onClose, children, className, style, iconFamilyClass, iconFamilyPrefix, icon: iconProp, materialStyle = false, }) {
2284
- const { iconMap: { xLg, }, } = useDContext();
2454
+ function DOffcanvasHeader({ showCloseButton, onClose, children, className, style, iconFamilyClass, iconFamilyPrefix, icon: iconProp, iconMaterialStyle, materialStyle: materialStyleProp, }) {
2455
+ var _a;
2456
+ const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { xLg, }, } = useDContext();
2285
2457
  const icon = useMemo(() => iconProp || xLg, [iconProp, xLg]);
2286
- return (jsxs(Fragment, { children: [jsxs("div", { className: classNames('offcanvas-header', className), style: style, children: [jsx("div", { children: children }), showCloseButton && (jsx("button", { type: "button", className: "d-close align-self-center", "aria-label": "Close", onClick: onClose, children: jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: materialStyle }) }))] }), jsx("div", { className: "d-offcanvas-separator" })] }));
2458
+ return (jsxs(Fragment, { children: [jsxs("div", { className: classNames('offcanvas-header', className), style: style, children: [jsx("div", { children: children }), showCloseButton && (jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: onClose, children: jsx(DIcon, { icon: icon, familyClass: iconFamilyClass !== null && iconFamilyClass !== void 0 ? iconFamilyClass : familyClass, familyPrefix: iconFamilyPrefix !== null && iconFamilyPrefix !== void 0 ? iconFamilyPrefix : familyPrefix, materialStyle: (_a = iconMaterialStyle !== null && iconMaterialStyle !== void 0 ? iconMaterialStyle : materialStyleProp) !== null && _a !== void 0 ? _a : materialStyle }) }))] }), jsx("div", { className: "d-offcanvas-separator" })] }));
2287
2459
  }
2288
2460
 
2289
2461
  function DOffcanvasBody({ children, className, style, }) {
@@ -2410,7 +2582,7 @@ function DPopover({ children, renderComponent, open, setOpen, adjustContentToRen
2410
2582
  }
2411
2583
  const reference = cloneElement(triggerElement, Object.assign({ ref: refs.setReference }, getReferenceProps(triggerElement.props)));
2412
2584
  return (jsxs("div", Object.assign({ className: classNames('d-popover', className), style: generateStyleVariables }, dataAttributes, { children: [reference, isOpen && (jsx(FloatingFocusManager, { context: context, modal: false, children: jsx("div", Object.assign({ className: classNames('d-popover-content', {
2413
- 'w-100': adjustContentToRender,
2585
+ 'd-popover-content-fill': adjustContentToRender,
2414
2586
  }), ref: refs.setFloating, style: floatingStyles, "aria-labelledby": headingId }, getFloatingProps(), { children: children })) }))] })));
2415
2587
  }
2416
2588
 
@@ -2424,8 +2596,8 @@ function DProgress({ className, style, currentValue, minValue = 0, maxValue = 10
2424
2596
  return (jsx("div", Object.assign({ className: classNames('progress', className), style: Object.assign({ height }, style) }, dataAttributes, { children: jsx("div", { className: classNames(generateClasses), role: "progressbar", "aria-label": "Progress bar", style: { width: formatProgress }, "aria-valuenow": currentValue, "aria-valuemin": minValue, "aria-valuemax": maxValue, children: !hideCurrentValue && formatProgress }) })));
2425
2597
  }
2426
2598
 
2427
- function DStepper$2({ options, currentStep, iconSuccess: iconSuccessProp, iconSuccessFamilyClass, iconSuccessFamilyPrefix, iconSuccessMaterialStyle = false, vertical = false, completed, alignStart = false, className, style, }) {
2428
- const { iconMap: { check, }, } = useDContext();
2599
+ function DStepper$2({ options, currentStep, iconSuccess: iconSuccessProp, iconSuccessFamilyClass, iconSuccessFamilyPrefix, iconSuccessMaterialStyle, vertical = false, completed, alignStart = false, className, style, }) {
2600
+ const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { check, }, } = useDContext();
2429
2601
  const icon = useMemo(() => iconSuccessProp || check, [check, iconSuccessProp]);
2430
2602
  if (currentStep < 1 || currentStep > options.length) {
2431
2603
  throw new Error('Current step should be in the range from 1 to options length');
@@ -2440,7 +2612,7 @@ function DStepper$2({ options, currentStep, iconSuccess: iconSuccessProp, iconSu
2440
2612
  }), children: [jsx("div", { className: "d-step-value", children: jsxs("div", { className: classNames({
2441
2613
  'd-step-icon-container': true,
2442
2614
  'd-step-check': value < currentStep || completed,
2443
- }), children: [((value < currentStep) || completed) && (jsx(DIcon, { icon: icon, familyClass: iconSuccessFamilyClass, familyPrefix: iconSuccessFamilyPrefix, materialStyle: iconSuccessMaterialStyle, className: "d-step-icon" })), value] }) }), jsxs("div", { className: "d-step-text-container", children: [jsx("div", { className: "d-step-label", children: label }), description && (jsx("div", { className: "d-step-description", children: description }))] })] }, value))) }));
2615
+ }), children: [((value < currentStep) || completed) && (jsx(DIcon, { icon: icon, familyClass: iconSuccessFamilyClass !== null && iconSuccessFamilyClass !== void 0 ? iconSuccessFamilyClass : familyClass, familyPrefix: iconSuccessFamilyPrefix !== null && iconSuccessFamilyPrefix !== void 0 ? iconSuccessFamilyPrefix : familyPrefix, materialStyle: iconSuccessMaterialStyle !== null && iconSuccessMaterialStyle !== void 0 ? iconSuccessMaterialStyle : materialStyle, className: "d-step-icon" })), value] }) }), jsxs("div", { className: "d-step-text-container", children: [jsx("div", { className: "d-step-label", children: label }), description && (jsx("div", { className: "d-step-description", children: description }))] })] }, value))) }));
2444
2616
  }
2445
2617
 
2446
2618
  function DStepper$1({ options, currentStep, className, style, }) {
@@ -2473,14 +2645,21 @@ function DStepper$1({ options, currentStep, className, style, }) {
2473
2645
  return (jsxs("div", { className: classNames('d-stepper', className), style: style, children: [jsx("div", { className: "d-step-bar", style: { background: progressStyle }, children: jsx("p", { className: "d-step-number", children: `${currentStep}/${options.length}` }) }), jsx("div", { className: "d-step-info", children: Object.keys(currentOption).length > 0 && (jsxs(Fragment, { children: [jsx("div", { className: "d-step-label", children: currentOption.label }), jsx("div", { className: "d-step-description", children: currentOption.description || '' })] })) })] }));
2474
2646
  }
2475
2647
 
2476
- function DStepper({ options, currentStep, iconSuccess, iconSuccessFamilyClass, iconSuccessFamilyPrefix, iconSuccessMaterialStyle = false, vertical = false, breakpoint = 'lg', className, completed = false, style, dataAttributes, }) {
2477
- return (jsxs("div", Object.assign({ className: className, style: style }, dataAttributes, { children: [jsx("div", { className: `d-block d-${breakpoint}-none`, children: jsx(DStepper$1, { options: options, currentStep: currentStep }) }), jsx("div", { className: `d-none d-${breakpoint}-block`, children: jsx(DStepper$2, { options: options, currentStep: currentStep, vertical: vertical, iconSuccess: iconSuccess, iconSuccessFamilyClass: iconSuccessFamilyClass, iconSuccessFamilyPrefix: iconSuccessFamilyPrefix, iconSuccessMaterialStyle: iconSuccessMaterialStyle, completed: completed }) })] })));
2648
+ function DStepper({ options, currentStep, iconSuccess, iconSuccessFamilyClass, iconSuccessFamilyPrefix, iconSuccessMaterialStyle, vertical = false, breakpoint = 'lg', className, completed = false, style, dataAttributes, }) {
2649
+ const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
2650
+ return (jsxs("div", Object.assign({ className: className, style: style }, dataAttributes, { children: [jsx("div", { className: classNames('d-stepper-mobile', `d-block d-${breakpoint}-none`), children: jsx(DStepper$1, { options: options, currentStep: currentStep }) }), jsx("div", { className: classNames('d-stepper-desktop', `d-none d-${breakpoint}-block`), children: jsx(DStepper$2, { options: options, currentStep: currentStep, vertical: vertical, iconSuccess: iconSuccess, iconSuccessFamilyClass: iconSuccessFamilyClass !== null && iconSuccessFamilyClass !== void 0 ? iconSuccessFamilyClass : familyClass, iconSuccessFamilyPrefix: iconSuccessFamilyPrefix !== null && iconSuccessFamilyPrefix !== void 0 ? iconSuccessFamilyPrefix : familyPrefix, iconSuccessMaterialStyle: iconSuccessMaterialStyle !== null && iconSuccessMaterialStyle !== void 0 ? iconSuccessMaterialStyle : materialStyle, completed: completed }) })] })));
2478
2651
  }
2479
2652
 
2480
2653
  const ARROW_WIDTH = 8;
2481
2654
  const ARROW_HEIGHT = 4;
2482
- const GAP = 2;
2483
- function DTooltip({ className, childrenClassName, style, offSet = ARROW_HEIGHT + GAP, padding, withFocus = false, withClick = false, withHover = true, open = false, placement = 'top', size, Component, children, }) {
2655
+ const GAP$1 = 2;
2656
+ /**
2657
+ * Tooltip is an abstraction component that wraps any element (`Component`) and displays
2658
+ * floating contextual content (`children`) positioned relative to it using Floating UI.
2659
+ * Use it to add short, non-critical hints or descriptions triggered by hover, focus, or
2660
+ * click, without altering the surrounding layout.
2661
+ */
2662
+ function DTooltip({ className, childrenClassName, style, offSet = ARROW_HEIGHT + GAP$1, padding, withFocus = false, withClick = false, withHover = true, open = false, placement = 'top', size, Component, children, }) {
2484
2663
  const [isOpen, setIsOpen] = useState(open);
2485
2664
  const arrowRef = useRef(null);
2486
2665
  const { refs, context, floatingStyles, } = useFloating({
@@ -2549,8 +2728,16 @@ function DTabs({ children, defaultSelected, onChange, options, className, classN
2549
2728
  useEffect(() => {
2550
2729
  setSelected(defaultSelected);
2551
2730
  }, [defaultSelected]);
2552
- const generateClasses = useMemo(() => (Object.assign({ nav: true, 'flex-column align-items-center': vertical && variant !== 'tabs', [`nav-${variant}`]: true }, className && { [className]: true })), [vertical, variant, className]);
2731
+ const generateClasses = useMemo(() => (Object.assign({ nav: true, 'd-tabs-nav-vertical': vertical && variant !== 'tabs', [`nav-${variant}`]: true }, className && { [className]: true })), [vertical, variant, className]);
2553
2732
  const tabRefs = useRef([]);
2733
+ // Always holds the latest `options` without needing to be a dependency:
2734
+ // `options` is commonly passed as an inline array literal (e.g.
2735
+ // `options={[{ label: 'SMS', tab: 'sms' }, ...]}`), so it's a new array
2736
+ // reference on every parent render even when its content hasn't changed.
2737
+ // Reading it from this ref (updated synchronously on every render) lets
2738
+ // the focus effect below react only to `selected` changing.
2739
+ const optionsRef = useRef(options);
2740
+ optionsRef.current = options;
2554
2741
  useEffect(() => {
2555
2742
  tabRefs.current = options.map((_, i) => tabRefs.current[i] || createRef());
2556
2743
  }, [options]);
@@ -2565,20 +2752,28 @@ function DTabs({ children, defaultSelected, onChange, options, className, classN
2565
2752
  setSelected(firstEnabled.tab);
2566
2753
  }
2567
2754
  }, [options, selected]);
2568
- // Declarative focus management
2569
- const focusTab = (idx) => {
2755
+ // Declarative focus management. Wrapped in `useCallback` with an empty
2756
+ // dependency array since it only reads from the `tabRefs` ref, so its
2757
+ // identity stays stable across renders and it can safely be used as an
2758
+ // effect dependency below.
2759
+ const focusTab = useCallback((idx) => {
2570
2760
  var _a;
2571
2761
  if ((_a = tabRefs.current[idx]) === null || _a === void 0 ? void 0 : _a.current) {
2572
2762
  tabRefs.current[idx].current.focus();
2573
2763
  }
2574
- };
2575
- // Focus selected tab when selected changes
2764
+ }, []);
2765
+ // Focus selected tab when selected changes.
2766
+ // Reads `options` from `optionsRef` (see comment above) instead of
2767
+ // depending on `options` directly, so a parent re-render that merely
2768
+ // creates a new `options` reference with identical content doesn't call
2769
+ // `focusTab` again and steal focus away from unrelated elements on the
2770
+ // page (e.g. an OTP input).
2576
2771
  useEffect(() => {
2577
- const idx = options.findIndex((opt) => opt.tab === selected && !opt.disabled);
2772
+ const idx = optionsRef.current.findIndex((opt) => opt.tab === selected && !opt.disabled);
2578
2773
  if (idx !== -1) {
2579
2774
  focusTab(idx);
2580
2775
  }
2581
- }, [selected, options]);
2776
+ }, [selected, focusTab]);
2582
2777
  const handleKeyDown = useCallback((idx, e) => {
2583
2778
  const count = options.length;
2584
2779
  if (count === 0)
@@ -2607,7 +2802,7 @@ function DTabs({ children, defaultSelected, onChange, options, className, classN
2607
2802
  }
2608
2803
  }
2609
2804
  }
2610
- }, [options, vertical]);
2805
+ }, [options, vertical, focusTab]);
2611
2806
  let tablistProps = {};
2612
2807
  if (ariaLabelledBy) {
2613
2808
  tablistProps = { 'aria-labelledby': ariaLabelledBy };
@@ -2620,12 +2815,12 @@ function DTabs({ children, defaultSelected, onChange, options, className, classN
2620
2815
  isSelected,
2621
2816
  }), [isSelected]);
2622
2817
  return (jsx(TabContext.Provider, { value: value, children: jsxs("div", Object.assign({ className: classNames({
2623
- 'd-flex w-100': true,
2624
- 'flex-column': !vertical || variant === 'tabs',
2818
+ 'd-tabs': true,
2819
+ 'd-tabs-column': !vertical || variant === 'tabs',
2625
2820
  }), style: style }, dataAttributes, { children: [jsx("ul", Object.assign({ className: classNames(generateClasses), role: "tablist", "aria-orientation": vertical ? 'vertical' : undefined }, tablistProps, { children: options.map((option, idx) => {
2626
2821
  const isTabSelected = !!option.tab && option.tab === selected;
2627
2822
  return (jsx("li", { role: "presentation", className: "nav-item", children: jsx("button", { ref: tabRefs.current[idx], id: `${option.tab}Tab`, className: classNames('nav-link', { active: isTabSelected }, classNameTab), type: "button", role: "tab", "aria-controls": `${option.tab}Pane`, "aria-selected": isTabSelected, tabIndex: isTabSelected ? 0 : -1, disabled: option.disabled, onClick: () => onSelect(option), onKeyDown: (e) => handleKeyDown(idx, e), children: option.label }) }, option.tab));
2628
- }) })), jsx("div", { className: "tab-content w-100", children: children })] })) }));
2823
+ }) })), jsx("div", { className: "d-tabs-content tab-content", children: children })] })) }));
2629
2824
  }
2630
2825
  var DTabs$1 = Object.assign(DTabs, {
2631
2826
  Tab: DTabContent,
@@ -2687,11 +2882,11 @@ function useDToast() {
2687
2882
  if (!description) {
2688
2883
  return (jsx(DToast$1, { className: classNames({
2689
2884
  [`toast-${color}`]: !!color,
2690
- }, 'show'), children: jsxs(DToast$1.Body, { children: [icon && (jsx(DIcon, { className: "toast-icon", icon: icon })), jsx("p", { className: "toast-title", children: title }), jsx("button", { type: "button", className: "d-close align-self-center", "aria-label": "Close", onClick: () => toast.dismiss(id), children: jsx(DIcon, { icon: closeIcon || xLg }) })] }) }));
2885
+ }, 'show'), children: jsxs(DToast$1.Body, { children: [icon && (jsx(DIcon, { className: "toast-icon", icon: icon })), jsx("p", { className: "toast-title", children: title }), jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: () => toast.dismiss(id), children: jsx(DIcon, { icon: closeIcon || xLg }) })] }) }));
2691
2886
  }
2692
2887
  return (jsxs(DToast$1, { className: classNames({
2693
2888
  [`toast-${color}`]: !!color,
2694
- }, 'show'), children: [jsxs(DToast$1.Header, { children: [icon && (jsx(DIcon, { className: "toast-icon", icon: icon })), jsx("p", { className: "toast-title", children: title }), timestamp && (jsx("small", { className: "toast-timestamp", children: timestamp })), jsx("button", { type: "button", className: "d-close align-self-center", "aria-label": "Close", onClick: () => toast.dismiss(id), children: jsx(DIcon, { icon: closeIcon || xLg }) })] }), jsx(DToast$1.Body, { children: jsx("span", { children: description }) })] }));
2889
+ }, 'show'), children: [jsxs(DToast$1.Header, { children: [icon && (jsx(DIcon, { className: "toast-icon", icon: icon })), jsx("p", { className: "toast-title", children: title }), timestamp && (jsx("small", { className: "toast-timestamp", children: timestamp })), jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: () => toast.dismiss(id), children: jsx(DIcon, { icon: closeIcon || xLg }) })] }), jsx(DToast$1.Body, { children: jsx("span", { children: description }) })] }));
2695
2890
  }, toastProps);
2696
2891
  }, [xLg]);
2697
2892
  return {
@@ -2713,11 +2908,10 @@ async function configureI8n(resources, _a = {}) {
2713
2908
  .then((t) => t);
2714
2909
  }
2715
2910
 
2716
- function getQueryString(value, config = {
2717
- useSearch: true,
2718
- }) {
2719
- const urlParams = new URLSearchParams(config.useSearch ? window.location.search : '');
2720
- return urlParams.get(value) || config.default;
2911
+ function getQueryString(value, config = {}) {
2912
+ const { useSearch = true, default: defaultValue } = config;
2913
+ const urlParams = new URLSearchParams(useSearch ? window.location.search : '');
2914
+ return urlParams.get(value) || defaultValue;
2721
2915
  }
2722
2916
 
2723
2917
  function changeQueryString(values, { useSearch = true, pushState = false, } = {}) {
@@ -2747,11 +2941,132 @@ function validatePhoneNumber(phone) {
2747
2941
  }
2748
2942
  }
2749
2943
 
2944
+ const SAFE_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:']);
2945
+ /**
2946
+ * Characters the URL parser drops before resolving a URL, so they cannot be used to hide a
2947
+ * scheme-relative prefix or a dangerous scheme (e.g. `/<TAB>/evil.com`, `java<TAB>script:`).
2948
+ */
2949
+ const IGNORED_CHARS$1 = /[\t\n\r]/g;
2950
+ /**
2951
+ * Two leading separators in any combination. Browsers treat a leading `\` exactly like a
2952
+ * leading `/`, so `//`, `/\`, `\/` and `\\` all resolve to a scheme-relative URL.
2953
+ */
2954
+ const SCHEME_RELATIVE = /^[/\\]{2}/;
2955
+ const LEADING_SEPARATOR = /^[/\\]/;
2956
+ /**
2957
+ * Validates a `href` value and returns it only if it is safe to render as a link,
2958
+ * preventing XSS through unsafe URL schemes and scheme-relative URLs.
2959
+ *
2960
+ * Before validating, the value is trimmed and every tab, line feed and carriage return is
2961
+ * removed, because the URL parser ignores those characters too and they would otherwise
2962
+ * hide an unsafe value from the checks below.
2963
+ *
2964
+ * A `href` is considered safe when it is either:
2965
+ * - An absolute path starting with a single separator (e.g. `/accounts/42`). A leading `\`
2966
+ * is normalized to `/` in the returned value, since that is how the browser resolves it.
2967
+ * - A URL using one of the allowed schemes: `http:`, `https:`, `mailto:`, `tel:`.
2968
+ *
2969
+ * A `href` is rejected (returns `undefined`) when it is:
2970
+ * - Empty or made only of whitespace/ignored characters (`''`, `' '`).
2971
+ * - Scheme-relative (starts with two separators, e.g. `//evil.com`, `/\evil.com`,
2972
+ * `/<TAB>/evil.com`), since the browser would resolve it using the current protocol and it
2973
+ * can be used to redirect to an attacker-controlled host.
2974
+ * - Using a disallowed/dangerous scheme, such as `javascript:` or `data:`
2975
+ * (e.g. `javascript:alert(1)`, `data:text/html,<script>...</script>`).
2976
+ * - Not parseable as an absolute URL and not an absolute path, such as bare fragments
2977
+ * (`#anchor`) or scheme-less relative paths (`relative/path`). These cannot be validated
2978
+ * against `SAFE_SCHEMES`, so they are rejected rather than assumed safe.
2979
+ *
2980
+ * @param href - The raw URL or path to validate, typically coming from user input,
2981
+ * a CMS, or an external API.
2982
+ * @returns The sanitized `href` when safe, `undefined` otherwise.
2983
+ *
2984
+ * @example
2985
+ * sanitizeHref('/accounts/42'); // '/accounts/42'
2986
+ * sanitizeHref('https://example.com'); // 'https://example.com'
2987
+ * sanitizeHref('mailto:test@example.com'); // 'mailto:test@example.com'
2988
+ * sanitizeHref('//evil.com'); // undefined
2989
+ * sanitizeHref('/\\evil.com'); // undefined
2990
+ * sanitizeHref('javascript:alert(1)'); // undefined
2991
+ */
2992
+ function sanitizeHref(href) {
2993
+ const normalized = href.trim().replace(IGNORED_CHARS$1, '');
2994
+ if (!normalized)
2995
+ return undefined;
2996
+ if (SCHEME_RELATIVE.test(normalized))
2997
+ return undefined;
2998
+ if (LEADING_SEPARATOR.test(normalized))
2999
+ return `/${normalized.slice(1)}`;
3000
+ try {
3001
+ const { protocol } = new URL(normalized);
3002
+ return SAFE_SCHEMES.has(protocol) ? normalized : undefined;
3003
+ }
3004
+ catch (_a) {
3005
+ return undefined;
3006
+ }
3007
+ }
3008
+
3009
+ /**
3010
+ * Characters the URL parser drops before resolving a URL, so they cannot be used to hide a
3011
+ * scheme-relative prefix (e.g. `/<TAB>/evil.com`).
3012
+ */
3013
+ const IGNORED_CHARS = /[\t\n\r]/g;
3014
+ /**
3015
+ * Leading separators. Browsers treat a leading `\` exactly like a leading `/`, so both have
3016
+ * to be stripped to prevent scheme-relative URLs (`//evil.com`, `/\evil.com`, `\\evil.com`).
3017
+ */
3018
+ const LEADING_SEPARATORS = /^[/\\]+/;
3019
+ /**
3020
+ * Builds an internal URL from a `path` and a set of query `params`, normalizing leading
3021
+ * separators to prevent scheme-relative URLs (e.g. `//accounts` and `/\accounts` both become
3022
+ * `/accounts`).
3023
+ *
3024
+ * The `path` is trimmed and every tab, line feed and carriage return is removed before
3025
+ * building the result, because the URL parser ignores those characters too and they would
3026
+ * otherwise hide a scheme-relative prefix (`/<TAB>/evil.com` resolves to `//evil.com`).
3027
+ *
3028
+ * Handles the special case where `path` is the literal string `'#'`, which happens when
3029
+ * a Liquid template variable used as a link target is left unconfigured; in that case the
3030
+ * params are ignored and `'#'` is returned as-is instead of building a broken URL.
3031
+ *
3032
+ * @param path - The path to build the URL from. Leading separators are stripped before
3033
+ * building the result (`/accounts`, `//accounts` and `\accounts` are all treated as `accounts`).
3034
+ * @param params - Key/value pairs serialized as the query string.
3035
+ * @returns The resulting URL:
3036
+ * - `'#'` when `path` normalizes to `'#'` (`'#'`, `'/#'`), ignoring the params.
3037
+ * - `'/'` when `path` is empty and there are no params.
3038
+ * - `'/?<query>'` when `path` is empty and there are params.
3039
+ * - `'<path>'` or `'<path>?<query>'` when `path` starts with `#`, since a fragment must not be
3040
+ * prefixed with `/` (it would navigate away from the current document).
3041
+ * - `'/<path>'` or `'/<path>?<query>'` otherwise.
3042
+ *
3043
+ * @example
3044
+ * buildUrl('accounts', { account_id: '42' }); // '/accounts?account_id=42'
3045
+ * buildUrl('//accounts', {}); // '/accounts'
3046
+ * buildUrl('#', { account_id: '42' }); // '#'
3047
+ * buildUrl('#accounts', { account_id: '42' }); // '#accounts?account_id=42'
3048
+ * buildUrl('', { tab: 'movimientos' }); // '/?tab=movimientos'
3049
+ */
3050
+ function buildUrl(path, params) {
3051
+ const normalizedPath = path
3052
+ .trim()
3053
+ .replace(IGNORED_CHARS, '')
3054
+ .replace(LEADING_SEPARATORS, '');
3055
+ if (normalizedPath === '#')
3056
+ return '#';
3057
+ const query = new URLSearchParams(Object.entries(params).map(([key, value]) => [key, String(value)])).toString();
3058
+ if (normalizedPath === '')
3059
+ return query ? `/?${query}` : '/';
3060
+ const prefix = normalizedPath.startsWith('#') ? '' : '/';
3061
+ return `${prefix}${normalizedPath}${query ? `?${query}` : ''}`;
3062
+ }
3063
+
2750
3064
  function DInputPhone(_a, ref) {
2751
3065
  var { id: idProp, style, className, label = '', disabled = false, loading = false, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle, iconEnd, iconEndDisabled, iconEndFamilyClass, iconEndFamilyPrefix, iconEndAriaLabel, iconEndTabIndex, iconEndMaterialStyle, hint, size, invalid = false, valid = false, floatingLabel = false, inputEnd, value, placeholder = '', dataAttributes, onChange, onIconEndClick, countrySelectorProps, filteredCountries, defaultCountry = 'cl' } = _a, inputProps = __rest(_a, ["id", "style", "className", "label", "disabled", "loading", "iconFamilyClass", "iconFamilyPrefix", "iconMaterialStyle", "iconEnd", "iconEndDisabled", "iconEndFamilyClass", "iconEndFamilyPrefix", "iconEndAriaLabel", "iconEndTabIndex", "iconEndMaterialStyle", "hint", "size", "invalid", "valid", "floatingLabel", "inputEnd", "value", "placeholder", "dataAttributes", "onChange", "onIconEndClick", "countrySelectorProps", "filteredCountries", "defaultCountry"]);
2752
3066
  const innerRef = useProvidedRefOrCreate(ref);
2753
3067
  const innerId = useId();
2754
3068
  const id = useMemo(() => idProp || innerId, [idProp, innerId]);
3069
+ const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
2755
3070
  const handleOnIconEndClick = useCallback(() => {
2756
3071
  onIconEndClick === null || onIconEndClick === void 0 ? void 0 : onIconEndClick(value);
2757
3072
  }, [onIconEndClick, value]);
@@ -2825,7 +3140,7 @@ function DInputPhone(_a, ref) {
2825
3140
  [`input-group-${size}`]: !!size,
2826
3141
  'input-group': true,
2827
3142
  'has-validation': invalid || valid,
2828
- }), children: [jsx(CountrySelector, Object.assign({}, countrySelectorProps, { selectedCountry: country.iso2, onSelect: ({ iso2 }) => setCountry(iso2), countries: countries, disabled: disabled || loading, className: classNames('input-group-text', countrySelectorProps === null || countrySelectorProps === void 0 ? void 0 : countrySelectorProps.className) })), dynamicComponent, (iconEnd && !loading) && (jsx("button", { type: "button", className: "input-group-text", id: `${id}End`, onClick: handleOnIconEndClick, disabled: disabled || loading || iconEndDisabled, "aria-label": iconEndAriaLabel, tabIndex: onIconEndClick ? iconEndTabIndex : -1, children: jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }) })), loading && (jsx("div", { className: "input-group-text", id: `${id}Loading`, children: jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsx("span", { className: "visually-hidden", children: "Loading..." }) }) })), !!inputEnd && (jsx("div", { className: "input-group-text", id: `${id}InputEnd`, children: inputEnd }))] }), hint && (jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
3143
+ }), children: [jsx(CountrySelector, Object.assign({}, countrySelectorProps, { selectedCountry: country.iso2, onSelect: ({ iso2 }) => setCountry(iso2), countries: countries, disabled: disabled || loading, className: classNames('input-group-text', countrySelectorProps === null || countrySelectorProps === void 0 ? void 0 : countrySelectorProps.className) })), dynamicComponent, (iconEnd && !loading) && (jsx("button", { type: "button", className: "input-group-text", id: `${id}End`, onClick: handleOnIconEndClick, disabled: disabled || loading || iconEndDisabled, "aria-label": iconEndAriaLabel, tabIndex: onIconEndClick ? iconEndTabIndex : -1, children: jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass !== null && iconEndFamilyClass !== void 0 ? iconEndFamilyClass : familyClass, familyPrefix: iconEndFamilyPrefix !== null && iconEndFamilyPrefix !== void 0 ? iconEndFamilyPrefix : familyPrefix, materialStyle: iconEndMaterialStyle !== null && iconEndMaterialStyle !== void 0 ? iconEndMaterialStyle : materialStyle }) })), loading && (jsx("div", { className: "input-group-text", id: `${id}Loading`, children: jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsx("span", { className: "visually-hidden", children: "Loading..." }) }) })), !!inputEnd && (jsx("div", { className: "input-group-text", id: `${id}InputEnd`, children: inputEnd }))] }), hint && (jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
2829
3144
  }
2830
3145
  const ForwardedDInputPhone = forwardRef(DInputPhone);
2831
3146
  ForwardedDInputPhone.displayName = 'DInputPhone';
@@ -2840,89 +3155,228 @@ function DCreditCard({ brand = 'visa', name, number, holderText = 'Card Holder',
2840
3155
  return (jsxs("div", { className: classNames('d-credit-card', isVertical && 'is-vertical', className), children: [jsxs("div", { className: "d-credit-card-header", children: [jsx("img", { src: logoImage || BRAND_LOGOS[brand] || DEFAULT_IMAGE, alt: brand, className: "d-credit-card-logo", width: 100 }), isChipVisible && (jsx("div", { className: "d-credit-card-chip", children: jsx("img", { src: CHIP_IMAGE, alt: "chip", width: 30, className: "d-credit-card-chip-image" }) }))] }), jsxs("div", { className: "d-credit-card-details", children: [jsx("div", { className: "d-credit-card-number", children: number }), jsx("small", { className: "d-credit-card-holder-text", children: holderText }), jsx("span", { className: "d-credit-card-name", children: name })] })] }));
2841
3156
  }
2842
3157
 
3158
+ // Gap between the toggle and the menu.
3159
+ const GAP = 4;
3160
+ // Minimum distance the menu should keep from the viewport edges.
3161
+ const VIEWPORT_PADDING = 8;
3162
+ // Minimum usable height left for the menu before we consider a side unusable.
3163
+ const MIN_USABLE_SPACE = 120;
2843
3164
  const getItemClass = (action) => classNames({
2844
3165
  'dropdown-item d-flex align-items-center': true,
2845
3166
  [`dropdown-item-${action.color}`]: !!action.color,
2846
3167
  disabled: action.disabled,
2847
3168
  });
2848
- function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal = false, placement = 'auto', }) {
3169
+ const clamp = (value, min, max) => {
3170
+ if (max < min)
3171
+ return min;
3172
+ return Math.min(Math.max(value, min), max);
3173
+ };
3174
+ /**
3175
+ * `position: fixed` is normally relative to the viewport, but any ancestor
3176
+ * with a `transform`, `perspective`, `filter`, `will-change` (of those) or a
3177
+ * non-trivial `contain` establishes a new containing block, making `fixed`
3178
+ * behave like `absolute` relative to that ancestor instead (e.g. Storybook's
3179
+ * docs canvas wrapper, animated cards, sticky containers, etc.). We detect
3180
+ * that ancestor so the computed coordinates can be adjusted accordingly,
3181
+ * keeping the menu correctly anchored to the toggle in every context.
3182
+ */
3183
+ const getFixedPositioningOffset = (fromEl) => {
3184
+ var _a;
3185
+ let node = (_a = fromEl === null || fromEl === void 0 ? void 0 : fromEl.parentElement) !== null && _a !== void 0 ? _a : null;
3186
+ while (node && node !== document.body) {
3187
+ const cs = window.getComputedStyle(node);
3188
+ // Treat empty/undefined values as "unset" (jsdom returns "" rather than
3189
+ // the CSS initial value like "none" for some of these properties).
3190
+ const isSet = (value) => !!value && value !== 'none';
3191
+ const establishesContainingBlock = isSet(cs.transform)
3192
+ || isSet(cs.perspective)
3193
+ || isSet(cs.filter)
3194
+ || isSet(cs.backdropFilter)
3195
+ || ['transform', 'perspective', 'filter'].some((prop) => { var _a; return (_a = cs.willChange) === null || _a === void 0 ? void 0 : _a.includes(prop); })
3196
+ || cs.contain.split(' ').some((value) => ['layout', 'paint', 'strict', 'content'].includes(value));
3197
+ if (establishesContainingBlock) {
3198
+ const rect = node.getBoundingClientRect();
3199
+ return { top: rect.top, left: rect.left };
3200
+ }
3201
+ node = node.parentElement;
3202
+ }
3203
+ return { top: 0, left: 0 };
3204
+ };
3205
+ /**
3206
+ * Resolves where the menu should render (flip) and where it should sit along
3207
+ * the cross axis (shift), so it always stays fully inside the viewport
3208
+ * regardless of where the toggle is placed or how the viewport is resized.
3209
+ * This mimics floating-ui's `flip` + `shift` middlewares without adding the
3210
+ * dependency, keeping the existing Bootstrap markup/classes.
3211
+ */
3212
+ const computeCoords = (toggleRect, menuSize, placement, alignment) => {
3213
+ const viewportWidth = window.innerWidth;
3214
+ const viewportHeight = window.innerHeight;
3215
+ const spaceBelow = viewportHeight - toggleRect.bottom;
3216
+ const spaceAbove = toggleRect.top;
3217
+ const spaceLeft = toggleRect.left;
3218
+ const spaceRight = viewportWidth - toggleRect.right;
3219
+ let side = placement === 'auto'
3220
+ ? 'down'
3221
+ : placement;
3222
+ if (placement === 'auto') {
3223
+ side = spaceBelow >= menuSize.height + GAP || spaceBelow >= spaceAbove ? 'down' : 'up';
3224
+ }
3225
+ // Flip within the current axis if the chosen side can't fit the menu but
3226
+ // the opposite side (same axis) can.
3227
+ if (side === 'down' && spaceBelow < menuSize.height + GAP && spaceAbove > spaceBelow) {
3228
+ side = 'up';
3229
+ }
3230
+ else if (side === 'up' && spaceAbove < menuSize.height + GAP && spaceBelow > spaceAbove) {
3231
+ side = 'down';
3232
+ }
3233
+ else if (side === 'start' && spaceLeft < menuSize.width + GAP && spaceRight > spaceLeft) {
3234
+ side = 'end';
3235
+ }
3236
+ else if (side === 'end' && spaceRight < menuSize.width + GAP && spaceLeft > spaceRight) {
3237
+ side = 'start';
3238
+ }
3239
+ // Cross-axis fallback: e.g. a horizontally-centered toggle on a narrow
3240
+ // viewport can't open sideways (neither `start` nor `end` fit), but there
3241
+ // is plenty of room above/below — switch the whole axis in that case
3242
+ // (and vice versa for `down`/`up` squeezed against a short viewport).
3243
+ const bestVerticalSpace = Math.max(spaceBelow, spaceAbove);
3244
+ const bestHorizontalSpace = Math.max(spaceLeft, spaceRight);
3245
+ if (side === 'down' || side === 'up') {
3246
+ if (bestVerticalSpace < MIN_USABLE_SPACE && bestHorizontalSpace > bestVerticalSpace) {
3247
+ side = spaceRight >= spaceLeft ? 'end' : 'start';
3248
+ }
3249
+ }
3250
+ else if (bestHorizontalSpace < menuSize.width + GAP
3251
+ && bestVerticalSpace > bestHorizontalSpace) {
3252
+ side = spaceBelow >= spaceAbove ? 'down' : 'up';
3253
+ }
3254
+ if (side === 'down' || side === 'up') {
3255
+ const top = side === 'down'
3256
+ ? toggleRect.bottom + GAP
3257
+ : toggleRect.top - menuSize.height - GAP;
3258
+ // Align horizontally per the requested `alignment` (start/end/center), then
3259
+ // fall back to the opposite edge if the preferred alignment would overflow
3260
+ // the viewport, and clamp as a final safety net so it never overflows.
3261
+ let left;
3262
+ if (alignment === 'end') {
3263
+ left = toggleRect.right - menuSize.width;
3264
+ }
3265
+ else if (alignment === 'center') {
3266
+ left = toggleRect.left + (toggleRect.width / 2) - (menuSize.width / 2);
3267
+ }
3268
+ else {
3269
+ left = toggleRect.left;
3270
+ }
3271
+ if (left + menuSize.width > viewportWidth - VIEWPORT_PADDING && alignment !== 'end') {
3272
+ const altLeft = toggleRect.right - menuSize.width;
3273
+ if (altLeft >= VIEWPORT_PADDING)
3274
+ left = altLeft;
3275
+ }
3276
+ else if (left < VIEWPORT_PADDING && alignment !== 'start') {
3277
+ const altLeft = toggleRect.left;
3278
+ if (altLeft + menuSize.width <= viewportWidth - VIEWPORT_PADDING)
3279
+ left = altLeft;
3280
+ }
3281
+ left = clamp(left, VIEWPORT_PADDING, Math.max(viewportWidth - menuSize.width - VIEWPORT_PADDING, VIEWPORT_PADDING));
3282
+ const availableHeight = side === 'down' ? spaceBelow : spaceAbove;
3283
+ // Cap strictly to the space actually available on the resolved side —
3284
+ // MIN_USABLE_SPACE is only meant to influence the flip/shift decision
3285
+ // above, not to force a taller box than what physically fits and
3286
+ // overflow the viewport.
3287
+ const maxUsableHeight = Math.max(availableHeight - GAP - VIEWPORT_PADDING, 0);
3288
+ return {
3289
+ top,
3290
+ left,
3291
+ minWidth: Math.max(toggleRect.width, 160),
3292
+ maxHeight: `${maxUsableHeight}px`,
3293
+ resolvedSide: side,
3294
+ };
3295
+ }
3296
+ // side is 'start' or 'end'
3297
+ let left = side === 'start'
3298
+ ? toggleRect.left - menuSize.width - GAP
3299
+ : toggleRect.right + GAP;
3300
+ // Safety-net clamp: in rare cases where the toggle is squeezed so tightly
3301
+ // that no side of any axis has enough room, keep the menu inside the
3302
+ // viewport rather than letting it render off-screen.
3303
+ left = clamp(left, VIEWPORT_PADDING, Math.max(viewportWidth - menuSize.width - VIEWPORT_PADDING, VIEWPORT_PADDING));
3304
+ // Shift vertically: align with the toggle's top edge by default, but switch
3305
+ // to the bottom edge (or clamp) if that would overflow the viewport.
3306
+ let { top } = toggleRect;
3307
+ if (top + menuSize.height > viewportHeight - VIEWPORT_PADDING) {
3308
+ top = toggleRect.bottom - menuSize.height;
3309
+ }
3310
+ top = clamp(top, VIEWPORT_PADDING, Math.max(viewportHeight - menuSize.height - VIEWPORT_PADDING, VIEWPORT_PADDING));
3311
+ return {
3312
+ top,
3313
+ left,
3314
+ minWidth: Math.max(toggleRect.width, 160),
3315
+ maxHeight: `${Math.max(viewportHeight - top - VIEWPORT_PADDING, 0)}px`,
3316
+ resolvedSide: side,
3317
+ };
3318
+ };
3319
+ function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal = false, placement = 'auto', alignment = 'start', }) {
2849
3320
  const [open, setOpen] = useState(false);
2850
- const [position, setPosition] = useState('down');
2851
- const [menuCoords, setMenuCoords] = useState(null);
2852
- // Used in default (non-portal) mode: wraps the entire dropdown
2853
- const dropdownRef = useRef(null);
2854
- // Used in portal mode: ref on the toggle wrapper to read its viewport coords
3321
+ const [coords, setCoords] = useState(null);
3322
+ // Initialize from `placement` (falling back to 'down' for 'auto') so the
3323
+ // wrapper's `drop-*` class reflects the requested side even before the
3324
+ // first open/measurement, matching the previous `drop-${placement}` class
3325
+ // behavior (relevant for Bootstrap caret/orientation styling).
3326
+ const [resolvedSide, setResolvedSide] = useState(placement === 'auto' ? 'down' : placement);
3327
+ // Wraps the toggle in both modes — used to read its viewport-relative rect.
2855
3328
  const toggleRef = useRef(null);
2856
- // Ref on the rendered <ul> — used for outside-click detection in portal mode
3329
+ // Ref on the rendered <ul> — used to measure its size and for outside-click detection.
2857
3330
  const menuRef = useRef(null);
2858
3331
  const toggle = () => {
2859
- setMenuCoords(null);
3332
+ setCoords(null);
2860
3333
  setOpen((prev) => !prev);
2861
3334
  };
2862
- const resolvedInlinePosition = placement === 'auto' ? position : placement;
2863
- // Compute fixed coords from the toggle's bounding rect (portal mode only)
2864
- const computePortalCoords = useCallback(() => {
2865
- if (!toggleRef.current)
3335
+ // Measures the toggle + menu and (re)computes fixed, pixel-perfect coords
3336
+ // with collision detection, so the menu never overflows the viewport.
3337
+ const updatePosition = useCallback(() => {
3338
+ if (!toggleRef.current || !menuRef.current)
3339
+ return;
3340
+ const toggleRect = toggleRef.current.getBoundingClientRect();
3341
+ // If the toggle itself has scrolled completely out of the viewport
3342
+ // (regardless of `placement`), close the menu instead of leaving it
3343
+ // rendered detached from the toggle that opened it.
3344
+ const toggleIsMeasured = toggleRect.width > 0 || toggleRect.height > 0;
3345
+ const toggleIsOutOfView = toggleRect.bottom <= 0
3346
+ || toggleRect.top >= window.innerHeight
3347
+ || toggleRect.right <= 0
3348
+ || toggleRect.left >= window.innerWidth;
3349
+ if (toggleIsMeasured && toggleIsOutOfView) {
3350
+ setOpen(false);
2866
3351
  return;
2867
- const rect = toggleRef.current.getBoundingClientRect();
2868
- const spaceRight = window.innerWidth - rect.right;
2869
- const spaceBottom = window.innerHeight - rect.bottom;
2870
- const spaceTop = rect.top;
2871
- let resolvedPlacement;
2872
- if (placement === 'auto') {
2873
- if (spaceBottom < 150) {
2874
- resolvedPlacement = 'up';
2875
- }
2876
- else if (spaceRight < 150) {
2877
- resolvedPlacement = 'start';
2878
- }
2879
- else {
2880
- resolvedPlacement = 'down';
2881
- }
2882
- }
2883
- else {
2884
- resolvedPlacement = placement;
2885
- }
2886
- const openStart = resolvedPlacement === 'start';
2887
- const openEnd = resolvedPlacement === 'end';
2888
- const openUp = resolvedPlacement === 'up';
2889
- let availableHeight = spaceBottom;
2890
- if (openUp) {
2891
- availableHeight = spaceTop;
2892
- }
2893
- else if (openStart || openEnd) {
2894
- availableHeight = window.innerHeight - rect.top;
2895
- }
2896
- const verticalCoords = openUp
2897
- ? { bottom: window.innerHeight - rect.top + 4 }
2898
- : { top: openStart || openEnd ? rect.top : rect.bottom + 4 };
2899
- let horizontalCoords;
2900
- if (openStart) {
2901
- horizontalCoords = { right: window.innerWidth - rect.left + 4 };
2902
- }
2903
- else if (openEnd) {
2904
- horizontalCoords = { left: rect.right + 4 };
2905
- }
2906
- else {
2907
- horizontalCoords = { left: rect.left };
2908
3352
  }
2909
- setMenuCoords(Object.assign(Object.assign(Object.assign({}, verticalCoords), horizontalCoords), { minWidth: Math.max(rect.width, 160), maxHeight: `${Math.max(availableHeight - 12, 120)}px` }));
2910
- }, [placement]);
2911
- // Outside-click: default mode
2912
- useEffect(() => {
2913
- if (asPortal)
2914
- return () => { };
2915
- const handler = (event) => {
2916
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
2917
- setOpen(false);
2918
- }
2919
- };
2920
- document.addEventListener('mousedown', handler);
2921
- return () => document.removeEventListener('mousedown', handler);
2922
- }, [asPortal]);
2923
- // Outside-click: portal mode (must check both toggle and floating menu)
2924
- useEffect(() => {
2925
- if (!asPortal || !open)
3353
+ const menuRect = menuRef.current.getBoundingClientRect();
3354
+ const _a = computeCoords(toggleRect, { width: menuRect.width, height: menuRect.height }, placement, alignment), { resolvedSide: side } = _a, menuCoords = __rest(_a, ["resolvedSide"]);
3355
+ // In portal mode the menu is appended to document.body, whose containing
3356
+ // block for `fixed` is always the viewport (no adjustment needed). In
3357
+ // inline mode the menu stays next to the toggle, so we must look for a
3358
+ // containing-block-establishing ancestor starting from the toggle.
3359
+ const offset = asPortal
3360
+ ? { top: 0, left: 0 }
3361
+ : getFixedPositioningOffset(toggleRef.current);
3362
+ setResolvedSide(side);
3363
+ setCoords(Object.assign(Object.assign({}, menuCoords), { top: menuCoords.top - offset.top, left: menuCoords.left - offset.left }));
3364
+ }, [placement, alignment, asPortal]);
3365
+ // Throttles scroll/resize-triggered updates to at most once per frame,
3366
+ // avoiding repeated forced reflows on busy/high-frequency scroll events.
3367
+ const rafIdRef = useRef(null);
3368
+ const scheduleUpdatePosition = useCallback(() => {
3369
+ if (rafIdRef.current !== null)
3370
+ return;
3371
+ rafIdRef.current = window.requestAnimationFrame(() => {
3372
+ rafIdRef.current = null;
3373
+ updatePosition();
3374
+ });
3375
+ }, [updatePosition]);
3376
+ // Outside-click detection (checks both the toggle and the floating menu,
3377
+ // since in portal mode the menu isn't a DOM descendant of the toggle).
3378
+ useLayoutEffect(() => {
3379
+ if (!open)
2926
3380
  return () => { };
2927
3381
  const handler = (event) => {
2928
3382
  var _a, _b;
@@ -2933,35 +3387,25 @@ function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal
2933
3387
  };
2934
3388
  document.addEventListener('mousedown', handler);
2935
3389
  return () => document.removeEventListener('mousedown', handler);
2936
- }, [asPortal, open]);
2937
- // Auto-position: default mode
2938
- useEffect(() => {
2939
- if (asPortal || !open || !dropdownRef.current || placement !== 'auto')
2940
- return;
2941
- const rect = dropdownRef.current.getBoundingClientRect();
2942
- const spaceBottom = window.innerHeight - rect.bottom;
2943
- const spaceRight = window.innerWidth - rect.right;
2944
- if (spaceBottom < 150)
2945
- setPosition('up');
2946
- else if (spaceRight < 150)
2947
- setPosition('start');
2948
- else
2949
- setPosition('down');
2950
- }, [asPortal, open, placement]);
2951
- // Compute + track coords: portal mode
2952
- // Re-runs whenever the menu opens and keeps coords fresh on scroll/resize
2953
- useEffect(() => {
2954
- if (!asPortal || !open)
3390
+ }, [open]);
3391
+ // Computes the initial position synchronously (before paint, to avoid a
3392
+ // flicker) and keeps it fresh while the menu is open and the viewport
3393
+ // scrolls or resizes (throttled to one update per frame, see above).
3394
+ useLayoutEffect(() => {
3395
+ if (!open)
2955
3396
  return () => { };
2956
- computePortalCoords();
2957
- const update = () => computePortalCoords();
2958
- window.addEventListener('scroll', update, { passive: true, capture: true });
2959
- window.addEventListener('resize', update, { passive: true });
3397
+ updatePosition();
3398
+ window.addEventListener('scroll', scheduleUpdatePosition, { passive: true, capture: true });
3399
+ window.addEventListener('resize', scheduleUpdatePosition, { passive: true });
2960
3400
  return () => {
2961
- window.removeEventListener('scroll', update, { capture: true });
2962
- window.removeEventListener('resize', update);
3401
+ window.removeEventListener('scroll', scheduleUpdatePosition, { capture: true });
3402
+ window.removeEventListener('resize', scheduleUpdatePosition);
3403
+ if (rafIdRef.current !== null) {
3404
+ window.cancelAnimationFrame(rafIdRef.current);
3405
+ rafIdRef.current = null;
3406
+ }
2963
3407
  };
2964
- }, [asPortal, open, computePortalCoords]);
3408
+ }, [open, updatePosition, scheduleUpdatePosition]);
2965
3409
  let ToggleElement;
2966
3410
  if (dropdownToggle) {
2967
3411
  ToggleElement = typeof dropdownToggle === 'function'
@@ -2971,57 +3415,30 @@ function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal
2971
3415
  else {
2972
3416
  ToggleElement = (jsx(DButtonIcon, { variant: "link", stopPropagationEnabled: false, "aria-label": "Toggle Dropdown", "aria-haspopup": "menu", "aria-expanded": open, onClick: toggle, icon: "MoreVertical" }));
2973
3417
  }
2974
- const portalMenuStyle = asPortal && menuCoords
3418
+ // Until the first measurement is available, keep the menu off-screen but
3419
+ // measurable (visibility: hidden preserves layout, unlike display: none).
3420
+ const menuStyle = coords
2975
3421
  ? {
2976
3422
  position: 'fixed',
2977
- top: menuCoords.top,
2978
- bottom: menuCoords.bottom,
2979
- left: menuCoords.left,
2980
- right: menuCoords.right,
2981
- minWidth: menuCoords.minWidth,
2982
- maxHeight: menuCoords.maxHeight,
3423
+ top: coords.top,
3424
+ left: coords.left,
3425
+ minWidth: coords.minWidth,
3426
+ maxHeight: coords.maxHeight,
2983
3427
  overflowY: 'auto',
2984
3428
  zIndex: 1050,
2985
3429
  transform: 'none',
3430
+ visibility: 'visible',
2986
3431
  }
2987
- : undefined;
2988
- let inlineTop = '100%';
2989
- if (resolvedInlinePosition === 'up') {
2990
- inlineTop = 'auto';
2991
- }
2992
- else if (resolvedInlinePosition === 'start' || resolvedInlinePosition === 'end') {
2993
- inlineTop = 0;
2994
- }
2995
- let inlineLeft = 0;
2996
- if (resolvedInlinePosition === 'start') {
2997
- inlineLeft = 'auto';
2998
- }
2999
- else if (resolvedInlinePosition === 'end') {
3000
- inlineLeft = '100%';
3001
- }
3002
- let inlineRight = 'auto';
3003
- if (resolvedInlinePosition === 'start') {
3004
- inlineRight = '100%';
3005
- }
3006
- let inlineTransform = 'translateY(4px)';
3007
- if (resolvedInlinePosition === 'up') {
3008
- inlineTransform = 'translateY(-4px)';
3009
- }
3010
- else if (resolvedInlinePosition === 'start') {
3011
- inlineTransform = 'translateX(-4px)';
3012
- }
3013
- else if (resolvedInlinePosition === 'end') {
3014
- inlineTransform = 'translateX(4px)';
3015
- }
3016
- const inlineMenuStyle = {
3017
- position: 'absolute',
3018
- top: inlineTop,
3019
- bottom: resolvedInlinePosition === 'up' ? '100%' : 'auto',
3020
- left: inlineLeft,
3021
- right: inlineRight,
3022
- transform: inlineTransform,
3023
- };
3024
- const menuItems = (jsx("ul", { ref: menuRef, role: "menu", className: classNames('dropdown-menu p-2', { show: open }, classNameMenu), style: portalMenuStyle !== null && portalMenuStyle !== void 0 ? portalMenuStyle : inlineMenuStyle, children: actions.map((action, index) => {
3432
+ : {
3433
+ position: 'fixed',
3434
+ top: 0,
3435
+ left: 0,
3436
+ visibility: 'hidden',
3437
+ pointerEvents: 'none',
3438
+ zIndex: 1050,
3439
+ transform: 'none',
3440
+ };
3441
+ const menuItems = (jsx("ul", { ref: menuRef, role: "menu", className: classNames('dropdown-menu p-2', { show: open }, classNameMenu), style: menuStyle, children: actions.map((action, index) => {
3025
3442
  if (action.isDivider) {
3026
3443
  return jsx("hr", { className: "dropdown-divider" }, index);
3027
3444
  }
@@ -3040,10 +3457,7 @@ function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal
3040
3457
  }
3041
3458
  }, disabled: action.disabled, children: [action.icon && jsx(DIcon, { icon: action.icon, className: "me-2", size: "1rem" }), action.label] })) }, index));
3042
3459
  }) }));
3043
- if (asPortal) {
3044
- return (jsxs("div", { ref: toggleRef, className: classNames('dropdown', className), children: [ToggleElement, open && menuCoords && createPortal(menuItems, document.body)] }));
3045
- }
3046
- return (jsxs("div", { className: classNames(`dropdown drop-${resolvedInlinePosition}`, className), ref: dropdownRef, children: [ToggleElement, menuItems] }));
3460
+ return (jsxs("div", { ref: toggleRef, className: classNames(`dropdown drop-${resolvedSide} d-inline-block`, className), children: [ToggleElement, open && (asPortal ? createPortal(menuItems, document.body) : menuItems)] }));
3047
3461
  }
3048
3462
 
3049
3463
  function useScreenshot() {
@@ -3073,13 +3487,18 @@ function useScreenshot() {
3073
3487
 
3074
3488
  function useScreenshotDownload() {
3075
3489
  const { clipRef, takeBlob } = useScreenshot();
3076
- const download = useCallback(async () => {
3077
- const blob = await takeBlob();
3490
+ const download = useCallback(async (fileName = 'voucher') => {
3491
+ const blob = await takeBlob('image/jpeg');
3078
3492
  const url = window.URL.createObjectURL(blob);
3079
3493
  const link = window.document.createElement('a');
3080
3494
  link.style.display = 'none';
3081
3495
  link.href = url;
3082
- link.download = 'voucher.jpg';
3496
+ // Fall back to the default base name when the caller passes a blank/whitespace value,
3497
+ // so the file is never named just ".jpg".
3498
+ const safeFileName = fileName.trim() || 'voucher';
3499
+ // The extension is always appended by the hook to guarantee a valid image file,
3500
+ // regardless of what fileName the caller passes (e.g. "receipt.png" -> "receipt.png.jpg").
3501
+ link.download = `${safeFileName}.jpg`;
3083
3502
  document.body.appendChild(link);
3084
3503
  link.click();
3085
3504
  document.body.removeChild(link);
@@ -3093,11 +3512,15 @@ function useScreenshotDownload() {
3093
3512
 
3094
3513
  function useScreenshotWebShare() {
3095
3514
  const { takeBlob, clipRef } = useScreenshot();
3096
- const share = useCallback(async () => {
3097
- const blob = await takeBlob();
3098
- const image = new File([blob], 'voucher.jpeg', { type: 'image/jpeg' });
3099
- if (!navigator.canShare
3100
- && (navigator.canShare && !navigator.canShare({ files: [image] }))) {
3515
+ const share = useCallback(async (fileName = 'voucher') => {
3516
+ const blob = await takeBlob('image/jpeg');
3517
+ // Fall back to the default base name when the caller passes a blank/whitespace value,
3518
+ // so the file is never named just ".jpeg".
3519
+ const safeFileName = fileName.trim() || 'voucher';
3520
+ // The extension is always appended by the hook to guarantee a valid image file,
3521
+ // regardless of what fileName the caller passes (e.g. "receipt.png" -> "receipt.png.jpeg").
3522
+ const image = new File([blob], `${safeFileName}.jpeg`, { type: 'image/jpeg' });
3523
+ if (!navigator.canShare || !navigator.canShare({ files: [image] })) {
3101
3524
  window.print();
3102
3525
  return;
3103
3526
  }
@@ -3109,11 +3532,11 @@ function useScreenshotWebShare() {
3109
3532
  };
3110
3533
  }
3111
3534
 
3112
- function DVoucher({ amount, amountDetails, icon, title, onError, message, downloadText = 'Download', shareText = 'Share', className, children, }) {
3535
+ function DVoucher({ amount, amountDetails, icon, title, onError, message, downloadText = 'Download', shareText = 'Share', fileName = 'voucher', hideActions = false, className, children, }) {
3113
3536
  const { shareRef, share } = useScreenshotWebShare();
3114
3537
  const { downloadRef, download } = useScreenshotDownload();
3115
3538
  const handleShare = () => {
3116
- share()
3539
+ share(fileName)
3117
3540
  .catch(async (err) => {
3118
3541
  if (onError) {
3119
3542
  await onError(err);
@@ -3124,7 +3547,7 @@ function DVoucher({ amount, amountDetails, icon, title, onError, message, downlo
3124
3547
  });
3125
3548
  };
3126
3549
  const handleDownload = () => {
3127
- download()
3550
+ download(fileName)
3128
3551
  .catch(async (err) => {
3129
3552
  if (onError) {
3130
3553
  await onError(err);
@@ -3152,80 +3575,36 @@ function DVoucher({ amount, amountDetails, icon, title, onError, message, downlo
3152
3575
  return (jsx("div", { className: classNames('d-voucher', className), ref: (el) => {
3153
3576
  shareRef.current = el;
3154
3577
  downloadRef.current = el;
3155
- }, children: jsxs("div", { children: [jsxs("div", { className: "d-voucher-header", children: [resolvedIconProps && (jsx(DIcon, Object.assign({}, resolvedIconProps))), jsxs("div", { className: "text-center", children: [jsx("h3", { className: "mb-2", children: title }), jsx("p", { className: "m-0", children: message })] })] }), amount && (jsxs("div", { className: "d-voucher-amount", children: [jsx("div", { className: classNames('text-center fw-bold fs-3', amountDetails ? 'mb-1' : 'm-0'), children: amount }), amountDetails] })), jsx("hr", { className: "my-4" }), children, jsx("hr", { className: "my-4" }), jsxs("div", { className: "d-voucher-footer", children: [jsx(DButton, { onClick: handleShare, iconStart: "Share2", text: shareText, variant: "outline", size: "sm" }), jsx(DButton, { onClick: handleDownload, iconStart: "Download", text: downloadText, variant: "outline", size: "sm" })] })] }) }));
3156
- }
3157
-
3158
- function useCountdown(seconds) {
3159
- const [secondsLeft, setSecondsLeft] = useState(seconds);
3160
- const [isActive, setIsActive] = useState(true);
3161
- const resetCountdown = useCallback((newSeconds = seconds) => {
3162
- setIsActive(false);
3163
- setSecondsLeft(newSeconds);
3164
- }, [seconds]);
3165
- const restartCountdown = useCallback(() => {
3166
- resetCountdown(seconds);
3167
- setIsActive(true);
3168
- }, [resetCountdown, seconds]);
3169
- useEffect(() => {
3170
- if (!isActive) {
3171
- return () => { };
3172
- }
3173
- const interval = setInterval(() => {
3174
- setSecondsLeft((prevSeconds) => {
3175
- const newSeconds = prevSeconds - 1;
3176
- if (newSeconds <= 0) {
3177
- clearInterval(interval);
3178
- setIsActive(false);
3179
- return 0;
3180
- }
3181
- return newSeconds;
3182
- });
3183
- }, 1000);
3184
- return () => clearInterval(interval);
3185
- }, [isActive]);
3186
- return { secondsLeft, restartCountdown };
3578
+ }, children: jsxs("div", { children: [jsxs("div", { className: "d-voucher-header", children: [resolvedIconProps && (jsx(DIcon, Object.assign({}, resolvedIconProps))), jsxs("div", { className: "d-voucher-title-group", children: [jsx("h3", { className: "d-voucher-title", children: title }), jsx("p", { className: "d-voucher-message", children: message })] })] }), amount && (jsxs("div", { className: "d-voucher-amount", children: [jsx("div", { className: classNames('d-voucher-amount-value', { 'd-voucher-amount-value-with-details': !!amountDetails }), children: amount }), amountDetails] })), jsx("hr", { className: "d-voucher-divider" }), children, !hideActions && (jsxs(Fragment, { children: [jsx("hr", { className: "my-4" }), jsxs("div", { className: "d-voucher-footer", children: [jsx(DButton, { onClick: handleShare, iconStart: "Share2", text: shareText, variant: "outline", size: "sm" }), jsx(DButton, { onClick: handleDownload, iconStart: "Download", text: downloadText, variant: "outline", size: "sm" })] })] }))] }) }));
3187
3579
  }
3188
3580
 
3189
3581
  const defaultMessage = (secs) => (secs > 0
3190
3582
  ? `Didn't get any code? Resend in: ${secs}s`
3191
3583
  : "Didn't get any code?");
3192
- function OtpCountdown({ seconds, resendText, message, }) {
3193
- const { secondsLeft, restartCountdown } = useCountdown(seconds);
3194
- return (jsxs("div", { className: "d-flex gap-2 align-items-center", children: [jsx("p", { className: "mb-0 flex-1", children: message ? message(secondsLeft) : defaultMessage(secondsLeft) }), jsx(DButton, { text: resendText, variant: "link", className: "text-nowrap", disabled: secondsLeft > 0, onClick: restartCountdown })] }));
3584
+ function OtpCountdown({ secondsLeft, restartCountdown, resendText, message, }) {
3585
+ return (jsxs("div", { className: "d-otp-countdown", children: [jsx("p", { className: "d-otp-countdown-text", children: message ? message(secondsLeft) : defaultMessage(secondsLeft) }), jsx(DButton, { text: resendText, variant: "link", className: "text-nowrap", disabled: secondsLeft > 0, onClick: restartCountdown })] }));
3195
3586
  }
3196
3587
 
3197
3588
  const TEXT_PROPS = {
3198
3589
  resend: 'Resend',
3199
- resendText: 'Resend code',
3590
+ resendText: 'Resend',
3200
3591
  submit: 'Authorize and continue',
3201
3592
  title: 'We will send you a 6-digit code to your associated phone number so you can continue with your request.',
3593
+ invalidCode: 'Invalid code, please try again.',
3202
3594
  contact: (jsxs(Fragment, { children: [jsx("span", { children: "Problems with your digital token? Contact us" }), ' ', jsx("a", { href: "https://www.modyo.com", className: "link-primary text-nowrap", target: "_blank", rel: "noreferrer", children: "Contact us" })] })),
3203
3595
  };
3204
3596
  function DOtp({ className, action, isLoading, otpSize = 6, texts = TEXT_PROPS, seconds = 15, }) {
3205
- const [otp, setOtp] = useState('');
3206
- const [invalid, setInvalid] = useState(false);
3207
- const handler = useCallback(async () => {
3208
- if (otp.length < otpSize) {
3209
- setInvalid(true);
3210
- return;
3211
- }
3212
- setInvalid(false);
3213
- await action();
3214
- }, [
3215
- otp.length,
3216
- action,
3217
- otpSize,
3218
- ]);
3219
- return (jsxs("div", { className: className, children: [jsx("p", { children: texts.title }), jsxs("div", { className: "d-flex flex-column gap-6 pb-4 px-3", children: [jsxs("div", { className: "d-flex flex-column gap-6", children: [jsx(DInputPin, { className: "modal-otp-pin", characters: otpSize, onChange: (e) => setOtp(e), invalid: invalid && otp.length < otpSize, placeholder: "0" }), jsx(OtpCountdown, { seconds: seconds, resendText: texts.resend })] }), jsx("hr", { className: "m-0" }), jsxs("div", { className: "d-flex flex-column flex-lg-row gap-4 align-items-center", children: [jsx(DButton, { text: texts.submit, onClick: () => {
3220
- handler().catch((err) => {
3597
+ const { setOtp, invalid, submit, isLoading: isSubmitting, secondsLeft, restartCountdown, } = useOtp({ action, otpSize, seconds });
3598
+ return (jsxs("div", { className: className, children: [jsx("p", { children: texts.title }), jsxs("div", { className: "d-otp d-otp-content", children: [jsxs("div", { className: "d-otp-fields", children: [jsx(DInputPin, { className: "modal-otp-pin", characters: otpSize, onChange: (e) => setOtp(e), invalid: invalid, hint: invalid ? texts.invalidCode : undefined, placeholder: "0" }), jsx(OtpCountdown, { secondsLeft: secondsLeft, restartCountdown: restartCountdown, resendText: texts.resendText })] }), jsx("hr", { className: "d-otp-divider" }), jsxs("div", { className: "d-otp-footer", children: [jsx(DButton, { text: texts.submit, onClick: () => {
3599
+ submit().catch((err) => {
3221
3600
  // eslint-disable-next-line no-console
3222
3601
  console.error('Error in DOtp action:', err);
3223
3602
  });
3224
- }, loading: isLoading }), jsx("p", { className: "small ms-lg-auto mb-0", children: texts.contact })] })] })] }));
3603
+ }, loading: isLoading || isSubmitting }), jsx("p", { className: "d-otp-contact", children: texts.contact })] })] })] }));
3225
3604
  }
3226
3605
 
3227
3606
  function DefaultErrorBoundary({ resetErrorBoundary }) {
3228
- return (jsx(DAlert, { color: "danger", showClose: false, children: jsxs("div", { className: "d-flex align-items-center gap-2", children: [jsx("span", { children: "An unexpected error occurred." }), jsx(DButton, { color: "secondary", variant: "outline", size: "sm", onClick: resetErrorBoundary, children: "Retry" })] }) }));
3607
+ return (jsx(DAlert, { color: "danger", showClose: false, children: jsxs("div", { className: "d-error-boundary-content", children: [jsx("span", { children: "An unexpected error occurred." }), jsx(DButton, { color: "secondary", variant: "outline", size: "sm", onClick: resetErrorBoundary, children: "Retry" })] }) }));
3229
3608
  }
3230
3609
 
3231
3610
  function DErrorBoundary({ name, fallback, resetKeys, onReset, onError, children, }) {
@@ -3243,15 +3622,15 @@ function DErrorBoundary({ name, fallback, resetKeys, onReset, onError, children,
3243
3622
  }
3244
3623
 
3245
3624
  function ErrorState({ message, onRetry, retryMessage = 'Retry', color = 'danger', }) {
3246
- return (jsxs(DAlert, { color: color, className: "d-flex align-items-center gap-3", children: [jsx("div", { className: "flex-grow-1", children: jsx("p", { className: "mb-0", children: message !== null && message !== void 0 ? message : 'An unexpected error occurred.' }) }), onRetry && (jsx(DButton, { onClick: onRetry, text: retryMessage, variant: "outline", iconStart: "RefreshCw" }))] }));
3625
+ return (jsxs(DAlert, { color: color, className: "d-error-state", children: [jsx("div", { className: "d-error-state-content", children: jsx("p", { className: "d-error-state-message", children: message !== null && message !== void 0 ? message : 'An unexpected error occurred.' }) }), onRetry && (jsx(DButton, { onClick: onRetry, text: retryMessage, variant: "outline", iconStart: "RefreshCw" }))] }));
3247
3626
  }
3248
3627
 
3249
3628
  function EmptyState({ message, icon = 'FileText', actionText, onAction, }) {
3250
- return (jsxs("div", { className: "d-flex flex-column align-items-center justify-content-center p-5 text-center", children: [jsx(DIcon, { icon: icon, size: "3rem", className: "text-secondary mb-3" }), jsx("p", { className: "text-secondary mb-3", children: message !== null && message !== void 0 ? message : 'No data available.' }), actionText && onAction && (jsx(DButton, { onClick: onAction, text: actionText, variant: "outline" }))] }));
3629
+ return (jsxs("div", { className: "d-empty-state", children: [jsx(DIcon, { icon: icon, size: "3rem", className: "d-empty-state-icon" }), jsx("p", { className: "d-empty-state-message", children: message !== null && message !== void 0 ? message : 'No data available.' }), actionText && onAction && (jsx(DButton, { onClick: onAction, text: actionText, variant: "outline" }))] }));
3251
3630
  }
3252
3631
 
3253
3632
  function LoadingState({ ariaLabel = 'Loading...', className }) {
3254
- return (jsx("div", { className: `d-flex align-items-center justify-content-center p-4 ${className || ''}`.trim(), "aria-busy": "true", "aria-live": "polite", children: jsx("span", { className: "spinner-border", role: "status", "aria-label": ariaLabel }) }));
3633
+ return (jsx("div", { className: `d-loading-state ${className || ''}`.trim(), "aria-busy": "true", "aria-live": "polite", children: jsx("span", { className: "spinner-border", role: "status", "aria-label": ariaLabel }) }));
3255
3634
  }
3256
3635
 
3257
3636
  function render(renderable) {
@@ -3310,7 +3689,7 @@ function DConfirmModalUI({ entry }) {
3310
3689
  }
3311
3690
  });
3312
3691
  }, [onConfirmAction]);
3313
- return (jsxs(DModal$1, { name: entry.id, size: "lg", className: `confirm-modal ${critical ? 'critical-modal' : ''}`, children: [jsx(DModal$1.Header, { onClose: handleClose, showCloseButton: true, children: jsx("h5", { className: "fw-bold", children: title }) }), jsxs(DModal$1.Body, { className: "py-3 px-5", children: [jsx("p", { className: "mb-4", children: message }), critical && (jsx(ForwardedDInput, { type: "text", label: critical.codeLabel || 'Confirmation code', placeholder: critical.inputPlaceholder, value: confirmationCode, onChange: (value) => setConfirmationCode(value), className: "mb-4", autoFocus: true }))] }), jsxs(DModal$1.Footer, { children: [jsx(DButton, { text: cancelLabel, variant: "outline", color: "secondary", onClick: handleClose, disabled: internalLoading }), jsx(DButton, { text: confirmLabel, color: confirmColor, onClick: handleConfirmClick, disabled: isConfirmDisabled, loading: internalLoading })] })] }));
3692
+ return (jsxs(DModal$1, { name: entry.id, size: "lg", className: `confirm-modal ${critical ? 'critical-modal' : ''}`, children: [jsx(DModal$1.Header, { onClose: handleClose, showCloseButton: true, children: jsx("h5", { className: "fw-bold", children: title }) }), jsxs(DModal$1.Body, { className: "d-confirm-modal-body", children: [jsx("p", { className: "d-confirm-modal-message", children: message }), critical && (jsx(ForwardedDInput, { type: "text", label: critical.codeLabel || 'Confirmation code', placeholder: critical.inputPlaceholder, value: confirmationCode, onChange: (value) => setConfirmationCode(value), className: "d-confirm-modal-field", autoFocus: true }))] }), jsxs(DModal$1.Footer, { children: [jsx(DButton, { text: cancelLabel, variant: "outline", color: "secondary", onClick: handleClose, disabled: internalLoading }), jsx(DButton, { text: confirmLabel, color: confirmColor, onClick: handleConfirmClick, disabled: isConfirmDisabled, loading: internalLoading })] })] }));
3314
3693
  }
3315
3694
 
3316
3695
  /**
@@ -3363,5 +3742,5 @@ function DConfirmModalContainer({ nodeId }) {
3363
3742
  return createPortal(jsx(AnimatePresence, { children: entries.map((entry) => (jsxs(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0, transition: { delay: 0.3 } }, transition: { duration: 0.15, ease: 'linear' }, children: [jsx("div", { className: "backdrop backdrop-confirm-modal", onClick: entry.onCloseAction, role: "presentation" }), jsx(DConfirmModalUI, { entry: entry })] }, entry.id))) }), portalNode);
3364
3743
  }
3365
3744
 
3366
- export { DAlert, DAvatar, DBadge, DBox, DBoxFile, DButton, DButtonIcon, DCard$1 as DCard, DCardBody, DCardFooter, DCardHeader, DCarousel$1 as DCarousel, DCarouselSlide, DChip, DCollapse, DConfirmModalContainer, DContext, DContextProvider, DCreditCard, DCurrencyText, DDataStateWrapper, DDatePicker, DDropdown, DErrorBoundary, DIcon, DIconBase, ForwardedDInput as DInput, DInputCheck, ForwardedDInputCounter as DInputCounter, ForwardedDInputCurrency as DInputCurrency, ForwardedDInputMask as DInputMask, ForwardedDInputPassword as DInputPassword, ForwardedDInputPhone as DInputPhone, DInputPin, ForwardedDInputRange as DInputRange, ForwardedDInputSearch as DInputSearch, DInputSelect, DInputSwitch, DLayout$1 as DLayout, DLayoutPane, DListGroup$1 as DListGroup, DListGroupItem, DModal$1 as DModal, DModalBody, DModalFooter, DModalHeader, DOffcanvas$1 as DOffcanvas, DOffcanvasBody, DOffcanvasFooter, DOffcanvasHeader, DOtp, DPaginator, DPasswordStrengthMeter, DPopover, DProgress, DSelect$1 as DSelect, DStepper, DStepper$2 as DStepperDesktop, DStepper$1 as DStepperMobile, DTabContent, DTabs$1 as DTabs, DTimeline, DToast$1 as DToast, DToastContainer, DTooltip, DVoucher, EmptyState, ErrorState, LoadingState, changeQueryString, checkMediaQuery, configureI8n as configureI18n, formatCurrency, getCssVariable, getQueryString, subscribeToMediaQuery, useConfirmModal, useDContext, useDPortalContext, useDToast, useDisableBodyScrollEffect, useDisableInputWheel, useFormatCurrency, useInputCurrency, useItemSelection, useMediaBreakpointUpLg, useMediaBreakpointUpMd, useMediaBreakpointUpSm, useMediaBreakpointUpXl, useMediaBreakpointUpXs, useMediaBreakpointUpXxl, useMediaQuery, useProvidedRefOrCreate, useStackState, useTabContext, validatePhoneNumber };
3745
+ export { DAlert, DAvatar, DBadge, DBox, DBoxFile, DButton, DButtonIcon, DCard$1 as DCard, DCardBody, DCardFooter, DCardHeader, DCarousel$1 as DCarousel, DCarouselSlide, DChip, DCollapse, DConfirmModalContainer, DContext, DContextProvider, DCreditCard, DCurrencyText, DDataStateWrapper, DDatePicker, DDropdown, DErrorBoundary, DIcon, DIconBase, ForwardedDInput as DInput, DInputCheck, ForwardedDInputCounter as DInputCounter, ForwardedDInputCurrency as DInputCurrency, ForwardedDInputMask as DInputMask, ForwardedDInputPassword as DInputPassword, ForwardedDInputPhone as DInputPhone, DInputPin, ForwardedDInputRange as DInputRange, ForwardedDInputSearch as DInputSearch, DInputSelect, DInputSwitch, DLayout$1 as DLayout, DLayoutPane, DListGroup$1 as DListGroup, DListGroupItem, DModal$1 as DModal, DModalBody, DModalFooter, DModalHeader, DOffcanvas$1 as DOffcanvas, DOffcanvasBody, DOffcanvasFooter, DOffcanvasHeader, DOtp, DPaginator, DPasswordStrengthMeter, DPopover, DProgress, DSelect$1 as DSelect, DStepper, DStepper$2 as DStepperDesktop, DStepper$1 as DStepperMobile, DTabContent, DTabs$1 as DTabs, DTimeline, DToast$1 as DToast, DToastContainer, DTooltip, DVoucher, EmptyState, ErrorState, LoadingState, buildUrl, changeQueryString, checkMediaQuery, configureI8n as configureI18n, formatCurrency, getCssVariable, getQueryString, sanitizeHref, subscribeToMediaQuery, useConfirmModal, useCountdown, useDContext, useDPortalContext, useDToast, useDisableBodyScrollEffect, useDisableInputWheel, useFormatCurrency, useInputCurrency, useItemSelection, useMediaBreakpointUpLg, useMediaBreakpointUpMd, useMediaBreakpointUpSm, useMediaBreakpointUpXl, useMediaBreakpointUpXs, useMediaBreakpointUpXxl, useMediaQuery, useOtp, useProvidedRefOrCreate, useScreenshot, useScreenshotDownload, useScreenshotWebShare, useStackState, useTabContext, validatePhoneNumber };
3367
3746
  //# sourceMappingURL=index.esm.js.map