@dynamic-framework/ui-react 2.0.0-dev.3 → 2.0.0-dev.5

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 (33) hide show
  1. package/dist/css/dynamic-ui-non-root.css +294 -46
  2. package/dist/css/dynamic-ui-non-root.min.css +3 -3
  3. package/dist/css/dynamic-ui-root.css +2 -2
  4. package/dist/css/dynamic-ui-root.min.css +2 -2
  5. package/dist/css/dynamic-ui.css +294 -46
  6. package/dist/css/dynamic-ui.min.css +3 -3
  7. package/dist/index.esm.js +234 -25
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +268 -57
  10. package/dist/index.js.map +1 -1
  11. package/dist/types/components/DButton/DButton.d.ts +7 -17
  12. package/dist/types/components/DInputCheck/DInputCheck.d.ts +2 -1
  13. package/dist/types/components/DInputMask/DInputMask.d.ts +7 -17
  14. package/dist/types/components/DInputSwitch/DInputSwitch.d.ts +2 -1
  15. package/dist/types/components/DLayout/DLayout.d.ts +2 -1
  16. package/dist/types/components/DPasswordStrengthMeter/DPasswordStrengthMeter.d.ts +23 -0
  17. package/dist/types/components/DPasswordStrengthMeter/PasswordCheckItem.d.ts +7 -0
  18. package/dist/types/components/DPasswordStrengthMeter/PasswordCheckList.d.ts +14 -0
  19. package/dist/types/components/DPasswordStrengthMeter/PasswordStrength.d.ts +6 -0
  20. package/dist/types/components/DPasswordStrengthMeter/index.d.ts +3 -0
  21. package/dist/types/components/DVoucher/DVoucher.d.ts +14 -0
  22. package/dist/types/components/DVoucher/hooks/useScreenshot.d.ts +5 -0
  23. package/dist/types/components/DVoucher/hooks/useScreenshotDownload.d.ts +5 -0
  24. package/dist/types/components/DVoucher/hooks/useScreenshotWebShare.d.ts +5 -0
  25. package/dist/types/components/DVoucher/index.d.ts +2 -0
  26. package/dist/types/components/index.d.ts +3 -0
  27. package/jest/setup.js +0 -2
  28. package/package.json +35 -29
  29. package/src/style/abstracts/_utilities.scss +19 -0
  30. package/src/style/abstracts/variables/_buttons.scss +2 -0
  31. package/src/style/base/_buttons.scss +56 -65
  32. package/src/style/components/_+import.scss +1 -0
  33. package/src/style/components/_d-voucher.scss +30 -0
package/dist/index.esm.js CHANGED
@@ -16,6 +16,7 @@ import { useFloating, autoUpdate, offset, flip, shift, useClick, useDismiss, use
16
16
  import { Toaster, toast } from 'react-hot-toast';
17
17
  import { defaultCountries, parseCountry, usePhoneInput, CountrySelector } from 'react-international-phone';
18
18
  import { PhoneNumberUtil } from 'google-libphonenumber';
19
+ import html2canvas from 'html2canvas';
19
20
  import i18n from 'i18next';
20
21
  import { initReactI18next } from 'react-i18next';
21
22
 
@@ -868,26 +869,59 @@ function DBoxFile(_a) {
868
869
  : children })] })) })), !!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}`))) }))] }));
869
870
  }
870
871
 
871
- function DButton({ color = 'primary', size, variant, state, text = '', children, ariaLabel, iconStart, iconStartFamilyClass, iconStartFamilyPrefix, iconStartMaterialStyle, iconEnd, iconEndFamilyClass, iconEndFamilyPrefix, iconEndMaterialStyle, loadingText, value, type = 'button', loading = false, loadingAriaLabel, disabled = false, stopPropagationEnabled = true, className, style, form, dataAttributes, onClick, }) {
872
- const generateClasses = useMemo(() => {
872
+ const DButton = forwardRef((props, ref) => {
873
+ const { color = 'primary', size, variant, text, children, iconStart, iconStartFamilyClass, iconStartFamilyPrefix, iconStartMaterialStyle, iconEnd, iconEndFamilyClass, iconEndFamilyPrefix, iconEndMaterialStyle, loading = false, loadingText, loadingAriaLabel, disabled = false, className, style, dataAttributes, onClick, type = 'button' } = 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"]);
874
+ const [buttonWidth, setButtonWidth] = useState();
875
+ const buttonRef = useRef(null);
876
+ const isDisabled = useMemo(() => disabled || loading, [disabled, loading]);
877
+ const content = useMemo(() => children || text, [children, text]);
878
+ const classes = useMemo(() => {
873
879
  const variantClass = variant
874
880
  ? `btn-${variant}-${color}`
875
881
  : `btn-${color}`;
876
- return Object.assign(Object.assign(Object.assign({ btn: true, [variantClass]: true }, size && { [`btn-${size}`]: true }), (state && state !== 'disabled') && { [state]: true }), { loading });
877
- }, [variant, color, size, state, loading]);
878
- const clickHandler = useCallback((event) => {
879
- if (stopPropagationEnabled) {
880
- event.stopPropagation();
882
+ return {
883
+ btn: true,
884
+ [variantClass]: true,
885
+ [`btn-${size}`]: !!size,
886
+ loading,
887
+ };
888
+ }, [variant, color, size, loading]);
889
+ const ariaLabel = useMemo(() => {
890
+ const ariaLabelProp = rest['aria-label'];
891
+ return loading
892
+ ? loadingAriaLabel || ariaLabelProp || text
893
+ : ariaLabelProp || text;
894
+ }, [loading, loadingAriaLabel, rest, text]);
895
+ const handleClick = useCallback((event) => {
896
+ if (disabled || loading) {
897
+ event.preventDefault();
898
+ return;
881
899
  }
882
900
  onClick === null || onClick === void 0 ? void 0 : onClick(event);
883
- }, [stopPropagationEnabled, onClick]);
884
- const isDisabled = useMemo(() => (state === 'disabled' || loading || disabled), [state, loading, disabled]);
885
- const content = children || text;
886
- const newAriaLabel = useMemo(() => (loading
887
- ? (loadingAriaLabel || ariaLabel || text)
888
- : (ariaLabel || text)), [loading, loadingAriaLabel, ariaLabel, text]);
889
- return (jsxs("button", Object.assign({ className: classNames(generateClasses, className), style: style, type: type, disabled: isDisabled, onClick: clickHandler, "aria-label": newAriaLabel, form: form }, dataAttributes, value && { value }, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle })), loading && (jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsx("span", { className: "visually-hidden", children: "Loading..." }) })), jsx("span", { children: loading && loadingText ? loadingText : content }), iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }))] })));
890
- }
901
+ }, [disabled, loading, onClick]);
902
+ useEffect(() => {
903
+ if (!loading && buttonRef.current) {
904
+ const width = buttonRef.current.offsetWidth;
905
+ if (width > 0)
906
+ setButtonWidth(width);
907
+ }
908
+ // eslint-disable-next-line react-hooks/exhaustive-deps
909
+ }, [content, iconEnd, iconStart]);
910
+ return (jsxs("button", Object.assign({ ref: (node) => {
911
+ buttonRef.current = node;
912
+ if (typeof ref === 'function')
913
+ ref(node);
914
+ // eslint-disable-next-line max-len
915
+ // eslint-disable-next-line no-param-reassign, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
916
+ else if (ref)
917
+ ref.current = node;
918
+ },
919
+ // eslint-disable-next-line react/button-has-type
920
+ type: type, className: classNames(classes, className), style: Object.assign(Object.assign({}, style), (loading && buttonWidth
921
+ ? { minWidth: `${buttonWidth}px` }
922
+ : 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$1, { children: [iconStart && (jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle })), content, iconEnd && (jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }))] }))] })));
923
+ });
924
+ DButton.displayName = 'DButton';
891
925
 
892
926
  function DButtonIcon({ id, icon, size, className, variant, state, loadingAriaLabel, iconMaterialStyle, ariaLabel, color = 'primary', type = 'button', loading = false, disabled = false, stopPropagationEnabled = true, style, iconFamilyClass, iconFamilyPrefix, dataAttributes, onClick, }) {
893
927
  const generateClasses = useMemo(() => {
@@ -1022,7 +1056,7 @@ const ForwardedDDatePickerInput = forwardRef(DDatePickerInput);
1022
1056
  ForwardedDDatePickerInput.displayName = 'DDatePickerInput';
1023
1057
 
1024
1058
  function DInputCheck(_a) {
1025
- var { id: idProp, type, name, label, ariaLabel, checked = false, disabled = false, invalid = false, valid = false, indeterminate, value, hint, onChange, className, style, dataAttributes } = _a, props = __rest(_a, ["id", "type", "name", "label", "ariaLabel", "checked", "disabled", "invalid", "valid", "indeterminate", "value", "hint", "onChange", "className", "style", "dataAttributes"]);
1059
+ var { id: idProp, type, name, label, ariaLabel, checked = false, disabled = false, invalid = false, valid = false, indeterminate, inputClassName, value, hint, onChange, className, style, dataAttributes } = _a, props = __rest(_a, ["id", "type", "name", "label", "ariaLabel", "checked", "disabled", "invalid", "valid", "indeterminate", "inputClassName", "value", "hint", "onChange", "className", "style", "dataAttributes"]);
1026
1060
  const innerRef = useRef(null);
1027
1061
  const innerId = useId();
1028
1062
  const id = useMemo(() => idProp || innerId, [idProp, innerId]);
@@ -1050,11 +1084,11 @@ function DInputCheck(_a) {
1050
1084
  const inputComponent = useMemo(() => (jsx("input", Object.assign({ ref: innerRef, onChange: handleChange, className: classNames('form-check-input', {
1051
1085
  'is-invalid': invalid,
1052
1086
  'is-valid': valid,
1053
- }, className), style: style, id: id, disabled: disabled, type: type, name: name, value: value, "aria-label": ariaLabel }, ariaDescribedby && { 'aria-describedby': ariaDescribedby }, props))), [
1087
+ }, inputClassName), style: style, id: id, disabled: disabled, type: type, name: name, value: value, "aria-label": ariaLabel }, ariaDescribedby && { 'aria-describedby': ariaDescribedby }, props))), [
1054
1088
  handleChange,
1055
1089
  invalid,
1056
1090
  valid,
1057
- className,
1091
+ inputClassName,
1058
1092
  style,
1059
1093
  id,
1060
1094
  disabled,
@@ -1068,7 +1102,7 @@ function DInputCheck(_a) {
1068
1102
  if (!label) {
1069
1103
  return inputComponent;
1070
1104
  }
1071
- return (jsxs("div", Object.assign({ className: "form-check" }, dataAttributes, { children: [inputComponent, jsx("label", { className: "form-check-label", htmlFor: id, children: label }), hint && (jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
1105
+ return (jsxs("div", Object.assign({ className: classNames('form-check', className) }, dataAttributes, { children: [inputComponent, jsx("label", { className: "form-check-label", htmlFor: id, children: label }), hint && (jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
1072
1106
  }
1073
1107
 
1074
1108
  function DSelectOptionCheck(_a) {
@@ -1268,7 +1302,7 @@ function DLayoutPane({ className, style, children, cols, colsXs, colsSm, colsMd,
1268
1302
  return (jsx("div", Object.assign({ className: classNames(colsClass, colsXsClass, colsSmClass, colsMdClass, colsLgClass, colsXlClass, colsXxlClass, className), style: style }, dataAttributes, { children: children })));
1269
1303
  }
1270
1304
 
1271
- function DLayout({ className, style, children, gap, gapSm, gapMd, gapLg, gapXl, gapXxl, dataAttributes, }) {
1305
+ function DLayout({ className, style, children, gap, columns, gapSm, gapMd, gapLg, gapXl, gapXxl, dataAttributes, }) {
1272
1306
  const gapClasses = classNames({
1273
1307
  [`gap-${gap}`]: gap !== undefined,
1274
1308
  [`gap-sm-${gapSm}`]: gapSm !== undefined,
@@ -1277,7 +1311,8 @@ function DLayout({ className, style, children, gap, gapSm, gapMd, gapLg, gapXl,
1277
1311
  [`gap-xl-${gapXl}`]: gapXl !== undefined,
1278
1312
  [`gap-xxl-${gapXxl}`]: gapXxl !== undefined,
1279
1313
  });
1280
- return (jsx("div", Object.assign({ style: style, className: classNames('grid', gapClasses, className) }, dataAttributes, { children: children })));
1314
+ const styleWithColumns = Object.assign(Object.assign({}, style), { '--bs-columns': columns });
1315
+ return (jsx("div", Object.assign({ style: styleWithColumns, className: classNames('grid', gapClasses, className) }, dataAttributes, { children: children })));
1281
1316
  }
1282
1317
  var DLayout$1 = Object.assign(DLayout, {
1283
1318
  Pane: DLayoutPane,
@@ -1491,6 +1526,86 @@ function DInputPassword(_a, ref) {
1491
1526
  const ForwardedDInputPassword = forwardRef(DInputPassword);
1492
1527
  ForwardedDInputPassword.displayName = 'DInputPassword';
1493
1528
 
1529
+ function PasswordCheckItem({ password, regex, text, }) {
1530
+ const isValid = regex.test(password);
1531
+ 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 })] }));
1532
+ }
1533
+
1534
+ const getColorClass = (strength, total) => {
1535
+ const percentage = total > 0 ? strength / total : 0;
1536
+ if (percentage === 0)
1537
+ return 'bg-gray-200';
1538
+ if (percentage <= 0.25)
1539
+ return 'bg-danger';
1540
+ if (percentage <= 0.5)
1541
+ return 'bg-warning';
1542
+ if (percentage <= 0.75)
1543
+ return 'bg-info';
1544
+ return 'bg-success';
1545
+ };
1546
+ function PasswordStrengthBar({ strength, total }) {
1547
+ const percentage = total > 0 ? (strength / total) * 100 : 0;
1548
+ 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: {
1549
+ width: `${percentage}%`,
1550
+ transition: 'width 0.3s ease-in-out',
1551
+ } }) }));
1552
+ }
1553
+
1554
+ const CHECK_REGEX = {
1555
+ uppercase: /[A-Z]/,
1556
+ lowercase: /[a-z]/,
1557
+ number: /\d/,
1558
+ specialChar: /[~!@#$^*\-_=[\]{}|;,.?]/,
1559
+ };
1560
+ function PasswordChecksList({ password, validationMessages, enabledChecks, }) {
1561
+ const allChecks = [
1562
+ {
1563
+ key: 'uppercase',
1564
+ regex: CHECK_REGEX.uppercase,
1565
+ text: validationMessages.uppercaseLetter,
1566
+ },
1567
+ {
1568
+ key: 'lowercase',
1569
+ regex: CHECK_REGEX.lowercase,
1570
+ text: validationMessages.lowercaseLetter,
1571
+ },
1572
+ {
1573
+ key: 'number',
1574
+ regex: CHECK_REGEX.number,
1575
+ text: validationMessages.number,
1576
+ },
1577
+ {
1578
+ key: 'specialChar',
1579
+ regex: CHECK_REGEX.specialChar,
1580
+ text: validationMessages.especialChar,
1581
+ },
1582
+ ];
1583
+ const passwordChecks = allChecks.filter((check) => enabledChecks.includes(check.key));
1584
+ const passed = passwordChecks.filter((r) => r.regex.test(password)).length;
1585
+ const total = passwordChecks.length;
1586
+ 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))) })] }));
1587
+ }
1588
+
1589
+ const DEFAULT_VALIDATION_MESSAGES = {
1590
+ number: 'At least one number',
1591
+ lowercaseLetter: 'At least one lowercase letter',
1592
+ uppercaseLetter: 'At least one uppercase letter',
1593
+ especialChar: 'At least one of these special characters: ~!@#$^*-_=[]{}|;,.?',
1594
+ notMatch: 'The password confirmation and the new password do not match.',
1595
+ };
1596
+ const DEFAULT_ENABLED_CHECKS = ['uppercase', 'lowercase', 'number', 'specialChar'];
1597
+ function DPasswordStrengthMeter({ id, label = 'Password', placeholder, value = '', name, disabled = false, invalid = false, validationMessages = DEFAULT_VALIDATION_MESSAGES, enabledChecks = DEFAULT_ENABLED_CHECKS, className, style, dataAttributes, onChange, }) {
1598
+ const [password, setPassword] = useState(value);
1599
+ useEffect(() => {
1600
+ setPassword(value);
1601
+ }, [value]);
1602
+ const handleChange = (newValue) => {
1603
+ setPassword(newValue);
1604
+ onChange === null || onChange === void 0 ? void 0 : onChange(newValue);
1605
+ };
1606
+ return (jsxs("div", Object.assign({ className: className, style: style }, dataAttributes, { children: [jsx(ForwardedDInputPassword, { id: id, label: label, placeholder: placeholder, value: password, name: name, disabled: disabled, invalid: invalid, onChange: handleChange }), jsx(PasswordChecksList, { password: password, validationMessages: validationMessages, enabledChecks: enabledChecks })] })));
1607
+ }
1608
+
1494
1609
  function DInputPin({ id: idProp, label = '', placeholder, type = 'text', disabled = false, loading = false, secret = false, characters = 4, innerInputMode = 'text', hint, invalid = false, valid = false, className, style, dataAttributes, onChange, }) {
1495
1610
  const innerId = useId();
1496
1611
  const id = useMemo(() => idProp || innerId, [idProp, innerId]);
@@ -1654,7 +1769,7 @@ function DInputSelect({ id: idProp, name, label = '', className, style, options
1654
1769
  }), 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 }))] })));
1655
1770
  }
1656
1771
 
1657
- function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, invalid = false, valid = false, readonly, className, style, dataAttributes, onChange, }) {
1772
+ function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, invalid = false, valid = false, readonly, className, style, dataAttributes, inputClassName, onChange, }) {
1658
1773
  const innerId = useId();
1659
1774
  const id = useMemo(() => idProp || innerId, [idProp, innerId]);
1660
1775
  const [internalIsChecked, setInternalIsChecked] = useState(checked);
@@ -1666,10 +1781,10 @@ function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, i
1666
1781
  setInternalIsChecked(value);
1667
1782
  onChange === null || onChange === void 0 ? void 0 : onChange(value);
1668
1783
  }, [onChange]);
1669
- return (jsxs("div", Object.assign({ className: "form-check form-switch" }, dataAttributes, { children: [jsx("input", { id: id, name: name, onChange: readonly ? () => false : changeHandler, className: classNames('form-check-input', {
1784
+ return (jsxs("div", Object.assign({ className: classNames('form-check', className) }, dataAttributes, { children: [jsx("input", { id: id, name: name, onChange: readonly ? () => false : changeHandler, className: classNames('form-check-input', {
1670
1785
  'is-invalid': invalid,
1671
1786
  'is-valid': valid,
1672
- }, className), style: style, type: "checkbox", role: "switch", checked: internalIsChecked, disabled: disabled, "aria-label": ariaLabel }), label && (jsx("label", { className: "form-check-label", htmlFor: id, children: label }))] })));
1787
+ }, 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 }))] })));
1673
1788
  }
1674
1789
 
1675
1790
  function DInputRange(_a, ref) {
@@ -2306,5 +2421,99 @@ function DDropdown({ actions, dropdownToggle, className, }) {
2306
2421
  }) })] }));
2307
2422
  }
2308
2423
 
2309
- export { DAlert, DAvatar, DBadge, DBox, DBoxFile, DButton, DButtonIcon, DCard$1 as DCard, DCardBody, DCardFooter, DCardHeader, DCarousel$1 as DCarousel, DCarouselSlide, DChip, DCollapse, DContext, DContextProvider, DCreditCard, DCurrencyText, DDatePicker, DDropdown, 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, 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, DPaginator, DPopover, DProgress, DSelect$1 as DSelect, DStepper, DStepper$2 as DStepperDesktop, DStepper$1 as DStepperMobile, DTabContent, DTableHead, DTabs$1 as DTabs, DTimeline, DToast$1 as DToast, DToastContainer, DTooltip, changeQueryString, checkMediaQuery, configureI8n as configureI18n, formatCurrency, getCssVariable, getQueryString, subscribeToMediaQuery, useDContext, useDPortalContext, useDToast, useDisableBodyScrollEffect, useDisableInputWheel, useFormatCurrency, useInputCurrency, useItemSelection, useMediaBreakpointUpLg, useMediaBreakpointUpMd, useMediaBreakpointUpSm, useMediaBreakpointUpXl, useMediaBreakpointUpXs, useMediaBreakpointUpXxl, useMediaQuery, usePortal, useProvidedRefOrCreate, useStackState, useTabContext, validatePhoneNumber };
2424
+ function useScreenshot() {
2425
+ const clipRef = useRef(null);
2426
+ const takeBlob = useCallback(async (type) => {
2427
+ if (!clipRef.current) {
2428
+ throw new Error('set the clipRef');
2429
+ }
2430
+ const canvas = await html2canvas(clipRef === null || clipRef === void 0 ? void 0 : clipRef.current, {
2431
+ allowTaint: true,
2432
+ useCORS: true,
2433
+ });
2434
+ return (new Promise((resolve, reject) => {
2435
+ canvas.toBlob((innerBlob) => {
2436
+ if (!innerBlob) {
2437
+ return reject();
2438
+ }
2439
+ return resolve(innerBlob);
2440
+ }, type);
2441
+ }));
2442
+ }, []);
2443
+ return {
2444
+ clipRef,
2445
+ takeBlob,
2446
+ };
2447
+ }
2448
+
2449
+ function useScreenshotDownload() {
2450
+ const { clipRef, takeBlob } = useScreenshot();
2451
+ const download = useCallback(async () => {
2452
+ const blob = await takeBlob();
2453
+ const url = window.URL.createObjectURL(blob);
2454
+ const link = window.document.createElement('a');
2455
+ link.style.display = 'none';
2456
+ link.href = url;
2457
+ link.download = 'voucher.jpg';
2458
+ document.body.appendChild(link);
2459
+ link.click();
2460
+ document.body.removeChild(link);
2461
+ window.URL.revokeObjectURL(url);
2462
+ }, [takeBlob]);
2463
+ return {
2464
+ download,
2465
+ downloadRef: clipRef,
2466
+ };
2467
+ }
2468
+
2469
+ function useScreenshotWebShare() {
2470
+ const { takeBlob, clipRef } = useScreenshot();
2471
+ const share = useCallback(async () => {
2472
+ const blob = await takeBlob();
2473
+ const image = new File([blob], 'voucher.jpeg', { type: 'image/jpeg' });
2474
+ if (!navigator.canShare
2475
+ && (navigator.canShare && !navigator.canShare({ files: [image] }))) {
2476
+ window.print();
2477
+ return;
2478
+ }
2479
+ await navigator.share({ files: [image] });
2480
+ }, [takeBlob]);
2481
+ return {
2482
+ share,
2483
+ shareRef: clipRef,
2484
+ };
2485
+ }
2486
+
2487
+ function DVoucher({ amount, amountDetails, icon = 'CircleCheckBig', color = 'success', title, onError, message, downloadText = 'Download', shareText = 'Share', children, }) {
2488
+ const { shareRef, share } = useScreenshotWebShare();
2489
+ const { downloadRef, download } = useScreenshotDownload();
2490
+ const handleShare = () => {
2491
+ share()
2492
+ .catch(async (err) => {
2493
+ if (onError) {
2494
+ await onError(err);
2495
+ }
2496
+ })
2497
+ .catch(() => {
2498
+ // Error already handled by onError
2499
+ });
2500
+ };
2501
+ const handleDownload = () => {
2502
+ download()
2503
+ .catch(async (err) => {
2504
+ if (onError) {
2505
+ await onError(err);
2506
+ }
2507
+ })
2508
+ .catch(() => {
2509
+ // Error already handled by onError
2510
+ });
2511
+ };
2512
+ return (jsx("div", { className: "d-voucher", ref: (el) => {
2513
+ shareRef.current = el;
2514
+ downloadRef.current = el;
2515
+ }, children: jsxs("div", { children: [jsxs("div", { className: "d-voucher-header", children: [jsx(DIcon, { icon: icon, color: color }), 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" })] })] }) }));
2516
+ }
2517
+
2518
+ export { DAlert, DAvatar, DBadge, DBox, DBoxFile, DButton, DButtonIcon, DCard$1 as DCard, DCardBody, DCardFooter, DCardHeader, DCarousel$1 as DCarousel, DCarouselSlide, DChip, DCollapse, DContext, DContextProvider, DCreditCard, DCurrencyText, DDatePicker, DDropdown, 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, 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, DPaginator, DPasswordStrengthMeter, DPopover, DProgress, DSelect$1 as DSelect, DStepper, DStepper$2 as DStepperDesktop, DStepper$1 as DStepperMobile, DTabContent, DTableHead, DTabs$1 as DTabs, DTimeline, DToast$1 as DToast, DToastContainer, DTooltip, DVoucher, changeQueryString, checkMediaQuery, configureI8n as configureI18n, formatCurrency, getCssVariable, getQueryString, subscribeToMediaQuery, useDContext, useDPortalContext, useDToast, useDisableBodyScrollEffect, useDisableInputWheel, useFormatCurrency, useInputCurrency, useItemSelection, useMediaBreakpointUpLg, useMediaBreakpointUpMd, useMediaBreakpointUpSm, useMediaBreakpointUpXl, useMediaBreakpointUpXs, useMediaBreakpointUpXxl, useMediaQuery, usePortal, useProvidedRefOrCreate, useStackState, useTabContext, validatePhoneNumber };
2310
2519
  //# sourceMappingURL=index.esm.js.map