@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.
- package/dist/css/dynamic-ui.css +276 -22
- package/dist/css/dynamic-ui.min.css +2 -2
- package/dist/index.esm.js +677 -298
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +683 -297
- package/dist/index.js.map +1 -1
- package/dist/types/components/DDropdown/DDropdown.d.ts +10 -2
- package/dist/types/components/DInputCheck/DInputCheck.d.ts +1 -0
- package/dist/types/components/DInputSwitch/DInputSwitch.d.ts +2 -1
- package/dist/types/components/DModal/components/DModalHeader.d.ts +5 -1
- package/dist/types/components/DOffcanvas/components/DOffcanvasHeader.d.ts +5 -1
- package/dist/types/components/DOtp/DOtp.d.ts +1 -0
- package/dist/types/components/DOtp/components/OtpCountdown.d.ts +3 -2
- package/dist/types/components/DTooltip/DTooltip.d.ts +38 -3
- package/dist/types/components/DVoucher/DVoucher.d.ts +3 -1
- package/dist/types/components/DVoucher/hooks/useScreenshotDownload.d.ts +1 -1
- package/dist/types/components/DVoucher/hooks/useScreenshotDownload.spec.d.ts +1 -0
- package/dist/types/components/DVoucher/hooks/useScreenshotWebShare.d.ts +1 -1
- package/dist/types/components/DVoucher/hooks/useScreenshotWebShare.spec.d.ts +1 -0
- package/dist/types/components/DVoucher/index.d.ts +3 -0
- package/dist/types/components/index.d.ts +1 -1
- package/dist/types/hooks/index.d.ts +3 -0
- package/dist/types/hooks/tests/useCountdown.spec.d.ts +1 -0
- package/dist/types/hooks/useCountdown.d.ts +14 -0
- package/dist/types/hooks/useInputCurrency.d.ts +1 -6
- package/dist/types/hooks/useOtp.d.ts +98 -0
- package/dist/types/utils/buildUrl.d.ts +32 -0
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/sanitizeHref.d.ts +37 -0
- package/dist/types/utils/tests/buildUrl.spec.d.ts +1 -0
- package/dist/types/utils/tests/sanitizeHref.spec.d.ts +1 -0
- package/package.json +9 -6
- package/src/style/_shame.scss +1 -5
- package/src/style/abstracts/variables/_+import.scss +2 -0
- package/src/style/abstracts/variables/_box.scss +7 -0
- package/src/style/abstracts/variables/_forms.scss +1 -3
- package/src/style/abstracts/variables/_input-currency.scss +1 -0
- package/src/style/abstracts/variables/_shadow.scss +12 -1
- package/src/style/base/_+import.scss +0 -1
- package/src/style/base/_form-check.scss +4 -2
- package/src/style/components/_+import.scss +7 -0
- package/src/style/components/_d-box-file.scss +5 -0
- package/src/style/components/_d-box.scss +5 -5
- package/src/style/components/_d-close.scss +1 -0
- package/src/style/components/_d-confirm-modal.scss +17 -0
- package/src/style/components/_d-data-state-wrapper.scss +47 -0
- package/src/style/components/_d-datepicker.scss +11 -0
- package/src/style/components/_d-error-boundary.scss +7 -0
- package/src/style/components/_d-input-currency.scss +5 -0
- package/src/style/components/_d-otp.scss +54 -0
- package/src/style/components/_d-password-strength-meter.scss +76 -0
- package/src/style/components/_d-popover.scss +4 -0
- package/src/style/components/_d-stepper.scss +8 -0
- package/src/style/components/_d-tabs.scss +18 -0
- package/src/style/components/_d-voucher.scss +30 -0
- package/dist/types/components/DOtp/DOtpspec.d.ts +0 -0
- package/dist/types/components/DOtp/hooks/useCountdown.d.ts +0 -4
- package/src/style/base/_form-text.scss +0 -12
package/dist/index.js
CHANGED
|
@@ -583,12 +583,12 @@ function DIcon(_a) {
|
|
|
583
583
|
return (jsxRuntime.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)));
|
|
584
584
|
}
|
|
585
585
|
|
|
586
|
-
function DAlert({ color = 'success', icon: iconProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle
|
|
587
|
-
const { iconMap: { alert, xLg, }, } = useDContext();
|
|
586
|
+
function DAlert({ color = 'success', icon: iconProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle, iconClose: iconCloseProp, iconCloseFamilyClass, iconCloseFamilyPrefix, iconCloseMaterialStyle, showClose, onClose, children, id, className, style, dataAttributes, }) {
|
|
587
|
+
const { icon: { materialStyle, familyClass, familyPrefix, }, iconMap: { alert, xLg, }, } = useDContext();
|
|
588
588
|
const icon = React.useMemo(() => iconProp || alert[color], [alert, iconProp, color]);
|
|
589
589
|
const iconClose = React.useMemo(() => (iconCloseProp || xLg), [iconCloseProp, xLg]);
|
|
590
590
|
const generateClasses = React.useMemo(() => (Object.assign({ alert: true, [`alert-${color}`]: true, 'fade show': !!showClose }, className && { [className]: true })), [color, showClose, className]);
|
|
591
|
-
return (jsxRuntime.jsxs("div", Object.assign({ className: classNames(generateClasses), style: style, role: "alert", id: id }, dataAttributes, { children: [icon && (jsxRuntime.jsx(DIcon, { className: "alert-icon", icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })), jsxRuntime.jsx("div", { className: "alert-text", children: children }), showClose && (jsxRuntime.jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: onClose, children: jsxRuntime.jsx(DIcon, { icon: iconClose, familyClass: iconCloseFamilyClass, familyPrefix: iconCloseFamilyPrefix, materialStyle: iconCloseMaterialStyle }) }))] })));
|
|
591
|
+
return (jsxRuntime.jsxs("div", Object.assign({ className: classNames(generateClasses), style: style, role: "alert", id: id }, dataAttributes, { children: [icon && (jsxRuntime.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 })), jsxRuntime.jsx("div", { className: "alert-text", children: children }), showClose && (jsxRuntime.jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: onClose, children: jsxRuntime.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 }) }))] })));
|
|
592
592
|
}
|
|
593
593
|
|
|
594
594
|
function DAvatar({ id, size, image, name: nameProp, useNameAsInitials = false, className, style, dataAttributes, }) {
|
|
@@ -610,6 +610,7 @@ function DAvatar({ id, size, image, name: nameProp, useNameAsInitials = false, c
|
|
|
610
610
|
|
|
611
611
|
function DBadge(props) {
|
|
612
612
|
const { text, soft = false, color = 'primary', id, rounded, className, size, style, iconStart, iconEnd, iconMaterialStyle, iconFamilyClass, iconFamilyPrefix, dataAttributes, } = props;
|
|
613
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
|
|
613
614
|
// Responsive size resolution using useResponsiveProp
|
|
614
615
|
const { responsivePropValue } = useResponsiveProp(true);
|
|
615
616
|
const resolvedSize = React.useMemo(() => {
|
|
@@ -626,7 +627,7 @@ function DBadge(props) {
|
|
|
626
627
|
'rounded-pill': !!rounded,
|
|
627
628
|
[`badge-${resolvedSize}`]: !!resolvedSize,
|
|
628
629
|
}), [rounded, soft, color, resolvedSize]);
|
|
629
|
-
return (jsxRuntime.jsxs("span", Object.assign({ className: classNames(generateClasses, className), style: style }, id && { id }, dataAttributes, { children: [iconStart && (jsxRuntime.jsx(DIcon, { icon: iconStart, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })), jsxRuntime.jsx("span", { children: text }), iconEnd && (jsxRuntime.jsx(DIcon, { icon: iconEnd, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle }))] })));
|
|
630
|
+
return (jsxRuntime.jsxs("span", Object.assign({ className: classNames(generateClasses, className), style: style }, id && { id }, dataAttributes, { children: [iconStart && (jsxRuntime.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 })), jsxRuntime.jsx("span", { children: text }), iconEnd && (jsxRuntime.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 }))] })));
|
|
630
631
|
}
|
|
631
632
|
|
|
632
633
|
function DBox({ className, style, children, dataAttributes, }) {
|
|
@@ -658,6 +659,7 @@ function DInput(_a, ref) {
|
|
|
658
659
|
const inputRef = useProvidedRefOrCreate(ref);
|
|
659
660
|
const innerId = React.useId();
|
|
660
661
|
const id = React.useMemo(() => idProp || innerId, [idProp, innerId]);
|
|
662
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
|
|
661
663
|
const handleOnChange = React.useCallback((event) => {
|
|
662
664
|
onChange === null || onChange === void 0 ? void 0 : onChange(event.currentTarget.value);
|
|
663
665
|
}, [onChange]);
|
|
@@ -720,7 +722,7 @@ function DInput(_a, ref) {
|
|
|
720
722
|
[`input-group-${size}`]: !!size,
|
|
721
723
|
'input-group': true,
|
|
722
724
|
'has-validation': invalid || valid,
|
|
723
|
-
}), children: [!!inputStart && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}InputStart`, children: inputStart })), iconStart && (onIconStartClick ? (jsxRuntime.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: jsxRuntime.jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle }) })) : (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}Start`, "aria-hidden": "true", tabIndex: -1, children: jsxRuntime.jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle }) }))), dynamicComponent, (iconEnd && !loading) && (onIconEndClick ? (jsxRuntime.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: jsxRuntime.jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }) })) : (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}End`, "aria-hidden": "true", tabIndex: -1, children: jsxRuntime.jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }) }))), loading && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}Loading`, children: jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", "data-testid": "loading-spinner", children: jsxRuntime.jsx("span", { className: "visually-hidden", children: "Loading..." }) }) })), !!inputEnd && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}InputEnd`, children: inputEnd }))] }), hint && (jsxRuntime.jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
|
|
725
|
+
}), children: [!!inputStart && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}InputStart`, children: inputStart })), iconStart && (onIconStartClick ? (jsxRuntime.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: jsxRuntime.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 }) })) : (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}Start`, "aria-hidden": "true", tabIndex: -1, children: jsxRuntime.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 ? (jsxRuntime.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: jsxRuntime.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 }) })) : (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}End`, "aria-hidden": "true", tabIndex: -1, children: jsxRuntime.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 && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}Loading`, children: jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", "data-testid": "loading-spinner", children: jsxRuntime.jsx("span", { className: "visually-hidden", children: "Loading..." }) }) })), !!inputEnd && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}InputEnd`, children: inputEnd }))] }), hint && (jsxRuntime.jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
|
|
724
726
|
}
|
|
725
727
|
const ForwardedDInput = React.forwardRef(DInput);
|
|
726
728
|
ForwardedDInput.displayName = 'DInput';
|
|
@@ -1116,7 +1118,7 @@ function useDBoxFile(props) {
|
|
|
1116
1118
|
|
|
1117
1119
|
function DBoxFile(_a) {
|
|
1118
1120
|
var { icon: iconProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle, children, className, style, dataAttributes } = _a, props = tslib.__rest(_a, ["icon", "iconFamilyClass", "iconFamilyPrefix", "iconMaterialStyle", "children", "className", "style", "dataAttributes"]);
|
|
1119
|
-
const { iconMap: { upload } } = useDContext();
|
|
1121
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { upload }, } = useDContext();
|
|
1120
1122
|
const icon = React.useMemo(() => iconProp || upload, [iconProp, upload]);
|
|
1121
1123
|
const { inputRef, rootRef, isDragValid, isDragInvalid, acceptAttr, files, handleFileSelect, handleDrop, handleDragEnter, handleDragLeave, handleClick, handleKeyDown, handleRemoveFile, openFileDialog, } = useDBoxFile(props);
|
|
1122
1124
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("section", Object.assign({ className: classNames('d-box-file', {
|
|
@@ -1124,13 +1126,14 @@ function DBoxFile(_a) {
|
|
|
1124
1126
|
'd-box-file-disabled': props.disabled,
|
|
1125
1127
|
'd-box-file-valid': isDragValid,
|
|
1126
1128
|
'd-box-file-invalid': isDragInvalid,
|
|
1127
|
-
}, className), style: style }, dataAttributes, { children: jsxRuntime.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: [jsxRuntime.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 && (jsxRuntime.jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })), jsxRuntime.jsx("div", { className: "d-box-content", children: typeof children === 'function'
|
|
1129
|
+
}, className), style: style }, dataAttributes, { children: jsxRuntime.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: [jsxRuntime.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 && (jsxRuntime.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 })), jsxRuntime.jsx("div", { className: "d-box-content", children: typeof children === 'function'
|
|
1128
1130
|
? children(openFileDialog)
|
|
1129
|
-
: children || (jsxRuntime.jsx("p", { className: "
|
|
1131
|
+
: children || (jsxRuntime.jsx("p", { className: "d-box-file-empty-text", children: "Drag and drop some files here, or click to select files" })) })] })) })), !!files.length && (jsxRuntime.jsx("ul", { className: "d-box-files", children: files.map((file, index) => (jsxRuntime.jsx(ForwardedDInput, { value: file.name, iconStart: "Paperclip", iconEnd: "Trash", readOnly: true, onIconEndClick: () => handleRemoveFile(index) }, `${file.name} ${index}`))) }))] }));
|
|
1130
1132
|
}
|
|
1131
1133
|
|
|
1132
1134
|
const DButton = React.forwardRef((props, ref) => {
|
|
1133
1135
|
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 = tslib.__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']);
|
|
1136
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
|
|
1134
1137
|
// Responsive size resolution using useResponsiveProp
|
|
1135
1138
|
const { responsivePropValue } = useResponsiveProp(true);
|
|
1136
1139
|
const resolvedSize = React.useMemo(() => {
|
|
@@ -1184,7 +1187,7 @@ const DButton = React.forwardRef((props, ref) => {
|
|
|
1184
1187
|
ref.current = node;
|
|
1185
1188
|
}, className: classNames(classes, className), style: Object.assign(Object.assign({}, style), (loading && buttonWidth
|
|
1186
1189
|
? { minWidth: `${buttonWidth}px` }
|
|
1187
|
-
: undefined)), "aria-label": ariaLabel, "aria-busy": loading, "aria-disabled": isDisabled, onClick: handleClick }, dataAttributes, { children: [loading && (jsxRuntime.jsxs("span", { className: "btn-loading", children: [jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", "aria-hidden": "true" }), loadingText && jsxRuntime.jsx("span", { role: "status", children: loadingText })] })), !loading && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconStart && (jsxRuntime.jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle })), content, iconEnd && (jsxRuntime.jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }))] }))] })));
|
|
1190
|
+
: undefined)), "aria-label": ariaLabel, "aria-busy": loading, "aria-disabled": isDisabled, onClick: handleClick }, dataAttributes, { children: [loading && (jsxRuntime.jsxs("span", { className: "btn-loading", children: [jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", "aria-hidden": "true" }), loadingText && jsxRuntime.jsx("span", { role: "status", children: loadingText })] })), !loading && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconStart && (jsxRuntime.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 && (jsxRuntime.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 }))] }))] })));
|
|
1188
1191
|
}
|
|
1189
1192
|
return (jsxRuntime.jsxs("button", Object.assign({ ref: (node) => {
|
|
1190
1193
|
buttonRef.current = node;
|
|
@@ -1198,12 +1201,13 @@ const DButton = React.forwardRef((props, ref) => {
|
|
|
1198
1201
|
// eslint-disable-next-line react/button-has-type
|
|
1199
1202
|
type: type, className: classNames(classes, className), style: Object.assign(Object.assign({}, style), (loading && buttonWidth
|
|
1200
1203
|
? { minWidth: `${buttonWidth}px` }
|
|
1201
|
-
: undefined)), disabled: isDisabled, "aria-label": ariaLabel, "aria-busy": loading, "aria-disabled": isDisabled, onClick: handleClick }, dataAttributes, rest, { children: [loading && (jsxRuntime.jsxs("span", { className: "btn-loading", children: [jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", "aria-hidden": "true" }), loadingText && jsxRuntime.jsx("span", { role: "status", children: loadingText })] })), !loading && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconStart && (jsxRuntime.jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle })), content, iconEnd && (jsxRuntime.jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }))] }))] })));
|
|
1204
|
+
: undefined)), disabled: isDisabled, "aria-label": ariaLabel, "aria-busy": loading, "aria-disabled": isDisabled, onClick: handleClick }, dataAttributes, rest, { children: [loading && (jsxRuntime.jsxs("span", { className: "btn-loading", children: [jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", "aria-hidden": "true" }), loadingText && jsxRuntime.jsx("span", { role: "status", children: loadingText })] })), !loading && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconStart && (jsxRuntime.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 && (jsxRuntime.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 }))] }))] })));
|
|
1202
1205
|
});
|
|
1203
1206
|
DButton.displayName = 'DButton';
|
|
1204
1207
|
|
|
1205
1208
|
function DButtonIcon(_a) {
|
|
1206
1209
|
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 = tslib.__rest(_a, ["id", "icon", "size", "className", "variant", "state", "loadingAriaLabel", "iconMaterialStyle", "disabled", "color", "loading", "href", "target", "rel", "stopPropagationEnabled", "style", "iconFamilyClass", "iconFamilyPrefix", "dataAttributes", "onClick", 'aria-label']);
|
|
1210
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
|
|
1207
1211
|
const generateClasses = React.useMemo(() => {
|
|
1208
1212
|
const variantClass = !variant || variant === 'solid'
|
|
1209
1213
|
? `btn-${color}`
|
|
@@ -1227,11 +1231,11 @@ function DButtonIcon(_a) {
|
|
|
1227
1231
|
if (href) {
|
|
1228
1232
|
return (jsxRuntime.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
|
|
1229
1233
|
? (jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsxRuntime.jsx("span", { className: "visually-hidden", children: "Loading..." }) }))
|
|
1230
|
-
: (jsxRuntime.jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })) })));
|
|
1234
|
+
: (jsxRuntime.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 })) })));
|
|
1231
1235
|
}
|
|
1232
1236
|
return (jsxRuntime.jsx("button", Object.assign({ className: classNames(generateClasses, className), style: style, disabled: state === 'disabled' || loading, onClick: clickHandler, "aria-label": ariaLabel }, dataAttributes, rest, { children: loading
|
|
1233
1237
|
? (jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsxRuntime.jsx("span", { className: "visually-hidden", children: "Loading..." }) }))
|
|
1234
|
-
: (jsxRuntime.jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })) })));
|
|
1238
|
+
: (jsxRuntime.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 })) })));
|
|
1235
1239
|
}
|
|
1236
1240
|
|
|
1237
1241
|
function DCardHeader({ className, style, children, }) {
|
|
@@ -1294,12 +1298,12 @@ function DChip({ color = 'primary', text, icon, iconFamilyClass, iconFamilyPrefi
|
|
|
1294
1298
|
'd-chip': true,
|
|
1295
1299
|
[`d-chip-${color}`]: !!color,
|
|
1296
1300
|
}), [color]);
|
|
1297
|
-
const { iconMap: { xLg, }, } = useDContext();
|
|
1301
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { xLg, }, } = useDContext();
|
|
1298
1302
|
const iconClose = React.useMemo(() => iconCloseProp || xLg, [iconCloseProp, xLg]);
|
|
1299
|
-
return (jsxRuntime.jsxs("span", Object.assign({ className: classNames(generateClasses, className), style: style }, dataAttributes, { children: [icon && (jsxRuntime.jsx("div", { className: "d-chip-icon-container", children: jsxRuntime.jsx(DIcon, { icon: icon, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle }) })), jsxRuntime.jsx("span", { children: text }), showClose && (jsxRuntime.jsx("button", { type: "button", className: "d-chip-icon-container", onClick: onClose, "aria-label": closeAriaLabel, children: jsxRuntime.jsx(DIcon, { icon: iconClose, familyClass: iconCloseFamilyClass, familyPrefix: iconCloseFamilyPrefix, materialStyle: iconCloseMaterialStyle }) }))] })));
|
|
1303
|
+
return (jsxRuntime.jsxs("span", Object.assign({ className: classNames(generateClasses, className), style: style }, dataAttributes, { children: [icon && (jsxRuntime.jsx("div", { className: "d-chip-icon-container", children: jsxRuntime.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 }) })), jsxRuntime.jsx("span", { children: text }), showClose && (jsxRuntime.jsx("button", { type: "button", className: "d-chip-icon-container", onClick: onClose, "aria-label": closeAriaLabel, children: jsxRuntime.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 }) }))] })));
|
|
1300
1304
|
}
|
|
1301
1305
|
|
|
1302
|
-
function DCollapse({ id, className, style, Component, defaultCollapsed = true, onChange, children, iconOpen: iconOpenProp, iconClose: iconCloseProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle
|
|
1306
|
+
function DCollapse({ id, className, style, Component, defaultCollapsed = true, onChange, children, iconOpen: iconOpenProp, iconClose: iconCloseProp, iconFamilyClass, iconFamilyPrefix, iconMaterialStyle, dataAttributes, }) {
|
|
1303
1307
|
const [collapsed, setCollapsed] = React.useState(defaultCollapsed);
|
|
1304
1308
|
const onChangeCollapse = () => {
|
|
1305
1309
|
setCollapsed((prev) => {
|
|
@@ -1313,10 +1317,10 @@ function DCollapse({ id, className, style, Component, defaultCollapsed = true, o
|
|
|
1313
1317
|
React.useEffect(() => {
|
|
1314
1318
|
setCollapsed(defaultCollapsed);
|
|
1315
1319
|
}, [defaultCollapsed]);
|
|
1316
|
-
const { iconMap: { chevronDown, chevronUp, }, } = useDContext();
|
|
1320
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { chevronDown, chevronUp, }, } = useDContext();
|
|
1317
1321
|
const iconOpen = React.useMemo(() => iconOpenProp || chevronDown, [chevronDown, iconOpenProp]);
|
|
1318
1322
|
const iconClose = React.useMemo(() => iconCloseProp || chevronUp, [chevronUp, iconCloseProp]);
|
|
1319
|
-
return (jsxRuntime.jsxs("div", Object.assign({ id: id, className: classNames('collapse-container', className), style: style }, dataAttributes, { children: [jsxRuntime.jsxs("button", { className: "collapse-button", type: "button", onClick: onChangeCollapse, children: [jsxRuntime.jsx("div", { className: "flex-grow-1", children: Component }), jsxRuntime.jsx(DIcon, { color: "primary", size: "1.25rem", icon: collapsed ? iconOpen : iconClose, familyClass: iconFamilyClass, familyPrefix: iconFamilyPrefix, materialStyle: iconMaterialStyle })] }), jsxRuntime.jsx("div", { className: classNames('collapse-body-wrapper', {
|
|
1323
|
+
return (jsxRuntime.jsxs("div", Object.assign({ id: id, className: classNames('collapse-container', className), style: style }, dataAttributes, { children: [jsxRuntime.jsxs("button", { className: "collapse-button", type: "button", onClick: onChangeCollapse, children: [jsxRuntime.jsx("div", { className: "flex-grow-1", children: Component }), jsxRuntime.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 })] }), jsxRuntime.jsx("div", { className: classNames('collapse-body-wrapper', {
|
|
1320
1324
|
show: !collapsed,
|
|
1321
1325
|
}), children: jsxRuntime.jsx("div", { className: "collapse-body", children: children }) })] })));
|
|
1322
1326
|
}
|
|
@@ -1502,9 +1506,9 @@ function DDatePickerHeaderSelector({ date, changeYear, changeMonth, decreaseMont
|
|
|
1502
1506
|
return (jsxRuntime.jsxs("div", { className: classNames('react-datepicker__header-selector react-datepicker__header-year-selector', className), style: style, children: [jsxRuntime.jsx(DButtonIcon, { icon: iconPrev || chevronLeft, size: iconSize, variant: "link", onClick: decreaseYear, disabled: prevYearButtonDisabled, "aria-label": prevYearAriaLabel, className: "header-button" }), jsxRuntime.jsx("p", { children: `${startYear} - ${endYear}` }), jsxRuntime.jsx(DButtonIcon, { icon: iconNext || chevronRight, size: iconSize, variant: "link", onClick: increaseYear, disabled: nextYearButtonDisabled, "aria-label": nextYearAriaLabel, className: "header-button" })] }));
|
|
1503
1507
|
}
|
|
1504
1508
|
if (pickerType === PickerType.Quarter || pickerType === PickerType.Month) {
|
|
1505
|
-
return (jsxRuntime.jsxs("div", { className: classNames(`react-datepicker__header-selector react-datepicker__header-${pickerType}-selector`, className), style: style, children: [jsxRuntime.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' } }), jsxRuntime.jsx("div", { className: "
|
|
1509
|
+
return (jsxRuntime.jsxs("div", { className: classNames(`react-datepicker__header-selector react-datepicker__header-${pickerType}-selector`, className), style: style, children: [jsxRuntime.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' } }), jsxRuntime.jsx("div", { className: "react-datepicker__header-year-selector", children: showHeaderSelectors ? (jsxRuntime.jsx(DSelect, { options: years, value: defaultYear, defaultValue: defaultYear, onChange: (year) => changeYear(Number(year === null || year === void 0 ? void 0 : year.value)), searchable: false })) : (jsxRuntime.jsx("p", { children: defaultYear === null || defaultYear === void 0 ? void 0 : defaultYear.label })) }), jsxRuntime.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' } })] }));
|
|
1506
1510
|
}
|
|
1507
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "datepicker-top-header", children: [showHeaderSelectors && (jsxRuntime.jsx(DSelect, { 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" })), jsxRuntime.jsx("h4", { className: "
|
|
1511
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "datepicker-top-header", children: [showHeaderSelectors && (jsxRuntime.jsx(DSelect, { 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" })), jsxRuntime.jsx("h4", { className: "datepicker-top-header-title", children: dateFns.format(monthDate, formatHeaderDate, { locale }) })] }), jsxRuntime.jsxs("div", { className: classNames('react-datepicker__header-selector react-datepicker__header-day-selector', className), style: style, children: [jsxRuntime.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 ? (jsxRuntime.jsx(DSelect, { 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" })) : (jsxRuntime.jsx("p", { children: `${defaultMonth.label} ${defaultYear === null || defaultYear === void 0 ? void 0 : defaultYear.label}` })), jsxRuntime.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' } })] })] }));
|
|
1508
1512
|
}
|
|
1509
1513
|
|
|
1510
1514
|
function DDatePicker(_a) {
|
|
@@ -1639,11 +1643,24 @@ function formatValue(value, currencyOptions) {
|
|
|
1639
1643
|
}
|
|
1640
1644
|
return currency(value, Object.assign(Object.assign({}, currencyOptions), { symbol: '' })).format();
|
|
1641
1645
|
}
|
|
1642
|
-
function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref) {
|
|
1646
|
+
function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref, minValue, maxValue) {
|
|
1643
1647
|
const inputRef = useProvidedRefOrCreate(ref);
|
|
1648
|
+
const clampValue = React.useCallback((newValue) => {
|
|
1649
|
+
if (newValue === undefined) {
|
|
1650
|
+
return newValue;
|
|
1651
|
+
}
|
|
1652
|
+
let clampedValue = newValue;
|
|
1653
|
+
if (minValue !== undefined) {
|
|
1654
|
+
clampedValue = Math.max(clampedValue, minValue);
|
|
1655
|
+
}
|
|
1656
|
+
if (maxValue !== undefined) {
|
|
1657
|
+
clampedValue = Math.min(clampedValue, maxValue);
|
|
1658
|
+
}
|
|
1659
|
+
return clampedValue;
|
|
1660
|
+
}, [minValue, maxValue]);
|
|
1644
1661
|
const [innerType, setInnerType] = React.useState('text');
|
|
1645
|
-
const [innerNumber, setInnerNumber] = React.useState(value);
|
|
1646
|
-
const [innerString, setInnerString] = React.useState(formatValue(value, currencyOptions));
|
|
1662
|
+
const [innerNumber, setInnerNumber] = React.useState(clampValue(value));
|
|
1663
|
+
const [innerString, setInnerString] = React.useState(formatValue(clampValue(value), currencyOptions));
|
|
1647
1664
|
const handleOnFocus = React.useCallback((event) => {
|
|
1648
1665
|
event.stopPropagation();
|
|
1649
1666
|
setInnerType('number');
|
|
@@ -1652,15 +1669,14 @@ function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref
|
|
|
1652
1669
|
const handleOnBlur = React.useCallback((event) => {
|
|
1653
1670
|
event.stopPropagation();
|
|
1654
1671
|
setInnerType('text');
|
|
1672
|
+
const clampedNumber = clampValue(innerNumber);
|
|
1673
|
+
if (clampedNumber !== innerNumber) {
|
|
1674
|
+
setInnerNumber(clampedNumber);
|
|
1675
|
+
setInnerString(formatValue(clampedNumber, currencyOptions));
|
|
1676
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(clampedNumber);
|
|
1677
|
+
}
|
|
1655
1678
|
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
1656
|
-
}, [onBlur]);
|
|
1657
|
-
const generateStyleVariables = React.useMemo(() => ({
|
|
1658
|
-
[`--${PREFIX_BS}input-currency-component-symbol-color`]: `var(--${PREFIX_BS}secondary)`,
|
|
1659
|
-
[`--${PREFIX_BS}input-currency-symbol-color`]: `var(--${PREFIX_BS}input-currency-component-symbol-color)`,
|
|
1660
|
-
}), []);
|
|
1661
|
-
const generateSymbolStyleVariables = React.useMemo(() => ({
|
|
1662
|
-
color: `var(--${PREFIX_BS}input-currency-symbol-color)`,
|
|
1663
|
-
}), []);
|
|
1679
|
+
}, [onBlur, innerNumber, clampValue, currencyOptions, onChange]);
|
|
1664
1680
|
const handleOnChange = React.useCallback((newValue) => {
|
|
1665
1681
|
const newNumber = (newValue === undefined || newValue === '') ? undefined : Number(newValue);
|
|
1666
1682
|
if (newNumber !== innerNumber) {
|
|
@@ -1669,7 +1685,12 @@ function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref
|
|
|
1669
1685
|
onChange === null || onChange === void 0 ? void 0 : onChange(newNumber);
|
|
1670
1686
|
}
|
|
1671
1687
|
}, [currencyOptions, onChange, innerNumber]);
|
|
1688
|
+
const isMountedRef = React.useRef(false);
|
|
1672
1689
|
React.useEffect(() => {
|
|
1690
|
+
if (!isMountedRef.current) {
|
|
1691
|
+
isMountedRef.current = true;
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1673
1694
|
if (value !== innerNumber) {
|
|
1674
1695
|
setInnerNumber(value);
|
|
1675
1696
|
setInnerString(formatValue(value, currencyOptions));
|
|
@@ -1683,8 +1704,6 @@ function useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref
|
|
|
1683
1704
|
handleOnFocus,
|
|
1684
1705
|
handleOnChange,
|
|
1685
1706
|
handleOnBlur,
|
|
1686
|
-
generateStyleVariables,
|
|
1687
|
-
generateSymbolStyleVariables,
|
|
1688
1707
|
};
|
|
1689
1708
|
}
|
|
1690
1709
|
|
|
@@ -1789,6 +1808,149 @@ function useConfirmModal(config) {
|
|
|
1789
1808
|
return { open };
|
|
1790
1809
|
}
|
|
1791
1810
|
|
|
1811
|
+
/**
|
|
1812
|
+
* Generic seconds-based countdown hook.
|
|
1813
|
+
*
|
|
1814
|
+
* Starts counting down from `seconds` to `0` and exposes `restartCountdown`
|
|
1815
|
+
* to reset and restart the timer (e.g. for "resend code in Xs" patterns,
|
|
1816
|
+
* session-expiry banners, or any other cooldown/throttle UI).
|
|
1817
|
+
*
|
|
1818
|
+
* @example
|
|
1819
|
+
* const { secondsLeft, restartCountdown } = useCountdown(30);
|
|
1820
|
+
*/
|
|
1821
|
+
function useCountdown(seconds) {
|
|
1822
|
+
const [secondsLeft, setSecondsLeft] = React.useState(seconds);
|
|
1823
|
+
const [isActive, setIsActive] = React.useState(true);
|
|
1824
|
+
const resetCountdown = React.useCallback((newSeconds = seconds) => {
|
|
1825
|
+
setIsActive(false);
|
|
1826
|
+
setSecondsLeft(newSeconds);
|
|
1827
|
+
}, [seconds]);
|
|
1828
|
+
const restartCountdown = React.useCallback(() => {
|
|
1829
|
+
resetCountdown(seconds);
|
|
1830
|
+
setIsActive(true);
|
|
1831
|
+
}, [resetCountdown, seconds]);
|
|
1832
|
+
React.useEffect(() => {
|
|
1833
|
+
if (!isActive) {
|
|
1834
|
+
return () => { };
|
|
1835
|
+
}
|
|
1836
|
+
const interval = setInterval(() => {
|
|
1837
|
+
setSecondsLeft((prevSeconds) => {
|
|
1838
|
+
const newSeconds = prevSeconds - 1;
|
|
1839
|
+
if (newSeconds <= 0) {
|
|
1840
|
+
clearInterval(interval);
|
|
1841
|
+
setIsActive(false);
|
|
1842
|
+
return 0;
|
|
1843
|
+
}
|
|
1844
|
+
return newSeconds;
|
|
1845
|
+
});
|
|
1846
|
+
}, 1000);
|
|
1847
|
+
return () => clearInterval(interval);
|
|
1848
|
+
}, [isActive]);
|
|
1849
|
+
return { secondsLeft, restartCountdown };
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
/**
|
|
1853
|
+
* Headless hook exposing the same OTP logic used internally by `DOtp`
|
|
1854
|
+
* (code state, length + correctness validation, submit action and resend
|
|
1855
|
+
* countdown), without any bundled markup/styles.
|
|
1856
|
+
*
|
|
1857
|
+
* Use this when the default `DOtp` component doesn't match your design and
|
|
1858
|
+
* you need to build a fully custom UI while reusing the same behavior.
|
|
1859
|
+
*
|
|
1860
|
+
* Internally composes `useCountdown` for the resend timer and re-exposes
|
|
1861
|
+
* `secondsLeft`/`restartCountdown`, so there is no need to call
|
|
1862
|
+
* `useCountdown` separately.
|
|
1863
|
+
*
|
|
1864
|
+
* `invalid` becomes `true` both when the OTP is shorter than `otpSize` and
|
|
1865
|
+
* when `action` throws/rejects (e.g. the backend rejected the entered code
|
|
1866
|
+
* as incorrect). In the latter case, the thrown value is exposed as `error`
|
|
1867
|
+
* so custom UIs can render an appropriate message (e.g. "Invalid code" vs.
|
|
1868
|
+
* "Enter all digits"). `invalid`/`error` are cleared automatically as soon
|
|
1869
|
+
* as the user edits the code via `setOtp`.
|
|
1870
|
+
*
|
|
1871
|
+
* @example
|
|
1872
|
+
* function CustomOtp() {
|
|
1873
|
+
* const {
|
|
1874
|
+
* otp,
|
|
1875
|
+
* setOtp,
|
|
1876
|
+
* invalid,
|
|
1877
|
+
* error,
|
|
1878
|
+
* submit,
|
|
1879
|
+
* isLoading,
|
|
1880
|
+
* secondsLeft,
|
|
1881
|
+
* restartCountdown,
|
|
1882
|
+
* } = useOtp({ action: async () => verifyOtp(otp), otpSize: 6, seconds: 15 });
|
|
1883
|
+
*
|
|
1884
|
+
* return (
|
|
1885
|
+
* <>
|
|
1886
|
+
* <MyCustomPinInput value={otp} onChange={setOtp} invalid={invalid} />
|
|
1887
|
+
* {invalid && <span>{error ? 'Invalid code' : 'Enter all digits'}</span>}
|
|
1888
|
+
* <button disabled={isLoading} onClick={() => { submit().catch(() => {}); }}>
|
|
1889
|
+
* {isLoading ? 'Submitting...' : 'Submit'}
|
|
1890
|
+
* </button>
|
|
1891
|
+
* <button disabled={secondsLeft > 0} onClick={restartCountdown}>
|
|
1892
|
+
* Resend {secondsLeft > 0 ? `(${secondsLeft}s)` : ''}
|
|
1893
|
+
* </button>
|
|
1894
|
+
* </>
|
|
1895
|
+
* );
|
|
1896
|
+
* }
|
|
1897
|
+
*/
|
|
1898
|
+
function useOtp({ action, otpSize = 6, seconds = 15, }) {
|
|
1899
|
+
const [otp, setOtpValue] = React.useState('');
|
|
1900
|
+
const [invalid, setInvalid] = React.useState(false);
|
|
1901
|
+
const [error, setError] = React.useState(null);
|
|
1902
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
1903
|
+
const { secondsLeft, restartCountdown } = useCountdown(seconds);
|
|
1904
|
+
const setOtp = React.useCallback((value) => {
|
|
1905
|
+
setOtpValue((prevOtp) => {
|
|
1906
|
+
// Guard against no-op calls (e.g. DInputPin re-notifying the same
|
|
1907
|
+
// value when its onChange reference changes) so we don't wipe out
|
|
1908
|
+
// an `invalid`/`error` state that was just set by submit().
|
|
1909
|
+
if (prevOtp === value) {
|
|
1910
|
+
return prevOtp;
|
|
1911
|
+
}
|
|
1912
|
+
setInvalid(false);
|
|
1913
|
+
setError(null);
|
|
1914
|
+
return value;
|
|
1915
|
+
});
|
|
1916
|
+
}, []);
|
|
1917
|
+
const submit = React.useCallback(async () => {
|
|
1918
|
+
if (otp.length < otpSize) {
|
|
1919
|
+
setInvalid(true);
|
|
1920
|
+
setError(null);
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
setIsLoading(true);
|
|
1924
|
+
try {
|
|
1925
|
+
await action();
|
|
1926
|
+
setInvalid(false);
|
|
1927
|
+
setError(null);
|
|
1928
|
+
}
|
|
1929
|
+
catch (err) {
|
|
1930
|
+
setInvalid(true);
|
|
1931
|
+
setError(err);
|
|
1932
|
+
throw err;
|
|
1933
|
+
}
|
|
1934
|
+
finally {
|
|
1935
|
+
setIsLoading(false);
|
|
1936
|
+
}
|
|
1937
|
+
}, [
|
|
1938
|
+
otp.length,
|
|
1939
|
+
action,
|
|
1940
|
+
otpSize,
|
|
1941
|
+
]);
|
|
1942
|
+
return {
|
|
1943
|
+
otp,
|
|
1944
|
+
setOtp,
|
|
1945
|
+
invalid,
|
|
1946
|
+
error,
|
|
1947
|
+
submit,
|
|
1948
|
+
isLoading,
|
|
1949
|
+
secondsLeft,
|
|
1950
|
+
restartCountdown,
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1792
1954
|
function DInputCounter(_a, ref) {
|
|
1793
1955
|
var { minValue, maxValue, value = minValue, invalid, iconStart: iconStartProp, iconEnd: iconEndProp, iconStartAriaLabel = 'decrease action', iconEndAriaLabel = 'increase action', style, onChange } = _a, props = tslib.__rest(_a, ["minValue", "maxValue", "value", "invalid", "iconStart", "iconEnd", "iconStartAriaLabel", "iconEndAriaLabel", "style", "onChange"]);
|
|
1794
1956
|
const { handleOnWheel, } = useDisableInputWheel(ref);
|
|
@@ -1831,8 +1993,8 @@ function DInputCurrency(_a, ref) {
|
|
|
1831
1993
|
var { value, minValue, maxValue, currencyCode, onFocus, onBlur, onChange } = _a, props = tslib.__rest(_a, ["value", "minValue", "maxValue", "currencyCode", "onFocus", "onBlur", "onChange"]);
|
|
1832
1994
|
const { currency: currencyOptions } = useDContext();
|
|
1833
1995
|
const { handleOnWheel, } = useDisableInputWheel(ref);
|
|
1834
|
-
const { inputRef, innerValue, innerType, handleOnFocus, handleOnChange, handleOnBlur,
|
|
1835
|
-
return (jsxRuntime.jsx(ForwardedDInput, Object.assign({ ref: inputRef, value: innerValue, onChange: handleOnChange,
|
|
1996
|
+
const { inputRef, innerValue, innerType, handleOnFocus, handleOnChange, handleOnBlur, } = useInputCurrency(currencyOptions, value, onFocus, onChange, onBlur, ref, minValue, maxValue);
|
|
1997
|
+
return (jsxRuntime.jsx(ForwardedDInput, Object.assign({ ref: inputRef, value: innerValue, onChange: handleOnChange, inputMode: "decimal", type: innerType, onFocus: handleOnFocus, onBlur: handleOnBlur, onWheel: handleOnWheel, inputStart: (jsxRuntime.jsx("span", { slot: "input-start", className: "d-input-currency-symbol", children: currencyCode || currencyOptions.symbol })) }, props)));
|
|
1836
1998
|
}
|
|
1837
1999
|
const ForwardedDInputCurrency = React.forwardRef(DInputCurrency);
|
|
1838
2000
|
ForwardedDInputCurrency.displayName = 'DInputCurrency';
|
|
@@ -1854,26 +2016,25 @@ ForwardedDInputPassword.displayName = 'DInputPassword';
|
|
|
1854
2016
|
|
|
1855
2017
|
function PasswordCheckItem({ password, regex, text, }) {
|
|
1856
2018
|
const isValid = regex.test(password);
|
|
1857
|
-
return (jsxRuntime.jsxs("li", { className:
|
|
2019
|
+
return (jsxRuntime.jsxs("li", { className: `d-password-check-item${isValid ? ' is-valid' : ''}`, children: [jsxRuntime.jsx(DIcon, { className: "d-password-check-item-icon", icon: isValid ? 'CircleCheck' : 'Circle', size: "16px" }), jsxRuntime.jsx("span", { children: text })] }));
|
|
1858
2020
|
}
|
|
1859
2021
|
|
|
1860
|
-
const
|
|
2022
|
+
const getStrengthModifier = (strength, total) => {
|
|
1861
2023
|
const percentage = total > 0 ? strength / total : 0;
|
|
1862
2024
|
if (percentage === 0)
|
|
1863
|
-
return '
|
|
2025
|
+
return 'is-empty';
|
|
1864
2026
|
if (percentage <= 0.25)
|
|
1865
|
-
return '
|
|
2027
|
+
return 'is-weak';
|
|
1866
2028
|
if (percentage <= 0.5)
|
|
1867
|
-
return '
|
|
2029
|
+
return 'is-fair';
|
|
1868
2030
|
if (percentage <= 0.75)
|
|
1869
|
-
return '
|
|
1870
|
-
return '
|
|
2031
|
+
return 'is-good';
|
|
2032
|
+
return 'is-strong';
|
|
1871
2033
|
};
|
|
1872
2034
|
function PasswordStrengthBar({ strength, total }) {
|
|
1873
2035
|
const percentage = total > 0 ? (strength / total) * 100 : 0;
|
|
1874
|
-
return (jsxRuntime.jsx("div", { className: "
|
|
2036
|
+
return (jsxRuntime.jsx("div", { className: "d-password-strength-bar", children: jsxRuntime.jsx("div", { className: `d-password-strength-bar-fill ${getStrengthModifier(strength, total)}`, style: {
|
|
1875
2037
|
width: `${percentage}%`,
|
|
1876
|
-
transition: 'width 0.3s ease-in-out',
|
|
1877
2038
|
} }) }));
|
|
1878
2039
|
}
|
|
1879
2040
|
|
|
@@ -1909,7 +2070,7 @@ function PasswordChecksList({ password, validationMessages, enabledChecks, }) {
|
|
|
1909
2070
|
const passwordChecks = allChecks.filter((check) => enabledChecks.includes(check.key));
|
|
1910
2071
|
const passed = passwordChecks.filter((r) => r.regex.test(password)).length;
|
|
1911
2072
|
const total = passwordChecks.length;
|
|
1912
|
-
return (jsxRuntime.jsxs("div", { className: "
|
|
2073
|
+
return (jsxRuntime.jsxs("div", { className: "d-password-strength-meter", children: [jsxRuntime.jsx(PasswordStrengthBar, { strength: passed, total: total }), jsxRuntime.jsx("ul", { className: "d-password-check-list", children: passwordChecks.map(({ key, regex, text }) => (jsxRuntime.jsx(PasswordCheckItem, { password: password, regex: regex, text: text }, key))) })] }));
|
|
1913
2074
|
}
|
|
1914
2075
|
|
|
1915
2076
|
const DEFAULT_VALIDATION_MESSAGES = {
|
|
@@ -1950,9 +2111,9 @@ function DInputCheck(_a) {
|
|
|
1950
2111
|
]);
|
|
1951
2112
|
React.useEffect(() => {
|
|
1952
2113
|
if (innerRef.current) {
|
|
1953
|
-
innerRef.current.indeterminate = Boolean(indeterminate);
|
|
2114
|
+
innerRef.current.indeterminate = type === 'checkbox' && Boolean(indeterminate);
|
|
1954
2115
|
}
|
|
1955
|
-
}, [indeterminate]);
|
|
2116
|
+
}, [indeterminate, type]);
|
|
1956
2117
|
React.useEffect(() => {
|
|
1957
2118
|
if (innerRef.current) {
|
|
1958
2119
|
innerRef.current.checked = checked;
|
|
@@ -2145,10 +2306,18 @@ function DInputSelect({ id: idProp, name, label = '', className, style, options
|
|
|
2145
2306
|
}), children: [iconStart && (jsxRuntime.jsx("button", { type: "button", className: "input-group-text", id: `${id}Start`, onClick: iconStartClickHandler, disabled: disabled || loading, "aria-label": iconStartAriaLabel, children: iconStart && (jsxRuntime.jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix })) })), dynamicComponent, iconEnd && !loading && (jsxRuntime.jsx("button", { type: "button", className: "input-group-text", id: `${id}End`, onClick: iconEndClickHandler, disabled: disabled || loading, "aria-label": iconEndAriaLabel, children: iconEnd && (jsxRuntime.jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix })) })), loading && (jsxRuntime.jsx("div", { className: "input-group-text form-control-icon loading", children: jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsxRuntime.jsx("span", { className: "visually-hidden", children: "Loading..." }) }) }))] }), hint && (jsxRuntime.jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
|
|
2146
2307
|
}
|
|
2147
2308
|
|
|
2148
|
-
function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, invalid = false, valid = false, readonly, className, style, dataAttributes, inputClassName, onChange, }) {
|
|
2309
|
+
function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, invalid = false, valid = false, hint, readonly, className, style, dataAttributes, inputClassName, onChange, }) {
|
|
2149
2310
|
const innerId = React.useId();
|
|
2150
2311
|
const id = React.useMemo(() => idProp || innerId, [idProp, innerId]);
|
|
2151
2312
|
const [internalIsChecked, setInternalIsChecked] = React.useState(checked);
|
|
2313
|
+
const ariaDescribedby = React.useMemo(() => ([
|
|
2314
|
+
!!hint && `${id}Hint`,
|
|
2315
|
+
]
|
|
2316
|
+
.filter(Boolean)
|
|
2317
|
+
.join(' ')), [
|
|
2318
|
+
id,
|
|
2319
|
+
hint,
|
|
2320
|
+
]);
|
|
2152
2321
|
React.useEffect(() => {
|
|
2153
2322
|
setInternalIsChecked(checked);
|
|
2154
2323
|
}, [checked]);
|
|
@@ -2157,10 +2326,10 @@ function DInputSwitch({ id: idProp, label, ariaLabel, name, checked, disabled, i
|
|
|
2157
2326
|
setInternalIsChecked(value);
|
|
2158
2327
|
onChange === null || onChange === void 0 ? void 0 : onChange(value);
|
|
2159
2328
|
}, [onChange]);
|
|
2160
|
-
return (jsxRuntime.jsxs("div", Object.assign({ className: classNames('form-check form-switch', className) }, dataAttributes, { children: [jsxRuntime.jsx("input", { id: id, name: name, onChange: readonly ? () => false : changeHandler, className: classNames('form-check-input', {
|
|
2329
|
+
return (jsxRuntime.jsxs("div", Object.assign({ className: classNames('form-check form-switch', className) }, dataAttributes, { children: [jsxRuntime.jsx("input", Object.assign({ id: id, name: name, onChange: readonly ? () => false : changeHandler, className: classNames('form-check-input', {
|
|
2161
2330
|
'is-invalid': invalid,
|
|
2162
2331
|
'is-valid': valid,
|
|
2163
|
-
}, inputClassName), style: style, type: "checkbox", role: "switch", checked: internalIsChecked, disabled: disabled, "aria-label": ariaLabel }), label && (jsxRuntime.jsx("label", { className: "form-check-label", htmlFor: id, children: label }))] })));
|
|
2332
|
+
}, inputClassName), style: style, type: "checkbox", role: "switch", checked: internalIsChecked, disabled: disabled, "aria-label": ariaLabel }, ariaDescribedby && { 'aria-describedby': ariaDescribedby })), label && (jsxRuntime.jsx("label", { className: "form-check-label", htmlFor: id, children: label })), hint && (jsxRuntime.jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
|
|
2164
2333
|
}
|
|
2165
2334
|
|
|
2166
2335
|
function DInputRange(_a, ref) {
|
|
@@ -2201,6 +2370,7 @@ const ForwardedDInputRange = React.forwardRef(DInputRange);
|
|
|
2201
2370
|
ForwardedDInputRange.displayName = 'DInputRange';
|
|
2202
2371
|
|
|
2203
2372
|
function DListGroupItem({ as = 'li', action: actionProp, active, disabled, href, onClick, color, iconStart, iconStartFamilyClass, iconStartFamilyPrefix, iconStartMaterialStyle, iconEnd, iconEndFamilyClass, iconEndFamilyPrefix, iconEndMaterialStyle, children, className, style, dataAttributes, }) {
|
|
2373
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
|
|
2204
2374
|
const Tag = React.useMemo(() => {
|
|
2205
2375
|
if (href) {
|
|
2206
2376
|
return 'a';
|
|
@@ -2229,7 +2399,7 @@ function DListGroupItem({ as = 'li', action: actionProp, active, disabled, href,
|
|
|
2229
2399
|
}
|
|
2230
2400
|
return Object.assign(Object.assign({}, active && { 'aria-current': true }), disabled && { 'aria-disabled': true });
|
|
2231
2401
|
}, [Tag, active, disabled]);
|
|
2232
|
-
return (jsxRuntime.jsxs(Tag, Object.assign({ className: classNames(generateClasses, className), style: style }, Tag === 'a' && href && { href }, onClick && { onClick }, ariaAttributes, dataAttributes, Tag === 'button' && { type: 'button' }, { children: [iconStart && (jsxRuntime.jsx(DIcon, { icon: iconStart, familyClass: iconStartFamilyClass, familyPrefix: iconStartFamilyPrefix, materialStyle: iconStartMaterialStyle })), children, iconEnd && (jsxRuntime.jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle, className: "ms-auto" }))] })));
|
|
2402
|
+
return (jsxRuntime.jsxs(Tag, Object.assign({ className: classNames(generateClasses, className), style: style }, Tag === 'a' && href && { href }, onClick && { onClick }, ariaAttributes, dataAttributes, Tag === 'button' && { type: 'button' }, { children: [iconStart && (jsxRuntime.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 && (jsxRuntime.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" }))] })));
|
|
2233
2403
|
}
|
|
2234
2404
|
|
|
2235
2405
|
function DListGroup$1({ as = 'ul', numbered, flush, horizontal, children, className, style, dataAttributes, }) {
|
|
@@ -2256,10 +2426,11 @@ var DListGroup = Object.assign(DListGroup$1, {
|
|
|
2256
2426
|
Item: DListGroupItem,
|
|
2257
2427
|
});
|
|
2258
2428
|
|
|
2259
|
-
function DModalHeader({ showCloseButton, onClose, children, className, style, iconFamilyClass, iconFamilyPrefix, icon: iconProp, materialStyle
|
|
2260
|
-
|
|
2429
|
+
function DModalHeader({ showCloseButton, onClose, children, className, style, iconFamilyClass, iconFamilyPrefix, icon: iconProp, iconMaterialStyle, materialStyle: materialStyleProp, }) {
|
|
2430
|
+
var _a;
|
|
2431
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { xLg, }, } = useDContext();
|
|
2261
2432
|
const icon = React.useMemo(() => iconProp || xLg, [iconProp, xLg]);
|
|
2262
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: classNames('modal-header', className), style: style, children: [jsxRuntime.jsx("div", { children: children }), showCloseButton && (jsxRuntime.jsx("button", { type: "button", className: "d-close
|
|
2433
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: classNames('modal-header', className), style: style, children: [jsxRuntime.jsx("div", { children: children }), showCloseButton && (jsxRuntime.jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: onClose, children: jsxRuntime.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 }) }))] }), jsxRuntime.jsx("div", { className: "d-modal-separator" })] }));
|
|
2263
2434
|
}
|
|
2264
2435
|
|
|
2265
2436
|
function DModalBody({ children, className, style, }) {
|
|
@@ -2300,10 +2471,11 @@ var DModal = Object.assign(DModal$1, {
|
|
|
2300
2471
|
Footer: DModalFooter,
|
|
2301
2472
|
});
|
|
2302
2473
|
|
|
2303
|
-
function DOffcanvasHeader({ showCloseButton, onClose, children, className, style, iconFamilyClass, iconFamilyPrefix, icon: iconProp, materialStyle
|
|
2304
|
-
|
|
2474
|
+
function DOffcanvasHeader({ showCloseButton, onClose, children, className, style, iconFamilyClass, iconFamilyPrefix, icon: iconProp, iconMaterialStyle, materialStyle: materialStyleProp, }) {
|
|
2475
|
+
var _a;
|
|
2476
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { xLg, }, } = useDContext();
|
|
2305
2477
|
const icon = React.useMemo(() => iconProp || xLg, [iconProp, xLg]);
|
|
2306
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: classNames('offcanvas-header', className), style: style, children: [jsxRuntime.jsx("div", { children: children }), showCloseButton && (jsxRuntime.jsx("button", { type: "button", className: "d-close
|
|
2478
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: classNames('offcanvas-header', className), style: style, children: [jsxRuntime.jsx("div", { children: children }), showCloseButton && (jsxRuntime.jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: onClose, children: jsxRuntime.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 }) }))] }), jsxRuntime.jsx("div", { className: "d-offcanvas-separator" })] }));
|
|
2307
2479
|
}
|
|
2308
2480
|
|
|
2309
2481
|
function DOffcanvasBody({ children, className, style, }) {
|
|
@@ -2430,7 +2602,7 @@ function DPopover({ children, renderComponent, open, setOpen, adjustContentToRen
|
|
|
2430
2602
|
}
|
|
2431
2603
|
const reference = React.cloneElement(triggerElement, Object.assign({ ref: refs.setReference }, getReferenceProps(triggerElement.props)));
|
|
2432
2604
|
return (jsxRuntime.jsxs("div", Object.assign({ className: classNames('d-popover', className), style: generateStyleVariables }, dataAttributes, { children: [reference, isOpen && (jsxRuntime.jsx(react.FloatingFocusManager, { context: context, modal: false, children: jsxRuntime.jsx("div", Object.assign({ className: classNames('d-popover-content', {
|
|
2433
|
-
'
|
|
2605
|
+
'd-popover-content-fill': adjustContentToRender,
|
|
2434
2606
|
}), ref: refs.setFloating, style: floatingStyles, "aria-labelledby": headingId }, getFloatingProps(), { children: children })) }))] })));
|
|
2435
2607
|
}
|
|
2436
2608
|
|
|
@@ -2444,8 +2616,8 @@ function DProgress({ className, style, currentValue, minValue = 0, maxValue = 10
|
|
|
2444
2616
|
return (jsxRuntime.jsx("div", Object.assign({ className: classNames('progress', className), style: Object.assign({ height }, style) }, dataAttributes, { children: jsxRuntime.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 }) })));
|
|
2445
2617
|
}
|
|
2446
2618
|
|
|
2447
|
-
function DStepper$2({ options, currentStep, iconSuccess: iconSuccessProp, iconSuccessFamilyClass, iconSuccessFamilyPrefix, iconSuccessMaterialStyle
|
|
2448
|
-
const { iconMap: { check, }, } = useDContext();
|
|
2619
|
+
function DStepper$2({ options, currentStep, iconSuccess: iconSuccessProp, iconSuccessFamilyClass, iconSuccessFamilyPrefix, iconSuccessMaterialStyle, vertical = false, completed, alignStart = false, className, style, }) {
|
|
2620
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, iconMap: { check, }, } = useDContext();
|
|
2449
2621
|
const icon = React.useMemo(() => iconSuccessProp || check, [check, iconSuccessProp]);
|
|
2450
2622
|
if (currentStep < 1 || currentStep > options.length) {
|
|
2451
2623
|
throw new Error('Current step should be in the range from 1 to options length');
|
|
@@ -2460,7 +2632,7 @@ function DStepper$2({ options, currentStep, iconSuccess: iconSuccessProp, iconSu
|
|
|
2460
2632
|
}), children: [jsxRuntime.jsx("div", { className: "d-step-value", children: jsxRuntime.jsxs("div", { className: classNames({
|
|
2461
2633
|
'd-step-icon-container': true,
|
|
2462
2634
|
'd-step-check': value < currentStep || completed,
|
|
2463
|
-
}), children: [((value < currentStep) || completed) && (jsxRuntime.jsx(DIcon, { icon: icon, familyClass: iconSuccessFamilyClass, familyPrefix: iconSuccessFamilyPrefix, materialStyle: iconSuccessMaterialStyle, className: "d-step-icon" })), value] }) }), jsxRuntime.jsxs("div", { className: "d-step-text-container", children: [jsxRuntime.jsx("div", { className: "d-step-label", children: label }), description && (jsxRuntime.jsx("div", { className: "d-step-description", children: description }))] })] }, value))) }));
|
|
2635
|
+
}), children: [((value < currentStep) || completed) && (jsxRuntime.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] }) }), jsxRuntime.jsxs("div", { className: "d-step-text-container", children: [jsxRuntime.jsx("div", { className: "d-step-label", children: label }), description && (jsxRuntime.jsx("div", { className: "d-step-description", children: description }))] })] }, value))) }));
|
|
2464
2636
|
}
|
|
2465
2637
|
|
|
2466
2638
|
function DStepper$1({ options, currentStep, className, style, }) {
|
|
@@ -2493,14 +2665,21 @@ function DStepper$1({ options, currentStep, className, style, }) {
|
|
|
2493
2665
|
return (jsxRuntime.jsxs("div", { className: classNames('d-stepper', className), style: style, children: [jsxRuntime.jsx("div", { className: "d-step-bar", style: { background: progressStyle }, children: jsxRuntime.jsx("p", { className: "d-step-number", children: `${currentStep}/${options.length}` }) }), jsxRuntime.jsx("div", { className: "d-step-info", children: Object.keys(currentOption).length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "d-step-label", children: currentOption.label }), jsxRuntime.jsx("div", { className: "d-step-description", children: currentOption.description || '' })] })) })] }));
|
|
2494
2666
|
}
|
|
2495
2667
|
|
|
2496
|
-
function DStepper({ options, currentStep, iconSuccess, iconSuccessFamilyClass, iconSuccessFamilyPrefix, iconSuccessMaterialStyle
|
|
2497
|
-
|
|
2668
|
+
function DStepper({ options, currentStep, iconSuccess, iconSuccessFamilyClass, iconSuccessFamilyPrefix, iconSuccessMaterialStyle, vertical = false, breakpoint = 'lg', className, completed = false, style, dataAttributes, }) {
|
|
2669
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
|
|
2670
|
+
return (jsxRuntime.jsxs("div", Object.assign({ className: className, style: style }, dataAttributes, { children: [jsxRuntime.jsx("div", { className: classNames('d-stepper-mobile', `d-block d-${breakpoint}-none`), children: jsxRuntime.jsx(DStepper$1, { options: options, currentStep: currentStep }) }), jsxRuntime.jsx("div", { className: classNames('d-stepper-desktop', `d-none d-${breakpoint}-block`), children: jsxRuntime.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 }) })] })));
|
|
2498
2671
|
}
|
|
2499
2672
|
|
|
2500
2673
|
const ARROW_WIDTH = 8;
|
|
2501
2674
|
const ARROW_HEIGHT = 4;
|
|
2502
|
-
const GAP = 2;
|
|
2503
|
-
|
|
2675
|
+
const GAP$1 = 2;
|
|
2676
|
+
/**
|
|
2677
|
+
* Tooltip is an abstraction component that wraps any element (`Component`) and displays
|
|
2678
|
+
* floating contextual content (`children`) positioned relative to it using Floating UI.
|
|
2679
|
+
* Use it to add short, non-critical hints or descriptions triggered by hover, focus, or
|
|
2680
|
+
* click, without altering the surrounding layout.
|
|
2681
|
+
*/
|
|
2682
|
+
function DTooltip({ className, childrenClassName, style, offSet = ARROW_HEIGHT + GAP$1, padding, withFocus = false, withClick = false, withHover = true, open = false, placement = 'top', size, Component, children, }) {
|
|
2504
2683
|
const [isOpen, setIsOpen] = React.useState(open);
|
|
2505
2684
|
const arrowRef = React.useRef(null);
|
|
2506
2685
|
const { refs, context, floatingStyles, } = react.useFloating({
|
|
@@ -2569,8 +2748,16 @@ function DTabs$1({ children, defaultSelected, onChange, options, className, clas
|
|
|
2569
2748
|
React.useEffect(() => {
|
|
2570
2749
|
setSelected(defaultSelected);
|
|
2571
2750
|
}, [defaultSelected]);
|
|
2572
|
-
const generateClasses = React.useMemo(() => (Object.assign({ nav: true, '
|
|
2751
|
+
const generateClasses = React.useMemo(() => (Object.assign({ nav: true, 'd-tabs-nav-vertical': vertical && variant !== 'tabs', [`nav-${variant}`]: true }, className && { [className]: true })), [vertical, variant, className]);
|
|
2573
2752
|
const tabRefs = React.useRef([]);
|
|
2753
|
+
// Always holds the latest `options` without needing to be a dependency:
|
|
2754
|
+
// `options` is commonly passed as an inline array literal (e.g.
|
|
2755
|
+
// `options={[{ label: 'SMS', tab: 'sms' }, ...]}`), so it's a new array
|
|
2756
|
+
// reference on every parent render even when its content hasn't changed.
|
|
2757
|
+
// Reading it from this ref (updated synchronously on every render) lets
|
|
2758
|
+
// the focus effect below react only to `selected` changing.
|
|
2759
|
+
const optionsRef = React.useRef(options);
|
|
2760
|
+
optionsRef.current = options;
|
|
2574
2761
|
React.useEffect(() => {
|
|
2575
2762
|
tabRefs.current = options.map((_, i) => tabRefs.current[i] || React.createRef());
|
|
2576
2763
|
}, [options]);
|
|
@@ -2585,20 +2772,28 @@ function DTabs$1({ children, defaultSelected, onChange, options, className, clas
|
|
|
2585
2772
|
setSelected(firstEnabled.tab);
|
|
2586
2773
|
}
|
|
2587
2774
|
}, [options, selected]);
|
|
2588
|
-
// Declarative focus management
|
|
2589
|
-
|
|
2775
|
+
// Declarative focus management. Wrapped in `useCallback` with an empty
|
|
2776
|
+
// dependency array since it only reads from the `tabRefs` ref, so its
|
|
2777
|
+
// identity stays stable across renders and it can safely be used as an
|
|
2778
|
+
// effect dependency below.
|
|
2779
|
+
const focusTab = React.useCallback((idx) => {
|
|
2590
2780
|
var _a;
|
|
2591
2781
|
if ((_a = tabRefs.current[idx]) === null || _a === void 0 ? void 0 : _a.current) {
|
|
2592
2782
|
tabRefs.current[idx].current.focus();
|
|
2593
2783
|
}
|
|
2594
|
-
};
|
|
2595
|
-
// Focus selected tab when selected changes
|
|
2784
|
+
}, []);
|
|
2785
|
+
// Focus selected tab when selected changes.
|
|
2786
|
+
// Reads `options` from `optionsRef` (see comment above) instead of
|
|
2787
|
+
// depending on `options` directly, so a parent re-render that merely
|
|
2788
|
+
// creates a new `options` reference with identical content doesn't call
|
|
2789
|
+
// `focusTab` again and steal focus away from unrelated elements on the
|
|
2790
|
+
// page (e.g. an OTP input).
|
|
2596
2791
|
React.useEffect(() => {
|
|
2597
|
-
const idx =
|
|
2792
|
+
const idx = optionsRef.current.findIndex((opt) => opt.tab === selected && !opt.disabled);
|
|
2598
2793
|
if (idx !== -1) {
|
|
2599
2794
|
focusTab(idx);
|
|
2600
2795
|
}
|
|
2601
|
-
}, [selected,
|
|
2796
|
+
}, [selected, focusTab]);
|
|
2602
2797
|
const handleKeyDown = React.useCallback((idx, e) => {
|
|
2603
2798
|
const count = options.length;
|
|
2604
2799
|
if (count === 0)
|
|
@@ -2627,7 +2822,7 @@ function DTabs$1({ children, defaultSelected, onChange, options, className, clas
|
|
|
2627
2822
|
}
|
|
2628
2823
|
}
|
|
2629
2824
|
}
|
|
2630
|
-
}, [options, vertical]);
|
|
2825
|
+
}, [options, vertical, focusTab]);
|
|
2631
2826
|
let tablistProps = {};
|
|
2632
2827
|
if (ariaLabelledBy) {
|
|
2633
2828
|
tablistProps = { 'aria-labelledby': ariaLabelledBy };
|
|
@@ -2640,12 +2835,12 @@ function DTabs$1({ children, defaultSelected, onChange, options, className, clas
|
|
|
2640
2835
|
isSelected,
|
|
2641
2836
|
}), [isSelected]);
|
|
2642
2837
|
return (jsxRuntime.jsx(TabContext.Provider, { value: value, children: jsxRuntime.jsxs("div", Object.assign({ className: classNames({
|
|
2643
|
-
'd-
|
|
2644
|
-
'
|
|
2838
|
+
'd-tabs': true,
|
|
2839
|
+
'd-tabs-column': !vertical || variant === 'tabs',
|
|
2645
2840
|
}), style: style }, dataAttributes, { children: [jsxRuntime.jsx("ul", Object.assign({ className: classNames(generateClasses), role: "tablist", "aria-orientation": vertical ? 'vertical' : undefined }, tablistProps, { children: options.map((option, idx) => {
|
|
2646
2841
|
const isTabSelected = !!option.tab && option.tab === selected;
|
|
2647
2842
|
return (jsxRuntime.jsx("li", { role: "presentation", className: "nav-item", children: jsxRuntime.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));
|
|
2648
|
-
}) })), jsxRuntime.jsx("div", { className: "
|
|
2843
|
+
}) })), jsxRuntime.jsx("div", { className: "d-tabs-content tab-content", children: children })] })) }));
|
|
2649
2844
|
}
|
|
2650
2845
|
var DTabs = Object.assign(DTabs$1, {
|
|
2651
2846
|
Tab: DTabContent,
|
|
@@ -2707,11 +2902,11 @@ function useDToast() {
|
|
|
2707
2902
|
if (!description) {
|
|
2708
2903
|
return (jsxRuntime.jsx(DToast, { className: classNames({
|
|
2709
2904
|
[`toast-${color}`]: !!color,
|
|
2710
|
-
}, 'show'), children: jsxRuntime.jsxs(DToast.Body, { children: [icon && (jsxRuntime.jsx(DIcon, { className: "toast-icon", icon: icon })), jsxRuntime.jsx("p", { className: "toast-title", children: title }), jsxRuntime.jsx("button", { type: "button", className: "d-close
|
|
2905
|
+
}, 'show'), children: jsxRuntime.jsxs(DToast.Body, { children: [icon && (jsxRuntime.jsx(DIcon, { className: "toast-icon", icon: icon })), jsxRuntime.jsx("p", { className: "toast-title", children: title }), jsxRuntime.jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: () => reactHotToast.toast.dismiss(id), children: jsxRuntime.jsx(DIcon, { icon: closeIcon || xLg }) })] }) }));
|
|
2711
2906
|
}
|
|
2712
2907
|
return (jsxRuntime.jsxs(DToast, { className: classNames({
|
|
2713
2908
|
[`toast-${color}`]: !!color,
|
|
2714
|
-
}, 'show'), children: [jsxRuntime.jsxs(DToast.Header, { children: [icon && (jsxRuntime.jsx(DIcon, { className: "toast-icon", icon: icon })), jsxRuntime.jsx("p", { className: "toast-title", children: title }), timestamp && (jsxRuntime.jsx("small", { className: "toast-timestamp", children: timestamp })), jsxRuntime.jsx("button", { type: "button", className: "d-close
|
|
2909
|
+
}, 'show'), children: [jsxRuntime.jsxs(DToast.Header, { children: [icon && (jsxRuntime.jsx(DIcon, { className: "toast-icon", icon: icon })), jsxRuntime.jsx("p", { className: "toast-title", children: title }), timestamp && (jsxRuntime.jsx("small", { className: "toast-timestamp", children: timestamp })), jsxRuntime.jsx("button", { type: "button", className: "d-close", "aria-label": "Close", onClick: () => reactHotToast.toast.dismiss(id), children: jsxRuntime.jsx(DIcon, { icon: closeIcon || xLg }) })] }), jsxRuntime.jsx(DToast.Body, { children: jsxRuntime.jsx("span", { children: description }) })] }));
|
|
2715
2910
|
}, toastProps);
|
|
2716
2911
|
}, [xLg]);
|
|
2717
2912
|
return {
|
|
@@ -2733,11 +2928,10 @@ async function configureI8n(resources, _a = {}) {
|
|
|
2733
2928
|
.then((t) => t);
|
|
2734
2929
|
}
|
|
2735
2930
|
|
|
2736
|
-
function getQueryString(value, config = {
|
|
2737
|
-
useSearch
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
return urlParams.get(value) || config.default;
|
|
2931
|
+
function getQueryString(value, config = {}) {
|
|
2932
|
+
const { useSearch = true, default: defaultValue } = config;
|
|
2933
|
+
const urlParams = new URLSearchParams(useSearch ? window.location.search : '');
|
|
2934
|
+
return urlParams.get(value) || defaultValue;
|
|
2741
2935
|
}
|
|
2742
2936
|
|
|
2743
2937
|
function changeQueryString(values, { useSearch = true, pushState = false, } = {}) {
|
|
@@ -2767,11 +2961,132 @@ function validatePhoneNumber(phone) {
|
|
|
2767
2961
|
}
|
|
2768
2962
|
}
|
|
2769
2963
|
|
|
2964
|
+
const SAFE_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:']);
|
|
2965
|
+
/**
|
|
2966
|
+
* Characters the URL parser drops before resolving a URL, so they cannot be used to hide a
|
|
2967
|
+
* scheme-relative prefix or a dangerous scheme (e.g. `/<TAB>/evil.com`, `java<TAB>script:`).
|
|
2968
|
+
*/
|
|
2969
|
+
const IGNORED_CHARS$1 = /[\t\n\r]/g;
|
|
2970
|
+
/**
|
|
2971
|
+
* Two leading separators in any combination. Browsers treat a leading `\` exactly like a
|
|
2972
|
+
* leading `/`, so `//`, `/\`, `\/` and `\\` all resolve to a scheme-relative URL.
|
|
2973
|
+
*/
|
|
2974
|
+
const SCHEME_RELATIVE = /^[/\\]{2}/;
|
|
2975
|
+
const LEADING_SEPARATOR = /^[/\\]/;
|
|
2976
|
+
/**
|
|
2977
|
+
* Validates a `href` value and returns it only if it is safe to render as a link,
|
|
2978
|
+
* preventing XSS through unsafe URL schemes and scheme-relative URLs.
|
|
2979
|
+
*
|
|
2980
|
+
* Before validating, the value is trimmed and every tab, line feed and carriage return is
|
|
2981
|
+
* removed, because the URL parser ignores those characters too and they would otherwise
|
|
2982
|
+
* hide an unsafe value from the checks below.
|
|
2983
|
+
*
|
|
2984
|
+
* A `href` is considered safe when it is either:
|
|
2985
|
+
* - An absolute path starting with a single separator (e.g. `/accounts/42`). A leading `\`
|
|
2986
|
+
* is normalized to `/` in the returned value, since that is how the browser resolves it.
|
|
2987
|
+
* - A URL using one of the allowed schemes: `http:`, `https:`, `mailto:`, `tel:`.
|
|
2988
|
+
*
|
|
2989
|
+
* A `href` is rejected (returns `undefined`) when it is:
|
|
2990
|
+
* - Empty or made only of whitespace/ignored characters (`''`, `' '`).
|
|
2991
|
+
* - Scheme-relative (starts with two separators, e.g. `//evil.com`, `/\evil.com`,
|
|
2992
|
+
* `/<TAB>/evil.com`), since the browser would resolve it using the current protocol and it
|
|
2993
|
+
* can be used to redirect to an attacker-controlled host.
|
|
2994
|
+
* - Using a disallowed/dangerous scheme, such as `javascript:` or `data:`
|
|
2995
|
+
* (e.g. `javascript:alert(1)`, `data:text/html,<script>...</script>`).
|
|
2996
|
+
* - Not parseable as an absolute URL and not an absolute path, such as bare fragments
|
|
2997
|
+
* (`#anchor`) or scheme-less relative paths (`relative/path`). These cannot be validated
|
|
2998
|
+
* against `SAFE_SCHEMES`, so they are rejected rather than assumed safe.
|
|
2999
|
+
*
|
|
3000
|
+
* @param href - The raw URL or path to validate, typically coming from user input,
|
|
3001
|
+
* a CMS, or an external API.
|
|
3002
|
+
* @returns The sanitized `href` when safe, `undefined` otherwise.
|
|
3003
|
+
*
|
|
3004
|
+
* @example
|
|
3005
|
+
* sanitizeHref('/accounts/42'); // '/accounts/42'
|
|
3006
|
+
* sanitizeHref('https://example.com'); // 'https://example.com'
|
|
3007
|
+
* sanitizeHref('mailto:test@example.com'); // 'mailto:test@example.com'
|
|
3008
|
+
* sanitizeHref('//evil.com'); // undefined
|
|
3009
|
+
* sanitizeHref('/\\evil.com'); // undefined
|
|
3010
|
+
* sanitizeHref('javascript:alert(1)'); // undefined
|
|
3011
|
+
*/
|
|
3012
|
+
function sanitizeHref(href) {
|
|
3013
|
+
const normalized = href.trim().replace(IGNORED_CHARS$1, '');
|
|
3014
|
+
if (!normalized)
|
|
3015
|
+
return undefined;
|
|
3016
|
+
if (SCHEME_RELATIVE.test(normalized))
|
|
3017
|
+
return undefined;
|
|
3018
|
+
if (LEADING_SEPARATOR.test(normalized))
|
|
3019
|
+
return `/${normalized.slice(1)}`;
|
|
3020
|
+
try {
|
|
3021
|
+
const { protocol } = new URL(normalized);
|
|
3022
|
+
return SAFE_SCHEMES.has(protocol) ? normalized : undefined;
|
|
3023
|
+
}
|
|
3024
|
+
catch (_a) {
|
|
3025
|
+
return undefined;
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
/**
|
|
3030
|
+
* Characters the URL parser drops before resolving a URL, so they cannot be used to hide a
|
|
3031
|
+
* scheme-relative prefix (e.g. `/<TAB>/evil.com`).
|
|
3032
|
+
*/
|
|
3033
|
+
const IGNORED_CHARS = /[\t\n\r]/g;
|
|
3034
|
+
/**
|
|
3035
|
+
* Leading separators. Browsers treat a leading `\` exactly like a leading `/`, so both have
|
|
3036
|
+
* to be stripped to prevent scheme-relative URLs (`//evil.com`, `/\evil.com`, `\\evil.com`).
|
|
3037
|
+
*/
|
|
3038
|
+
const LEADING_SEPARATORS = /^[/\\]+/;
|
|
3039
|
+
/**
|
|
3040
|
+
* Builds an internal URL from a `path` and a set of query `params`, normalizing leading
|
|
3041
|
+
* separators to prevent scheme-relative URLs (e.g. `//accounts` and `/\accounts` both become
|
|
3042
|
+
* `/accounts`).
|
|
3043
|
+
*
|
|
3044
|
+
* The `path` is trimmed and every tab, line feed and carriage return is removed before
|
|
3045
|
+
* building the result, because the URL parser ignores those characters too and they would
|
|
3046
|
+
* otherwise hide a scheme-relative prefix (`/<TAB>/evil.com` resolves to `//evil.com`).
|
|
3047
|
+
*
|
|
3048
|
+
* Handles the special case where `path` is the literal string `'#'`, which happens when
|
|
3049
|
+
* a Liquid template variable used as a link target is left unconfigured; in that case the
|
|
3050
|
+
* params are ignored and `'#'` is returned as-is instead of building a broken URL.
|
|
3051
|
+
*
|
|
3052
|
+
* @param path - The path to build the URL from. Leading separators are stripped before
|
|
3053
|
+
* building the result (`/accounts`, `//accounts` and `\accounts` are all treated as `accounts`).
|
|
3054
|
+
* @param params - Key/value pairs serialized as the query string.
|
|
3055
|
+
* @returns The resulting URL:
|
|
3056
|
+
* - `'#'` when `path` normalizes to `'#'` (`'#'`, `'/#'`), ignoring the params.
|
|
3057
|
+
* - `'/'` when `path` is empty and there are no params.
|
|
3058
|
+
* - `'/?<query>'` when `path` is empty and there are params.
|
|
3059
|
+
* - `'<path>'` or `'<path>?<query>'` when `path` starts with `#`, since a fragment must not be
|
|
3060
|
+
* prefixed with `/` (it would navigate away from the current document).
|
|
3061
|
+
* - `'/<path>'` or `'/<path>?<query>'` otherwise.
|
|
3062
|
+
*
|
|
3063
|
+
* @example
|
|
3064
|
+
* buildUrl('accounts', { account_id: '42' }); // '/accounts?account_id=42'
|
|
3065
|
+
* buildUrl('//accounts', {}); // '/accounts'
|
|
3066
|
+
* buildUrl('#', { account_id: '42' }); // '#'
|
|
3067
|
+
* buildUrl('#accounts', { account_id: '42' }); // '#accounts?account_id=42'
|
|
3068
|
+
* buildUrl('', { tab: 'movimientos' }); // '/?tab=movimientos'
|
|
3069
|
+
*/
|
|
3070
|
+
function buildUrl(path, params) {
|
|
3071
|
+
const normalizedPath = path
|
|
3072
|
+
.trim()
|
|
3073
|
+
.replace(IGNORED_CHARS, '')
|
|
3074
|
+
.replace(LEADING_SEPARATORS, '');
|
|
3075
|
+
if (normalizedPath === '#')
|
|
3076
|
+
return '#';
|
|
3077
|
+
const query = new URLSearchParams(Object.entries(params).map(([key, value]) => [key, String(value)])).toString();
|
|
3078
|
+
if (normalizedPath === '')
|
|
3079
|
+
return query ? `/?${query}` : '/';
|
|
3080
|
+
const prefix = normalizedPath.startsWith('#') ? '' : '/';
|
|
3081
|
+
return `${prefix}${normalizedPath}${query ? `?${query}` : ''}`;
|
|
3082
|
+
}
|
|
3083
|
+
|
|
2770
3084
|
function DInputPhone(_a, ref) {
|
|
2771
3085
|
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 = tslib.__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"]);
|
|
2772
3086
|
const innerRef = useProvidedRefOrCreate(ref);
|
|
2773
3087
|
const innerId = React.useId();
|
|
2774
3088
|
const id = React.useMemo(() => idProp || innerId, [idProp, innerId]);
|
|
3089
|
+
const { icon: { familyClass, familyPrefix, materialStyle, }, } = useDContext();
|
|
2775
3090
|
const handleOnIconEndClick = React.useCallback(() => {
|
|
2776
3091
|
onIconEndClick === null || onIconEndClick === void 0 ? void 0 : onIconEndClick(value);
|
|
2777
3092
|
}, [onIconEndClick, value]);
|
|
@@ -2845,7 +3160,7 @@ function DInputPhone(_a, ref) {
|
|
|
2845
3160
|
[`input-group-${size}`]: !!size,
|
|
2846
3161
|
'input-group': true,
|
|
2847
3162
|
'has-validation': invalid || valid,
|
|
2848
|
-
}), children: [jsxRuntime.jsx(reactInternationalPhone.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) && (jsxRuntime.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: jsxRuntime.jsx(DIcon, { icon: iconEnd, familyClass: iconEndFamilyClass, familyPrefix: iconEndFamilyPrefix, materialStyle: iconEndMaterialStyle }) })), loading && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}Loading`, children: jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsxRuntime.jsx("span", { className: "visually-hidden", children: "Loading..." }) }) })), !!inputEnd && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}InputEnd`, children: inputEnd }))] }), hint && (jsxRuntime.jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
|
|
3163
|
+
}), children: [jsxRuntime.jsx(reactInternationalPhone.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) && (jsxRuntime.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: jsxRuntime.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 && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}Loading`, children: jsxRuntime.jsx("span", { className: "spinner-border spinner-border-sm", role: "status", "aria-hidden": "true", children: jsxRuntime.jsx("span", { className: "visually-hidden", children: "Loading..." }) }) })), !!inputEnd && (jsxRuntime.jsx("div", { className: "input-group-text", id: `${id}InputEnd`, children: inputEnd }))] }), hint && (jsxRuntime.jsx("div", { className: "form-text", id: `${id}Hint`, children: hint }))] })));
|
|
2849
3164
|
}
|
|
2850
3165
|
const ForwardedDInputPhone = React.forwardRef(DInputPhone);
|
|
2851
3166
|
ForwardedDInputPhone.displayName = 'DInputPhone';
|
|
@@ -2860,89 +3175,228 @@ function DCreditCard({ brand = 'visa', name, number, holderText = 'Card Holder',
|
|
|
2860
3175
|
return (jsxRuntime.jsxs("div", { className: classNames('d-credit-card', isVertical && 'is-vertical', className), children: [jsxRuntime.jsxs("div", { className: "d-credit-card-header", children: [jsxRuntime.jsx("img", { src: logoImage || BRAND_LOGOS[brand] || DEFAULT_IMAGE, alt: brand, className: "d-credit-card-logo", width: 100 }), isChipVisible && (jsxRuntime.jsx("div", { className: "d-credit-card-chip", children: jsxRuntime.jsx("img", { src: CHIP_IMAGE, alt: "chip", width: 30, className: "d-credit-card-chip-image" }) }))] }), jsxRuntime.jsxs("div", { className: "d-credit-card-details", children: [jsxRuntime.jsx("div", { className: "d-credit-card-number", children: number }), jsxRuntime.jsx("small", { className: "d-credit-card-holder-text", children: holderText }), jsxRuntime.jsx("span", { className: "d-credit-card-name", children: name })] })] }));
|
|
2861
3176
|
}
|
|
2862
3177
|
|
|
3178
|
+
// Gap between the toggle and the menu.
|
|
3179
|
+
const GAP = 4;
|
|
3180
|
+
// Minimum distance the menu should keep from the viewport edges.
|
|
3181
|
+
const VIEWPORT_PADDING = 8;
|
|
3182
|
+
// Minimum usable height left for the menu before we consider a side unusable.
|
|
3183
|
+
const MIN_USABLE_SPACE = 120;
|
|
2863
3184
|
const getItemClass = (action) => classNames({
|
|
2864
3185
|
'dropdown-item d-flex align-items-center': true,
|
|
2865
3186
|
[`dropdown-item-${action.color}`]: !!action.color,
|
|
2866
3187
|
disabled: action.disabled,
|
|
2867
3188
|
});
|
|
2868
|
-
|
|
3189
|
+
const clamp = (value, min, max) => {
|
|
3190
|
+
if (max < min)
|
|
3191
|
+
return min;
|
|
3192
|
+
return Math.min(Math.max(value, min), max);
|
|
3193
|
+
};
|
|
3194
|
+
/**
|
|
3195
|
+
* `position: fixed` is normally relative to the viewport, but any ancestor
|
|
3196
|
+
* with a `transform`, `perspective`, `filter`, `will-change` (of those) or a
|
|
3197
|
+
* non-trivial `contain` establishes a new containing block, making `fixed`
|
|
3198
|
+
* behave like `absolute` relative to that ancestor instead (e.g. Storybook's
|
|
3199
|
+
* docs canvas wrapper, animated cards, sticky containers, etc.). We detect
|
|
3200
|
+
* that ancestor so the computed coordinates can be adjusted accordingly,
|
|
3201
|
+
* keeping the menu correctly anchored to the toggle in every context.
|
|
3202
|
+
*/
|
|
3203
|
+
const getFixedPositioningOffset = (fromEl) => {
|
|
3204
|
+
var _a;
|
|
3205
|
+
let node = (_a = fromEl === null || fromEl === void 0 ? void 0 : fromEl.parentElement) !== null && _a !== void 0 ? _a : null;
|
|
3206
|
+
while (node && node !== document.body) {
|
|
3207
|
+
const cs = window.getComputedStyle(node);
|
|
3208
|
+
// Treat empty/undefined values as "unset" (jsdom returns "" rather than
|
|
3209
|
+
// the CSS initial value like "none" for some of these properties).
|
|
3210
|
+
const isSet = (value) => !!value && value !== 'none';
|
|
3211
|
+
const establishesContainingBlock = isSet(cs.transform)
|
|
3212
|
+
|| isSet(cs.perspective)
|
|
3213
|
+
|| isSet(cs.filter)
|
|
3214
|
+
|| isSet(cs.backdropFilter)
|
|
3215
|
+
|| ['transform', 'perspective', 'filter'].some((prop) => { var _a; return (_a = cs.willChange) === null || _a === void 0 ? void 0 : _a.includes(prop); })
|
|
3216
|
+
|| cs.contain.split(' ').some((value) => ['layout', 'paint', 'strict', 'content'].includes(value));
|
|
3217
|
+
if (establishesContainingBlock) {
|
|
3218
|
+
const rect = node.getBoundingClientRect();
|
|
3219
|
+
return { top: rect.top, left: rect.left };
|
|
3220
|
+
}
|
|
3221
|
+
node = node.parentElement;
|
|
3222
|
+
}
|
|
3223
|
+
return { top: 0, left: 0 };
|
|
3224
|
+
};
|
|
3225
|
+
/**
|
|
3226
|
+
* Resolves where the menu should render (flip) and where it should sit along
|
|
3227
|
+
* the cross axis (shift), so it always stays fully inside the viewport
|
|
3228
|
+
* regardless of where the toggle is placed or how the viewport is resized.
|
|
3229
|
+
* This mimics floating-ui's `flip` + `shift` middlewares without adding the
|
|
3230
|
+
* dependency, keeping the existing Bootstrap markup/classes.
|
|
3231
|
+
*/
|
|
3232
|
+
const computeCoords = (toggleRect, menuSize, placement, alignment) => {
|
|
3233
|
+
const viewportWidth = window.innerWidth;
|
|
3234
|
+
const viewportHeight = window.innerHeight;
|
|
3235
|
+
const spaceBelow = viewportHeight - toggleRect.bottom;
|
|
3236
|
+
const spaceAbove = toggleRect.top;
|
|
3237
|
+
const spaceLeft = toggleRect.left;
|
|
3238
|
+
const spaceRight = viewportWidth - toggleRect.right;
|
|
3239
|
+
let side = placement === 'auto'
|
|
3240
|
+
? 'down'
|
|
3241
|
+
: placement;
|
|
3242
|
+
if (placement === 'auto') {
|
|
3243
|
+
side = spaceBelow >= menuSize.height + GAP || spaceBelow >= spaceAbove ? 'down' : 'up';
|
|
3244
|
+
}
|
|
3245
|
+
// Flip within the current axis if the chosen side can't fit the menu but
|
|
3246
|
+
// the opposite side (same axis) can.
|
|
3247
|
+
if (side === 'down' && spaceBelow < menuSize.height + GAP && spaceAbove > spaceBelow) {
|
|
3248
|
+
side = 'up';
|
|
3249
|
+
}
|
|
3250
|
+
else if (side === 'up' && spaceAbove < menuSize.height + GAP && spaceBelow > spaceAbove) {
|
|
3251
|
+
side = 'down';
|
|
3252
|
+
}
|
|
3253
|
+
else if (side === 'start' && spaceLeft < menuSize.width + GAP && spaceRight > spaceLeft) {
|
|
3254
|
+
side = 'end';
|
|
3255
|
+
}
|
|
3256
|
+
else if (side === 'end' && spaceRight < menuSize.width + GAP && spaceLeft > spaceRight) {
|
|
3257
|
+
side = 'start';
|
|
3258
|
+
}
|
|
3259
|
+
// Cross-axis fallback: e.g. a horizontally-centered toggle on a narrow
|
|
3260
|
+
// viewport can't open sideways (neither `start` nor `end` fit), but there
|
|
3261
|
+
// is plenty of room above/below — switch the whole axis in that case
|
|
3262
|
+
// (and vice versa for `down`/`up` squeezed against a short viewport).
|
|
3263
|
+
const bestVerticalSpace = Math.max(spaceBelow, spaceAbove);
|
|
3264
|
+
const bestHorizontalSpace = Math.max(spaceLeft, spaceRight);
|
|
3265
|
+
if (side === 'down' || side === 'up') {
|
|
3266
|
+
if (bestVerticalSpace < MIN_USABLE_SPACE && bestHorizontalSpace > bestVerticalSpace) {
|
|
3267
|
+
side = spaceRight >= spaceLeft ? 'end' : 'start';
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
else if (bestHorizontalSpace < menuSize.width + GAP
|
|
3271
|
+
&& bestVerticalSpace > bestHorizontalSpace) {
|
|
3272
|
+
side = spaceBelow >= spaceAbove ? 'down' : 'up';
|
|
3273
|
+
}
|
|
3274
|
+
if (side === 'down' || side === 'up') {
|
|
3275
|
+
const top = side === 'down'
|
|
3276
|
+
? toggleRect.bottom + GAP
|
|
3277
|
+
: toggleRect.top - menuSize.height - GAP;
|
|
3278
|
+
// Align horizontally per the requested `alignment` (start/end/center), then
|
|
3279
|
+
// fall back to the opposite edge if the preferred alignment would overflow
|
|
3280
|
+
// the viewport, and clamp as a final safety net so it never overflows.
|
|
3281
|
+
let left;
|
|
3282
|
+
if (alignment === 'end') {
|
|
3283
|
+
left = toggleRect.right - menuSize.width;
|
|
3284
|
+
}
|
|
3285
|
+
else if (alignment === 'center') {
|
|
3286
|
+
left = toggleRect.left + (toggleRect.width / 2) - (menuSize.width / 2);
|
|
3287
|
+
}
|
|
3288
|
+
else {
|
|
3289
|
+
left = toggleRect.left;
|
|
3290
|
+
}
|
|
3291
|
+
if (left + menuSize.width > viewportWidth - VIEWPORT_PADDING && alignment !== 'end') {
|
|
3292
|
+
const altLeft = toggleRect.right - menuSize.width;
|
|
3293
|
+
if (altLeft >= VIEWPORT_PADDING)
|
|
3294
|
+
left = altLeft;
|
|
3295
|
+
}
|
|
3296
|
+
else if (left < VIEWPORT_PADDING && alignment !== 'start') {
|
|
3297
|
+
const altLeft = toggleRect.left;
|
|
3298
|
+
if (altLeft + menuSize.width <= viewportWidth - VIEWPORT_PADDING)
|
|
3299
|
+
left = altLeft;
|
|
3300
|
+
}
|
|
3301
|
+
left = clamp(left, VIEWPORT_PADDING, Math.max(viewportWidth - menuSize.width - VIEWPORT_PADDING, VIEWPORT_PADDING));
|
|
3302
|
+
const availableHeight = side === 'down' ? spaceBelow : spaceAbove;
|
|
3303
|
+
// Cap strictly to the space actually available on the resolved side —
|
|
3304
|
+
// MIN_USABLE_SPACE is only meant to influence the flip/shift decision
|
|
3305
|
+
// above, not to force a taller box than what physically fits and
|
|
3306
|
+
// overflow the viewport.
|
|
3307
|
+
const maxUsableHeight = Math.max(availableHeight - GAP - VIEWPORT_PADDING, 0);
|
|
3308
|
+
return {
|
|
3309
|
+
top,
|
|
3310
|
+
left,
|
|
3311
|
+
minWidth: Math.max(toggleRect.width, 160),
|
|
3312
|
+
maxHeight: `${maxUsableHeight}px`,
|
|
3313
|
+
resolvedSide: side,
|
|
3314
|
+
};
|
|
3315
|
+
}
|
|
3316
|
+
// side is 'start' or 'end'
|
|
3317
|
+
let left = side === 'start'
|
|
3318
|
+
? toggleRect.left - menuSize.width - GAP
|
|
3319
|
+
: toggleRect.right + GAP;
|
|
3320
|
+
// Safety-net clamp: in rare cases where the toggle is squeezed so tightly
|
|
3321
|
+
// that no side of any axis has enough room, keep the menu inside the
|
|
3322
|
+
// viewport rather than letting it render off-screen.
|
|
3323
|
+
left = clamp(left, VIEWPORT_PADDING, Math.max(viewportWidth - menuSize.width - VIEWPORT_PADDING, VIEWPORT_PADDING));
|
|
3324
|
+
// Shift vertically: align with the toggle's top edge by default, but switch
|
|
3325
|
+
// to the bottom edge (or clamp) if that would overflow the viewport.
|
|
3326
|
+
let { top } = toggleRect;
|
|
3327
|
+
if (top + menuSize.height > viewportHeight - VIEWPORT_PADDING) {
|
|
3328
|
+
top = toggleRect.bottom - menuSize.height;
|
|
3329
|
+
}
|
|
3330
|
+
top = clamp(top, VIEWPORT_PADDING, Math.max(viewportHeight - menuSize.height - VIEWPORT_PADDING, VIEWPORT_PADDING));
|
|
3331
|
+
return {
|
|
3332
|
+
top,
|
|
3333
|
+
left,
|
|
3334
|
+
minWidth: Math.max(toggleRect.width, 160),
|
|
3335
|
+
maxHeight: `${Math.max(viewportHeight - top - VIEWPORT_PADDING, 0)}px`,
|
|
3336
|
+
resolvedSide: side,
|
|
3337
|
+
};
|
|
3338
|
+
};
|
|
3339
|
+
function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal = false, placement = 'auto', alignment = 'start', }) {
|
|
2869
3340
|
const [open, setOpen] = React.useState(false);
|
|
2870
|
-
const [
|
|
2871
|
-
|
|
2872
|
-
//
|
|
2873
|
-
|
|
2874
|
-
//
|
|
3341
|
+
const [coords, setCoords] = React.useState(null);
|
|
3342
|
+
// Initialize from `placement` (falling back to 'down' for 'auto') so the
|
|
3343
|
+
// wrapper's `drop-*` class reflects the requested side even before the
|
|
3344
|
+
// first open/measurement, matching the previous `drop-${placement}` class
|
|
3345
|
+
// behavior (relevant for Bootstrap caret/orientation styling).
|
|
3346
|
+
const [resolvedSide, setResolvedSide] = React.useState(placement === 'auto' ? 'down' : placement);
|
|
3347
|
+
// Wraps the toggle in both modes — used to read its viewport-relative rect.
|
|
2875
3348
|
const toggleRef = React.useRef(null);
|
|
2876
|
-
// Ref on the rendered <ul> — used for outside-click detection
|
|
3349
|
+
// Ref on the rendered <ul> — used to measure its size and for outside-click detection.
|
|
2877
3350
|
const menuRef = React.useRef(null);
|
|
2878
3351
|
const toggle = () => {
|
|
2879
|
-
|
|
3352
|
+
setCoords(null);
|
|
2880
3353
|
setOpen((prev) => !prev);
|
|
2881
3354
|
};
|
|
2882
|
-
|
|
2883
|
-
//
|
|
2884
|
-
const
|
|
2885
|
-
if (!toggleRef.current)
|
|
3355
|
+
// Measures the toggle + menu and (re)computes fixed, pixel-perfect coords
|
|
3356
|
+
// with collision detection, so the menu never overflows the viewport.
|
|
3357
|
+
const updatePosition = React.useCallback(() => {
|
|
3358
|
+
if (!toggleRef.current || !menuRef.current)
|
|
3359
|
+
return;
|
|
3360
|
+
const toggleRect = toggleRef.current.getBoundingClientRect();
|
|
3361
|
+
// If the toggle itself has scrolled completely out of the viewport
|
|
3362
|
+
// (regardless of `placement`), close the menu instead of leaving it
|
|
3363
|
+
// rendered detached from the toggle that opened it.
|
|
3364
|
+
const toggleIsMeasured = toggleRect.width > 0 || toggleRect.height > 0;
|
|
3365
|
+
const toggleIsOutOfView = toggleRect.bottom <= 0
|
|
3366
|
+
|| toggleRect.top >= window.innerHeight
|
|
3367
|
+
|| toggleRect.right <= 0
|
|
3368
|
+
|| toggleRect.left >= window.innerWidth;
|
|
3369
|
+
if (toggleIsMeasured && toggleIsOutOfView) {
|
|
3370
|
+
setOpen(false);
|
|
2886
3371
|
return;
|
|
2887
|
-
const rect = toggleRef.current.getBoundingClientRect();
|
|
2888
|
-
const spaceRight = window.innerWidth - rect.right;
|
|
2889
|
-
const spaceBottom = window.innerHeight - rect.bottom;
|
|
2890
|
-
const spaceTop = rect.top;
|
|
2891
|
-
let resolvedPlacement;
|
|
2892
|
-
if (placement === 'auto') {
|
|
2893
|
-
if (spaceBottom < 150) {
|
|
2894
|
-
resolvedPlacement = 'up';
|
|
2895
|
-
}
|
|
2896
|
-
else if (spaceRight < 150) {
|
|
2897
|
-
resolvedPlacement = 'start';
|
|
2898
|
-
}
|
|
2899
|
-
else {
|
|
2900
|
-
resolvedPlacement = 'down';
|
|
2901
|
-
}
|
|
2902
|
-
}
|
|
2903
|
-
else {
|
|
2904
|
-
resolvedPlacement = placement;
|
|
2905
|
-
}
|
|
2906
|
-
const openStart = resolvedPlacement === 'start';
|
|
2907
|
-
const openEnd = resolvedPlacement === 'end';
|
|
2908
|
-
const openUp = resolvedPlacement === 'up';
|
|
2909
|
-
let availableHeight = spaceBottom;
|
|
2910
|
-
if (openUp) {
|
|
2911
|
-
availableHeight = spaceTop;
|
|
2912
|
-
}
|
|
2913
|
-
else if (openStart || openEnd) {
|
|
2914
|
-
availableHeight = window.innerHeight - rect.top;
|
|
2915
|
-
}
|
|
2916
|
-
const verticalCoords = openUp
|
|
2917
|
-
? { bottom: window.innerHeight - rect.top + 4 }
|
|
2918
|
-
: { top: openStart || openEnd ? rect.top : rect.bottom + 4 };
|
|
2919
|
-
let horizontalCoords;
|
|
2920
|
-
if (openStart) {
|
|
2921
|
-
horizontalCoords = { right: window.innerWidth - rect.left + 4 };
|
|
2922
|
-
}
|
|
2923
|
-
else if (openEnd) {
|
|
2924
|
-
horizontalCoords = { left: rect.right + 4 };
|
|
2925
|
-
}
|
|
2926
|
-
else {
|
|
2927
|
-
horizontalCoords = { left: rect.left };
|
|
2928
3372
|
}
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
const
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
};
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
React.
|
|
2945
|
-
if (
|
|
3373
|
+
const menuRect = menuRef.current.getBoundingClientRect();
|
|
3374
|
+
const _a = computeCoords(toggleRect, { width: menuRect.width, height: menuRect.height }, placement, alignment), { resolvedSide: side } = _a, menuCoords = tslib.__rest(_a, ["resolvedSide"]);
|
|
3375
|
+
// In portal mode the menu is appended to document.body, whose containing
|
|
3376
|
+
// block for `fixed` is always the viewport (no adjustment needed). In
|
|
3377
|
+
// inline mode the menu stays next to the toggle, so we must look for a
|
|
3378
|
+
// containing-block-establishing ancestor starting from the toggle.
|
|
3379
|
+
const offset = asPortal
|
|
3380
|
+
? { top: 0, left: 0 }
|
|
3381
|
+
: getFixedPositioningOffset(toggleRef.current);
|
|
3382
|
+
setResolvedSide(side);
|
|
3383
|
+
setCoords(Object.assign(Object.assign({}, menuCoords), { top: menuCoords.top - offset.top, left: menuCoords.left - offset.left }));
|
|
3384
|
+
}, [placement, alignment, asPortal]);
|
|
3385
|
+
// Throttles scroll/resize-triggered updates to at most once per frame,
|
|
3386
|
+
// avoiding repeated forced reflows on busy/high-frequency scroll events.
|
|
3387
|
+
const rafIdRef = React.useRef(null);
|
|
3388
|
+
const scheduleUpdatePosition = React.useCallback(() => {
|
|
3389
|
+
if (rafIdRef.current !== null)
|
|
3390
|
+
return;
|
|
3391
|
+
rafIdRef.current = window.requestAnimationFrame(() => {
|
|
3392
|
+
rafIdRef.current = null;
|
|
3393
|
+
updatePosition();
|
|
3394
|
+
});
|
|
3395
|
+
}, [updatePosition]);
|
|
3396
|
+
// Outside-click detection (checks both the toggle and the floating menu,
|
|
3397
|
+
// since in portal mode the menu isn't a DOM descendant of the toggle).
|
|
3398
|
+
React.useLayoutEffect(() => {
|
|
3399
|
+
if (!open)
|
|
2946
3400
|
return () => { };
|
|
2947
3401
|
const handler = (event) => {
|
|
2948
3402
|
var _a, _b;
|
|
@@ -2953,35 +3407,25 @@ function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal
|
|
|
2953
3407
|
};
|
|
2954
3408
|
document.addEventListener('mousedown', handler);
|
|
2955
3409
|
return () => document.removeEventListener('mousedown', handler);
|
|
2956
|
-
}, [
|
|
2957
|
-
//
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
const spaceBottom = window.innerHeight - rect.bottom;
|
|
2963
|
-
const spaceRight = window.innerWidth - rect.right;
|
|
2964
|
-
if (spaceBottom < 150)
|
|
2965
|
-
setPosition('up');
|
|
2966
|
-
else if (spaceRight < 150)
|
|
2967
|
-
setPosition('start');
|
|
2968
|
-
else
|
|
2969
|
-
setPosition('down');
|
|
2970
|
-
}, [asPortal, open, placement]);
|
|
2971
|
-
// Compute + track coords: portal mode
|
|
2972
|
-
// Re-runs whenever the menu opens and keeps coords fresh on scroll/resize
|
|
2973
|
-
React.useEffect(() => {
|
|
2974
|
-
if (!asPortal || !open)
|
|
3410
|
+
}, [open]);
|
|
3411
|
+
// Computes the initial position synchronously (before paint, to avoid a
|
|
3412
|
+
// flicker) and keeps it fresh while the menu is open and the viewport
|
|
3413
|
+
// scrolls or resizes (throttled to one update per frame, see above).
|
|
3414
|
+
React.useLayoutEffect(() => {
|
|
3415
|
+
if (!open)
|
|
2975
3416
|
return () => { };
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
window.addEventListener('
|
|
2979
|
-
window.addEventListener('resize', update, { passive: true });
|
|
3417
|
+
updatePosition();
|
|
3418
|
+
window.addEventListener('scroll', scheduleUpdatePosition, { passive: true, capture: true });
|
|
3419
|
+
window.addEventListener('resize', scheduleUpdatePosition, { passive: true });
|
|
2980
3420
|
return () => {
|
|
2981
|
-
window.removeEventListener('scroll',
|
|
2982
|
-
window.removeEventListener('resize',
|
|
3421
|
+
window.removeEventListener('scroll', scheduleUpdatePosition, { capture: true });
|
|
3422
|
+
window.removeEventListener('resize', scheduleUpdatePosition);
|
|
3423
|
+
if (rafIdRef.current !== null) {
|
|
3424
|
+
window.cancelAnimationFrame(rafIdRef.current);
|
|
3425
|
+
rafIdRef.current = null;
|
|
3426
|
+
}
|
|
2983
3427
|
};
|
|
2984
|
-
}, [
|
|
3428
|
+
}, [open, updatePosition, scheduleUpdatePosition]);
|
|
2985
3429
|
let ToggleElement;
|
|
2986
3430
|
if (dropdownToggle) {
|
|
2987
3431
|
ToggleElement = typeof dropdownToggle === 'function'
|
|
@@ -2991,57 +3435,30 @@ function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal
|
|
|
2991
3435
|
else {
|
|
2992
3436
|
ToggleElement = (jsxRuntime.jsx(DButtonIcon, { variant: "link", stopPropagationEnabled: false, "aria-label": "Toggle Dropdown", "aria-haspopup": "menu", "aria-expanded": open, onClick: toggle, icon: "MoreVertical" }));
|
|
2993
3437
|
}
|
|
2994
|
-
|
|
3438
|
+
// Until the first measurement is available, keep the menu off-screen but
|
|
3439
|
+
// measurable (visibility: hidden preserves layout, unlike display: none).
|
|
3440
|
+
const menuStyle = coords
|
|
2995
3441
|
? {
|
|
2996
3442
|
position: 'fixed',
|
|
2997
|
-
top:
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
minWidth: menuCoords.minWidth,
|
|
3002
|
-
maxHeight: menuCoords.maxHeight,
|
|
3443
|
+
top: coords.top,
|
|
3444
|
+
left: coords.left,
|
|
3445
|
+
minWidth: coords.minWidth,
|
|
3446
|
+
maxHeight: coords.maxHeight,
|
|
3003
3447
|
overflowY: 'auto',
|
|
3004
3448
|
zIndex: 1050,
|
|
3005
3449
|
transform: 'none',
|
|
3450
|
+
visibility: 'visible',
|
|
3006
3451
|
}
|
|
3007
|
-
:
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
inlineLeft = 'auto';
|
|
3018
|
-
}
|
|
3019
|
-
else if (resolvedInlinePosition === 'end') {
|
|
3020
|
-
inlineLeft = '100%';
|
|
3021
|
-
}
|
|
3022
|
-
let inlineRight = 'auto';
|
|
3023
|
-
if (resolvedInlinePosition === 'start') {
|
|
3024
|
-
inlineRight = '100%';
|
|
3025
|
-
}
|
|
3026
|
-
let inlineTransform = 'translateY(4px)';
|
|
3027
|
-
if (resolvedInlinePosition === 'up') {
|
|
3028
|
-
inlineTransform = 'translateY(-4px)';
|
|
3029
|
-
}
|
|
3030
|
-
else if (resolvedInlinePosition === 'start') {
|
|
3031
|
-
inlineTransform = 'translateX(-4px)';
|
|
3032
|
-
}
|
|
3033
|
-
else if (resolvedInlinePosition === 'end') {
|
|
3034
|
-
inlineTransform = 'translateX(4px)';
|
|
3035
|
-
}
|
|
3036
|
-
const inlineMenuStyle = {
|
|
3037
|
-
position: 'absolute',
|
|
3038
|
-
top: inlineTop,
|
|
3039
|
-
bottom: resolvedInlinePosition === 'up' ? '100%' : 'auto',
|
|
3040
|
-
left: inlineLeft,
|
|
3041
|
-
right: inlineRight,
|
|
3042
|
-
transform: inlineTransform,
|
|
3043
|
-
};
|
|
3044
|
-
const menuItems = (jsxRuntime.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) => {
|
|
3452
|
+
: {
|
|
3453
|
+
position: 'fixed',
|
|
3454
|
+
top: 0,
|
|
3455
|
+
left: 0,
|
|
3456
|
+
visibility: 'hidden',
|
|
3457
|
+
pointerEvents: 'none',
|
|
3458
|
+
zIndex: 1050,
|
|
3459
|
+
transform: 'none',
|
|
3460
|
+
};
|
|
3461
|
+
const menuItems = (jsxRuntime.jsx("ul", { ref: menuRef, role: "menu", className: classNames('dropdown-menu p-2', { show: open }, classNameMenu), style: menuStyle, children: actions.map((action, index) => {
|
|
3045
3462
|
if (action.isDivider) {
|
|
3046
3463
|
return jsxRuntime.jsx("hr", { className: "dropdown-divider" }, index);
|
|
3047
3464
|
}
|
|
@@ -3060,10 +3477,7 @@ function DDropdown({ actions, dropdownToggle, className, classNameMenu, asPortal
|
|
|
3060
3477
|
}
|
|
3061
3478
|
}, disabled: action.disabled, children: [action.icon && jsxRuntime.jsx(DIcon, { icon: action.icon, className: "me-2", size: "1rem" }), action.label] })) }, index));
|
|
3062
3479
|
}) }));
|
|
3063
|
-
|
|
3064
|
-
return (jsxRuntime.jsxs("div", { ref: toggleRef, className: classNames('dropdown', className), children: [ToggleElement, open && menuCoords && reactDom.createPortal(menuItems, document.body)] }));
|
|
3065
|
-
}
|
|
3066
|
-
return (jsxRuntime.jsxs("div", { className: classNames(`dropdown drop-${resolvedInlinePosition}`, className), ref: dropdownRef, children: [ToggleElement, menuItems] }));
|
|
3480
|
+
return (jsxRuntime.jsxs("div", { ref: toggleRef, className: classNames(`dropdown drop-${resolvedSide} d-inline-block`, className), children: [ToggleElement, open && (asPortal ? reactDom.createPortal(menuItems, document.body) : menuItems)] }));
|
|
3067
3481
|
}
|
|
3068
3482
|
|
|
3069
3483
|
function useScreenshot() {
|
|
@@ -3093,13 +3507,18 @@ function useScreenshot() {
|
|
|
3093
3507
|
|
|
3094
3508
|
function useScreenshotDownload() {
|
|
3095
3509
|
const { clipRef, takeBlob } = useScreenshot();
|
|
3096
|
-
const download = React.useCallback(async () => {
|
|
3097
|
-
const blob = await takeBlob();
|
|
3510
|
+
const download = React.useCallback(async (fileName = 'voucher') => {
|
|
3511
|
+
const blob = await takeBlob('image/jpeg');
|
|
3098
3512
|
const url = window.URL.createObjectURL(blob);
|
|
3099
3513
|
const link = window.document.createElement('a');
|
|
3100
3514
|
link.style.display = 'none';
|
|
3101
3515
|
link.href = url;
|
|
3102
|
-
|
|
3516
|
+
// Fall back to the default base name when the caller passes a blank/whitespace value,
|
|
3517
|
+
// so the file is never named just ".jpg".
|
|
3518
|
+
const safeFileName = fileName.trim() || 'voucher';
|
|
3519
|
+
// The extension is always appended by the hook to guarantee a valid image file,
|
|
3520
|
+
// regardless of what fileName the caller passes (e.g. "receipt.png" -> "receipt.png.jpg").
|
|
3521
|
+
link.download = `${safeFileName}.jpg`;
|
|
3103
3522
|
document.body.appendChild(link);
|
|
3104
3523
|
link.click();
|
|
3105
3524
|
document.body.removeChild(link);
|
|
@@ -3113,11 +3532,15 @@ function useScreenshotDownload() {
|
|
|
3113
3532
|
|
|
3114
3533
|
function useScreenshotWebShare() {
|
|
3115
3534
|
const { takeBlob, clipRef } = useScreenshot();
|
|
3116
|
-
const share = React.useCallback(async () => {
|
|
3117
|
-
const blob = await takeBlob();
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3535
|
+
const share = React.useCallback(async (fileName = 'voucher') => {
|
|
3536
|
+
const blob = await takeBlob('image/jpeg');
|
|
3537
|
+
// Fall back to the default base name when the caller passes a blank/whitespace value,
|
|
3538
|
+
// so the file is never named just ".jpeg".
|
|
3539
|
+
const safeFileName = fileName.trim() || 'voucher';
|
|
3540
|
+
// The extension is always appended by the hook to guarantee a valid image file,
|
|
3541
|
+
// regardless of what fileName the caller passes (e.g. "receipt.png" -> "receipt.png.jpeg").
|
|
3542
|
+
const image = new File([blob], `${safeFileName}.jpeg`, { type: 'image/jpeg' });
|
|
3543
|
+
if (!navigator.canShare || !navigator.canShare({ files: [image] })) {
|
|
3121
3544
|
window.print();
|
|
3122
3545
|
return;
|
|
3123
3546
|
}
|
|
@@ -3129,11 +3552,11 @@ function useScreenshotWebShare() {
|
|
|
3129
3552
|
};
|
|
3130
3553
|
}
|
|
3131
3554
|
|
|
3132
|
-
function DVoucher({ amount, amountDetails, icon, title, onError, message, downloadText = 'Download', shareText = 'Share', className, children, }) {
|
|
3555
|
+
function DVoucher({ amount, amountDetails, icon, title, onError, message, downloadText = 'Download', shareText = 'Share', fileName = 'voucher', hideActions = false, className, children, }) {
|
|
3133
3556
|
const { shareRef, share } = useScreenshotWebShare();
|
|
3134
3557
|
const { downloadRef, download } = useScreenshotDownload();
|
|
3135
3558
|
const handleShare = () => {
|
|
3136
|
-
share()
|
|
3559
|
+
share(fileName)
|
|
3137
3560
|
.catch(async (err) => {
|
|
3138
3561
|
if (onError) {
|
|
3139
3562
|
await onError(err);
|
|
@@ -3144,7 +3567,7 @@ function DVoucher({ amount, amountDetails, icon, title, onError, message, downlo
|
|
|
3144
3567
|
});
|
|
3145
3568
|
};
|
|
3146
3569
|
const handleDownload = () => {
|
|
3147
|
-
download()
|
|
3570
|
+
download(fileName)
|
|
3148
3571
|
.catch(async (err) => {
|
|
3149
3572
|
if (onError) {
|
|
3150
3573
|
await onError(err);
|
|
@@ -3172,80 +3595,36 @@ function DVoucher({ amount, amountDetails, icon, title, onError, message, downlo
|
|
|
3172
3595
|
return (jsxRuntime.jsx("div", { className: classNames('d-voucher', className), ref: (el) => {
|
|
3173
3596
|
shareRef.current = el;
|
|
3174
3597
|
downloadRef.current = el;
|
|
3175
|
-
}, children: jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "d-voucher-header", children: [resolvedIconProps && (jsxRuntime.jsx(DIcon, Object.assign({}, resolvedIconProps))), jsxRuntime.jsxs("div", { className: "
|
|
3176
|
-
}
|
|
3177
|
-
|
|
3178
|
-
function useCountdown(seconds) {
|
|
3179
|
-
const [secondsLeft, setSecondsLeft] = React.useState(seconds);
|
|
3180
|
-
const [isActive, setIsActive] = React.useState(true);
|
|
3181
|
-
const resetCountdown = React.useCallback((newSeconds = seconds) => {
|
|
3182
|
-
setIsActive(false);
|
|
3183
|
-
setSecondsLeft(newSeconds);
|
|
3184
|
-
}, [seconds]);
|
|
3185
|
-
const restartCountdown = React.useCallback(() => {
|
|
3186
|
-
resetCountdown(seconds);
|
|
3187
|
-
setIsActive(true);
|
|
3188
|
-
}, [resetCountdown, seconds]);
|
|
3189
|
-
React.useEffect(() => {
|
|
3190
|
-
if (!isActive) {
|
|
3191
|
-
return () => { };
|
|
3192
|
-
}
|
|
3193
|
-
const interval = setInterval(() => {
|
|
3194
|
-
setSecondsLeft((prevSeconds) => {
|
|
3195
|
-
const newSeconds = prevSeconds - 1;
|
|
3196
|
-
if (newSeconds <= 0) {
|
|
3197
|
-
clearInterval(interval);
|
|
3198
|
-
setIsActive(false);
|
|
3199
|
-
return 0;
|
|
3200
|
-
}
|
|
3201
|
-
return newSeconds;
|
|
3202
|
-
});
|
|
3203
|
-
}, 1000);
|
|
3204
|
-
return () => clearInterval(interval);
|
|
3205
|
-
}, [isActive]);
|
|
3206
|
-
return { secondsLeft, restartCountdown };
|
|
3598
|
+
}, children: jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "d-voucher-header", children: [resolvedIconProps && (jsxRuntime.jsx(DIcon, Object.assign({}, resolvedIconProps))), jsxRuntime.jsxs("div", { className: "d-voucher-title-group", children: [jsxRuntime.jsx("h3", { className: "d-voucher-title", children: title }), jsxRuntime.jsx("p", { className: "d-voucher-message", children: message })] })] }), amount && (jsxRuntime.jsxs("div", { className: "d-voucher-amount", children: [jsxRuntime.jsx("div", { className: classNames('d-voucher-amount-value', { 'd-voucher-amount-value-with-details': !!amountDetails }), children: amount }), amountDetails] })), jsxRuntime.jsx("hr", { className: "d-voucher-divider" }), children, !hideActions && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("hr", { className: "my-4" }), jsxRuntime.jsxs("div", { className: "d-voucher-footer", children: [jsxRuntime.jsx(DButton, { onClick: handleShare, iconStart: "Share2", text: shareText, variant: "outline", size: "sm" }), jsxRuntime.jsx(DButton, { onClick: handleDownload, iconStart: "Download", text: downloadText, variant: "outline", size: "sm" })] })] }))] }) }));
|
|
3207
3599
|
}
|
|
3208
3600
|
|
|
3209
3601
|
const defaultMessage = (secs) => (secs > 0
|
|
3210
3602
|
? `Didn't get any code? Resend in: ${secs}s`
|
|
3211
3603
|
: "Didn't get any code?");
|
|
3212
|
-
function OtpCountdown({
|
|
3213
|
-
|
|
3214
|
-
return (jsxRuntime.jsxs("div", { className: "d-flex gap-2 align-items-center", children: [jsxRuntime.jsx("p", { className: "mb-0 flex-1", children: message ? message(secondsLeft) : defaultMessage(secondsLeft) }), jsxRuntime.jsx(DButton, { text: resendText, variant: "link", className: "text-nowrap", disabled: secondsLeft > 0, onClick: restartCountdown })] }));
|
|
3604
|
+
function OtpCountdown({ secondsLeft, restartCountdown, resendText, message, }) {
|
|
3605
|
+
return (jsxRuntime.jsxs("div", { className: "d-otp-countdown", children: [jsxRuntime.jsx("p", { className: "d-otp-countdown-text", children: message ? message(secondsLeft) : defaultMessage(secondsLeft) }), jsxRuntime.jsx(DButton, { text: resendText, variant: "link", className: "text-nowrap", disabled: secondsLeft > 0, onClick: restartCountdown })] }));
|
|
3215
3606
|
}
|
|
3216
3607
|
|
|
3217
3608
|
const TEXT_PROPS = {
|
|
3218
3609
|
resend: 'Resend',
|
|
3219
|
-
resendText: 'Resend
|
|
3610
|
+
resendText: 'Resend',
|
|
3220
3611
|
submit: 'Authorize and continue',
|
|
3221
3612
|
title: 'We will send you a 6-digit code to your associated phone number so you can continue with your request.',
|
|
3613
|
+
invalidCode: 'Invalid code, please try again.',
|
|
3222
3614
|
contact: (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { children: "Problems with your digital token? Contact us" }), ' ', jsxRuntime.jsx("a", { href: "https://www.modyo.com", className: "link-primary text-nowrap", target: "_blank", rel: "noreferrer", children: "Contact us" })] })),
|
|
3223
3615
|
};
|
|
3224
3616
|
function DOtp({ className, action, isLoading, otpSize = 6, texts = TEXT_PROPS, seconds = 15, }) {
|
|
3225
|
-
const
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
if (otp.length < otpSize) {
|
|
3229
|
-
setInvalid(true);
|
|
3230
|
-
return;
|
|
3231
|
-
}
|
|
3232
|
-
setInvalid(false);
|
|
3233
|
-
await action();
|
|
3234
|
-
}, [
|
|
3235
|
-
otp.length,
|
|
3236
|
-
action,
|
|
3237
|
-
otpSize,
|
|
3238
|
-
]);
|
|
3239
|
-
return (jsxRuntime.jsxs("div", { className: className, children: [jsxRuntime.jsx("p", { children: texts.title }), jsxRuntime.jsxs("div", { className: "d-flex flex-column gap-6 pb-4 px-3", children: [jsxRuntime.jsxs("div", { className: "d-flex flex-column gap-6", children: [jsxRuntime.jsx(DInputPin, { className: "modal-otp-pin", characters: otpSize, onChange: (e) => setOtp(e), invalid: invalid && otp.length < otpSize, placeholder: "0" }), jsxRuntime.jsx(OtpCountdown, { seconds: seconds, resendText: texts.resend })] }), jsxRuntime.jsx("hr", { className: "m-0" }), jsxRuntime.jsxs("div", { className: "d-flex flex-column flex-lg-row gap-4 align-items-center", children: [jsxRuntime.jsx(DButton, { text: texts.submit, onClick: () => {
|
|
3240
|
-
handler().catch((err) => {
|
|
3617
|
+
const { setOtp, invalid, submit, isLoading: isSubmitting, secondsLeft, restartCountdown, } = useOtp({ action, otpSize, seconds });
|
|
3618
|
+
return (jsxRuntime.jsxs("div", { className: className, children: [jsxRuntime.jsx("p", { children: texts.title }), jsxRuntime.jsxs("div", { className: "d-otp d-otp-content", children: [jsxRuntime.jsxs("div", { className: "d-otp-fields", children: [jsxRuntime.jsx(DInputPin, { className: "modal-otp-pin", characters: otpSize, onChange: (e) => setOtp(e), invalid: invalid, hint: invalid ? texts.invalidCode : undefined, placeholder: "0" }), jsxRuntime.jsx(OtpCountdown, { secondsLeft: secondsLeft, restartCountdown: restartCountdown, resendText: texts.resendText })] }), jsxRuntime.jsx("hr", { className: "d-otp-divider" }), jsxRuntime.jsxs("div", { className: "d-otp-footer", children: [jsxRuntime.jsx(DButton, { text: texts.submit, onClick: () => {
|
|
3619
|
+
submit().catch((err) => {
|
|
3241
3620
|
// eslint-disable-next-line no-console
|
|
3242
3621
|
console.error('Error in DOtp action:', err);
|
|
3243
3622
|
});
|
|
3244
|
-
}, loading: isLoading }), jsxRuntime.jsx("p", { className: "
|
|
3623
|
+
}, loading: isLoading || isSubmitting }), jsxRuntime.jsx("p", { className: "d-otp-contact", children: texts.contact })] })] })] }));
|
|
3245
3624
|
}
|
|
3246
3625
|
|
|
3247
3626
|
function DefaultErrorBoundary({ resetErrorBoundary }) {
|
|
3248
|
-
return (jsxRuntime.jsx(DAlert, { color: "danger", showClose: false, children: jsxRuntime.jsxs("div", { className: "d-
|
|
3627
|
+
return (jsxRuntime.jsx(DAlert, { color: "danger", showClose: false, children: jsxRuntime.jsxs("div", { className: "d-error-boundary-content", children: [jsxRuntime.jsx("span", { children: "An unexpected error occurred." }), jsxRuntime.jsx(DButton, { color: "secondary", variant: "outline", size: "sm", onClick: resetErrorBoundary, children: "Retry" })] }) }));
|
|
3249
3628
|
}
|
|
3250
3629
|
|
|
3251
3630
|
function DErrorBoundary({ name, fallback, resetKeys, onReset, onError, children, }) {
|
|
@@ -3263,15 +3642,15 @@ function DErrorBoundary({ name, fallback, resetKeys, onReset, onError, children,
|
|
|
3263
3642
|
}
|
|
3264
3643
|
|
|
3265
3644
|
function ErrorState({ message, onRetry, retryMessage = 'Retry', color = 'danger', }) {
|
|
3266
|
-
return (jsxRuntime.jsxs(DAlert, { color: color, className: "d-
|
|
3645
|
+
return (jsxRuntime.jsxs(DAlert, { color: color, className: "d-error-state", children: [jsxRuntime.jsx("div", { className: "d-error-state-content", children: jsxRuntime.jsx("p", { className: "d-error-state-message", children: message !== null && message !== void 0 ? message : 'An unexpected error occurred.' }) }), onRetry && (jsxRuntime.jsx(DButton, { onClick: onRetry, text: retryMessage, variant: "outline", iconStart: "RefreshCw" }))] }));
|
|
3267
3646
|
}
|
|
3268
3647
|
|
|
3269
3648
|
function EmptyState({ message, icon = 'FileText', actionText, onAction, }) {
|
|
3270
|
-
return (jsxRuntime.jsxs("div", { className: "d-
|
|
3649
|
+
return (jsxRuntime.jsxs("div", { className: "d-empty-state", children: [jsxRuntime.jsx(DIcon, { icon: icon, size: "3rem", className: "d-empty-state-icon" }), jsxRuntime.jsx("p", { className: "d-empty-state-message", children: message !== null && message !== void 0 ? message : 'No data available.' }), actionText && onAction && (jsxRuntime.jsx(DButton, { onClick: onAction, text: actionText, variant: "outline" }))] }));
|
|
3271
3650
|
}
|
|
3272
3651
|
|
|
3273
3652
|
function LoadingState({ ariaLabel = 'Loading...', className }) {
|
|
3274
|
-
return (jsxRuntime.jsx("div", { className: `d-
|
|
3653
|
+
return (jsxRuntime.jsx("div", { className: `d-loading-state ${className || ''}`.trim(), "aria-busy": "true", "aria-live": "polite", children: jsxRuntime.jsx("span", { className: "spinner-border", role: "status", "aria-label": ariaLabel }) }));
|
|
3275
3654
|
}
|
|
3276
3655
|
|
|
3277
3656
|
function render(renderable) {
|
|
@@ -3330,7 +3709,7 @@ function DConfirmModalUI({ entry }) {
|
|
|
3330
3709
|
}
|
|
3331
3710
|
});
|
|
3332
3711
|
}, [onConfirmAction]);
|
|
3333
|
-
return (jsxRuntime.jsxs(DModal, { name: entry.id, size: "lg", className: `confirm-modal ${critical ? 'critical-modal' : ''}`, children: [jsxRuntime.jsx(DModal.Header, { onClose: handleClose, showCloseButton: true, children: jsxRuntime.jsx("h5", { className: "fw-bold", children: title }) }), jsxRuntime.jsxs(DModal.Body, { className: "
|
|
3712
|
+
return (jsxRuntime.jsxs(DModal, { name: entry.id, size: "lg", className: `confirm-modal ${critical ? 'critical-modal' : ''}`, children: [jsxRuntime.jsx(DModal.Header, { onClose: handleClose, showCloseButton: true, children: jsxRuntime.jsx("h5", { className: "fw-bold", children: title }) }), jsxRuntime.jsxs(DModal.Body, { className: "d-confirm-modal-body", children: [jsxRuntime.jsx("p", { className: "d-confirm-modal-message", children: message }), critical && (jsxRuntime.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 }))] }), jsxRuntime.jsxs(DModal.Footer, { children: [jsxRuntime.jsx(DButton, { text: cancelLabel, variant: "outline", color: "secondary", onClick: handleClose, disabled: internalLoading }), jsxRuntime.jsx(DButton, { text: confirmLabel, color: confirmColor, onClick: handleConfirmClick, disabled: isConfirmDisabled, loading: internalLoading })] })] }));
|
|
3334
3713
|
}
|
|
3335
3714
|
|
|
3336
3715
|
/**
|
|
@@ -3460,14 +3839,17 @@ exports.DVoucher = DVoucher;
|
|
|
3460
3839
|
exports.EmptyState = EmptyState;
|
|
3461
3840
|
exports.ErrorState = ErrorState;
|
|
3462
3841
|
exports.LoadingState = LoadingState;
|
|
3842
|
+
exports.buildUrl = buildUrl;
|
|
3463
3843
|
exports.changeQueryString = changeQueryString;
|
|
3464
3844
|
exports.checkMediaQuery = checkMediaQuery;
|
|
3465
3845
|
exports.configureI18n = configureI8n;
|
|
3466
3846
|
exports.formatCurrency = formatCurrency;
|
|
3467
3847
|
exports.getCssVariable = getCssVariable;
|
|
3468
3848
|
exports.getQueryString = getQueryString;
|
|
3849
|
+
exports.sanitizeHref = sanitizeHref;
|
|
3469
3850
|
exports.subscribeToMediaQuery = subscribeToMediaQuery;
|
|
3470
3851
|
exports.useConfirmModal = useConfirmModal;
|
|
3852
|
+
exports.useCountdown = useCountdown;
|
|
3471
3853
|
exports.useDContext = useDContext;
|
|
3472
3854
|
exports.useDPortalContext = useDPortalContext;
|
|
3473
3855
|
exports.useDToast = useDToast;
|
|
@@ -3483,7 +3865,11 @@ exports.useMediaBreakpointUpXl = useMediaBreakpointUpXl;
|
|
|
3483
3865
|
exports.useMediaBreakpointUpXs = useMediaBreakpointUpXs;
|
|
3484
3866
|
exports.useMediaBreakpointUpXxl = useMediaBreakpointUpXxl;
|
|
3485
3867
|
exports.useMediaQuery = useMediaQuery;
|
|
3868
|
+
exports.useOtp = useOtp;
|
|
3486
3869
|
exports.useProvidedRefOrCreate = useProvidedRefOrCreate;
|
|
3870
|
+
exports.useScreenshot = useScreenshot;
|
|
3871
|
+
exports.useScreenshotDownload = useScreenshotDownload;
|
|
3872
|
+
exports.useScreenshotWebShare = useScreenshotWebShare;
|
|
3487
3873
|
exports.useStackState = useStackState;
|
|
3488
3874
|
exports.useTabContext = useTabContext;
|
|
3489
3875
|
exports.validatePhoneNumber = validatePhoneNumber;
|