UNPKG

@carbon/ibm-products

Version:
255 lines (253 loc) 9.95 kB
/** * Copyright IBM Corp. 2020, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const require_runtime = require("../../_virtual/_rolldown/runtime.js"); const require_index = require("../../node_modules/classnames/index.js"); const require_settings = require("../../settings.js"); const require_devtools = require("../../global/js/utils/devtools.js"); const require_usePortalTarget = require("../../global/js/hooks/usePortalTarget.js"); const require_uuidv4 = require("../../global/js/utils/uuidv4.js"); let react = require("react"); react = require_runtime.__toESM(react); let prop_types = require("prop-types"); prop_types = require_runtime.__toESM(prop_types); let _carbon_react = require("@carbon/react"); let _carbon_react_icons = require("@carbon/react/icons"); //#region src/components/ExportModal/ExportModal.tsx var import_classnames = /* @__PURE__ */ require_runtime.__toESM(require_index.default); const componentName = "ExportModal"; const defaults = { inputType: "text", preformattedExtensions: Object.freeze([]), validExtensions: Object.freeze([]) }; /** * Modal dialog version of the export pattern */ const ExportModal = (0, react.forwardRef)(({ body, className, error, errorMessage, filename, hidePasswordLabel, inputLabel, inputType = "text", invalidInputText, loading, loadingMessage, onClose, onRequestSubmit, open, portalTarget: portalTargetIn, preformattedExtensions = defaults.preformattedExtensions, preformattedExtensionsLabel, primaryButtonText, secondaryButtonText, showPasswordLabel, successMessage, successful, title, triggerButtonRef, validExtensions = defaults.validExtensions, ...rest }, ref) => { const blockClass = `${require_settings.pkg.prefix}--export-modal`; const [name, setName] = (0, react.useState)(""); const [dirtyInput, setDirtyInput] = (0, react.useState)(false); const [extension, setExtension] = (0, react.useState)(""); const renderPortalUse = require_usePortalTarget.usePortalTarget(portalTargetIn); const carbonPrefix = (0, _carbon_react.usePrefix)(); (0, react.useEffect)(() => { setName(filename); if (preformattedExtensions && preformattedExtensions.length > 0 && preformattedExtensions[0]?.extension) setExtension(preformattedExtensions?.[0]?.extension); }, [ filename, preformattedExtensions, open ]); (0, react.useEffect)(() => { if (successful) document.querySelector(`.${blockClass} .${carbonPrefix}--modal-close-button button`)?.focus(); }, [ successful, blockClass, carbonPrefix ]); const onNameChangeHandler = (evt) => { setName(evt.target.value); }; const onExtensionChangeHandler = (value) => { setExtension(value); }; const onBlurHandler = () => { setDirtyInput(true); }; const onSubmitHandler = () => { const returnName = extension ? `${filename}.${extension.toLocaleLowerCase()}` : name; onRequestSubmit?.(returnName); }; const hasInvalidExtension = () => { if (!dirtyInput || !validExtensions || !validExtensions.length) return false; if (!name.includes(".")) return true; const ext = name.split(".").pop(); if (!validExtensions.includes(ext)) return true; return false; }; const internalId = (0, react.useRef)(require_uuidv4.default()); const primaryButtonDisabled = loading || !name || hasInvalidExtension(); const submitted = loading || error || successful; const commonInputProps = { id: `text-input--${internalId.current}`, value: name, onChange: onNameChangeHandler, labelText: inputLabel, invalid: hasInvalidExtension(), invalidText: invalidInputText, onBlur: onBlurHandler, ["data-modal-primary-focus"]: true }; return renderPortalUse(/* @__PURE__ */ react.default.createElement(_carbon_react.unstable_FeatureFlags, { enableExperimentalFocusWrapWithoutSentinels: true }, /* @__PURE__ */ react.default.createElement(_carbon_react.ComposedModal, { ...rest, className: (0, import_classnames.default)(blockClass, className), "aria-label": title, size: "sm", preventCloseOnClickOutside: true, launcherButtonRef: triggerButtonRef, open, ref, onClose, ...require_devtools.getDevtoolsProps(componentName) }, /* @__PURE__ */ react.default.createElement(_carbon_react.ModalHeader, { className: `${blockClass}__header`, closeModal: onClose, title }), /* @__PURE__ */ react.default.createElement(_carbon_react.ModalBody, { className: `${blockClass}__body-container` }, !submitted && /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, body && /* @__PURE__ */ react.default.createElement("p", { className: `${blockClass}__body` }, body), preformattedExtensions.length ? /* @__PURE__ */ react.default.createElement(_carbon_react.FormGroup, { legendText: preformattedExtensionsLabel }, /* @__PURE__ */ react.default.createElement(_carbon_react.RadioButtonGroup, { orientation: "vertical", onChange: onExtensionChangeHandler, valueSelected: extension, name: "extensions", "aria-label": "extensions" }, preformattedExtensions.map((o) => /* @__PURE__ */ react.default.createElement(_carbon_react.RadioButton, { key: o.extension, id: o.extension, value: o.extension, labelText: `${o.extension} (${o.description})`, "data-modal-primary-focus": true })))) : /* @__PURE__ */ react.default.createElement("div", { className: `${blockClass}__input-container` }, inputType === "text" ? /* @__PURE__ */ react.default.createElement(_carbon_react.TextInput, commonInputProps) : /* @__PURE__ */ react.default.createElement(_carbon_react.PasswordInput, { ...commonInputProps, showPasswordLabel, hidePasswordLabel, tooltipPosition: "left" }))), /* @__PURE__ */ react.default.createElement("div", { "aria-live": "polite", className: `${blockClass}__messaging` }, loading && /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement(_carbon_react.Loading, { "aria-live": "off", description: "", small: true, withOverlay: false }), /* @__PURE__ */ react.default.createElement("p", null, loadingMessage)), successful && /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement(_carbon_react_icons.CheckmarkFilled, { size: 16, className: `${blockClass}__checkmark-icon` }), /* @__PURE__ */ react.default.createElement("p", null, successMessage)), error && /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement(_carbon_react_icons.ErrorFilled, { size: 16, className: `${blockClass}__error-icon` }), /* @__PURE__ */ react.default.createElement("p", null, errorMessage)))), !submitted && /* @__PURE__ */ react.default.createElement(_carbon_react.ModalFooter, { className: `${blockClass}__footer` }, /* @__PURE__ */ react.default.createElement(_carbon_react.Button, { type: "button", kind: "secondary", onClick: onClose }, secondaryButtonText), /* @__PURE__ */ react.default.createElement(_carbon_react.Button, { type: "submit", kind: "primary", onClick: onSubmitHandler, disabled: primaryButtonDisabled }, primaryButtonText))))); }); ExportModal.propTypes = { /** * Body content for the modal */ /**@ts-ignore*/ body: prop_types.default.string, /** * Optional class name */ className: prop_types.default.string, /** * specify if an error occurred */ error: prop_types.default.bool, /** * messaging to display in the event of an error */ errorMessage: prop_types.default.string, /** * name of the file being exported */ filename: prop_types.default.string.isRequired, /** * label text that's displayed when hovering over visibility toggler to hide key */ hidePasswordLabel: prop_types.default.string, /** * label for the text input */ inputLabel: prop_types.default.string, /** * specify the type of text input */ /**@ts-ignore */ inputType: prop_types.default.oneOf(["text", "password"]), /** * text for an invalid input */ invalidInputText: prop_types.default.string, /** * specify if the modal is in a loading state */ loading: prop_types.default.bool, /** * message to display during the loading state */ loadingMessage: prop_types.default.string, /** * Specify a handler for closing modal */ onClose: prop_types.default.func, /** * Specify a handler for "submitting" modal. Returns the file name */ onRequestSubmit: prop_types.default.func, /** * Specify whether the Modal is currently open */ open: prop_types.default.bool, /** * The DOM node the tearsheet should be rendered within. Defaults to document.body. */ portalTarget: prop_types.default.node, /** * Array of extensions to display as radio buttons */ /**@ts-ignore */ preformattedExtensions: prop_types.default.arrayOf(prop_types.default.shape({ extension: prop_types.default.string, description: prop_types.default.string })), /** * Label for the preformatted label form group */ preformattedExtensionsLabel: prop_types.default.string, /** * Specify the text for the primary button */ primaryButtonText: prop_types.default.string.isRequired, /** * Specify the text for the secondary button */ secondaryButtonText: prop_types.default.string.isRequired, /** * label text that's displayed when hovering over visibility toggler to show key */ showPasswordLabel: prop_types.default.string, /** * messaging to display if the export was successful */ successMessage: prop_types.default.string, /** * specify if the export was successful */ successful: prop_types.default.bool, /** * The text displayed at the top of the modal */ title: prop_types.default.string.isRequired, /** * Sets the trigger button ref */ triggerButtonRef: prop_types.default.any, /** * array of valid extensions the file can have */ /**@ts-ignore */ validExtensions: prop_types.default.array }; ExportModal.displayName = componentName; //#endregion exports.ExportModal = ExportModal;