@dynamic-framework/ui-react 2.0.0-dev.4 → 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 (30) hide show
  1. package/dist/css/dynamic-ui-non-root.css +65 -45
  2. package/dist/css/dynamic-ui-non-root.min.css +2 -2
  3. package/dist/css/dynamic-ui-root.css +1 -1
  4. package/dist/css/dynamic-ui-root.min.css +1 -1
  5. package/dist/css/dynamic-ui.css +65 -45
  6. package/dist/css/dynamic-ui.min.css +2 -2
  7. package/dist/index.esm.js +231 -23
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +232 -22
  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/DInputSwitch/DInputSwitch.d.ts +2 -1
  14. package/dist/types/components/DPasswordStrengthMeter/DPasswordStrengthMeter.d.ts +23 -0
  15. package/dist/types/components/DPasswordStrengthMeter/PasswordCheckItem.d.ts +7 -0
  16. package/dist/types/components/DPasswordStrengthMeter/PasswordCheckList.d.ts +14 -0
  17. package/dist/types/components/DPasswordStrengthMeter/PasswordStrength.d.ts +6 -0
  18. package/dist/types/components/DPasswordStrengthMeter/index.d.ts +3 -0
  19. package/dist/types/components/DVoucher/DVoucher.d.ts +14 -0
  20. package/dist/types/components/DVoucher/hooks/useScreenshot.d.ts +5 -0
  21. package/dist/types/components/DVoucher/hooks/useScreenshotDownload.d.ts +5 -0
  22. package/dist/types/components/DVoucher/hooks/useScreenshotWebShare.d.ts +5 -0
  23. package/dist/types/components/DVoucher/index.d.ts +2 -0
  24. package/dist/types/components/index.d.ts +3 -0
  25. package/jest/setup.js +0 -2
  26. package/package.json +6 -4
  27. package/src/style/abstracts/variables/_buttons.scss +2 -0
  28. package/src/style/base/_buttons.scss +56 -65
  29. package/src/style/components/_+import.scss +1 -0
  30. 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) {
@@ -1492,6 +1526,86 @@ function DInputPassword(_a, ref) {
1492
1526
  const ForwardedDInputPassword = forwardRef(DInputPassword);
1493
1527
  ForwardedDInputPassword.displayName = 'DInputPassword';
1494
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
+
1495
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, }) {
1496
1610
  const innerId = useId();
1497
1611
  const id = useMemo(() => idProp || innerId, [idProp, innerId]);
@@ -1655,7 +1769,7 @@ function DInputSelect({ id: idProp, name, label = '', className, style, options
1655
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 }))] })));
1656
1770
  }
1657
1771
 
1658
- 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, }) {
1659
1773
  const innerId = useId();
1660
1774
  const id = useMemo(() => idProp || innerId, [idProp, innerId]);
1661
1775
  const [internalIsChecked, setInternalIsChecked] = useState(checked);
@@ -1667,10 +1781,10 @@ function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, i
1667
1781
  setInternalIsChecked(value);
1668
1782
  onChange === null || onChange === void 0 ? void 0 : onChange(value);
1669
1783
  }, [onChange]);
1670
- 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', {
1671
1785
  'is-invalid': invalid,
1672
1786
  'is-valid': valid,
1673
- }, 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 }))] })));
1674
1788
  }
1675
1789
 
1676
1790
  function DInputRange(_a, ref) {
@@ -2307,5 +2421,99 @@ function DDropdown({ actions, dropdownToggle, className, }) {
2307
2421
  }) })] }));
2308
2422
  }
2309
2423
 
2310
- 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 };
2311
2519
  //# sourceMappingURL=index.esm.js.map