UNPKG

@craftercms/studio-ui

Version:

Services, components, models & utils to build CrafterCMS authoring extensions.

150 lines (148 loc) 5.89 kB
/* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import React, { useEffect, useState } from 'react'; import { FormattedMessage } from 'react-intl'; import InputAdornment from '@mui/material/InputAdornment'; import FormHelperText from '@mui/material/FormHelperText'; import FormControl from '@mui/material/FormControl'; import TextField from '@mui/material/TextField'; import { UNDEFINED } from '../../utils/constants'; import { checkPathExistence } from '../../services/content'; import { takeUntil } from 'rxjs/operators'; import useUnmount$ from '../../hooks/useUnmount$'; import useActiveSiteId from '../../hooks/useActiveSiteId'; import CircularProgress from '@mui/material/CircularProgress'; import { CheckRounded, ErrorRounded } from '@mui/icons-material'; import { withoutFile, withoutIndex } from '../../utils/path'; import useUpdateRefs from '../../hooks/useUpdateRefs'; export function PathSelectionInput(props) { const { rootPath = '', currentPath = '', allowFiles = false, onChange: onChangeProp, startAdornment } = props; const unmount$ = useUnmount$(); const site = useActiveSiteId(); const [path, setPath] = useState(''); const [pathExists, setPathExists] = useState(null); // null = unchecked const [isChecking, setIsChecking] = useState(false); const getFullPath = () => `${rootPath}${path}`.trim(); const check = () => { setIsChecking(true); let value = getFullPath(); if (!allowFiles) { value = withoutFile(value); } value = value.replace(/\/$/, ''); setPath(value.substr(rootPath.length)); checkPathExistence(site, value) .pipe(takeUntil(unmount$)) .subscribe({ next(exists) { var _a, _b; setIsChecking(false); setPathExists(exists); exists && ((_b = (_a = refs.current).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, value)); }, error() { setIsChecking(false); setPathExists(false); } }); }; const onKeyPress = (event) => { if (event.key === 'Enter') { check(); } }; const onChange = (event) => { setPath(event.target.value); setPathExists(null); }; const refs = useUpdateRefs({ rootPath, onChange: onChangeProp, getFullPath }); useEffect(() => { const newPath = withoutIndex(currentPath.startsWith(rootPath) ? currentPath.substr(rootPath.length) : currentPath); if (`${rootPath}${newPath}` !== refs.current.getFullPath()) { setPathExists(null); setIsChecking(false); setPath(newPath); } }, [refs, rootPath, currentPath]); return React.createElement( FormControl, { sx: { mb: 1 } }, React.createElement(TextField, { fullWidth: true, value: path, onKeyPress: onKeyPress, onChange: onChange, error: pathExists === false, 'aria-describedby': 'pathInputTextField', label: React.createElement(FormattedMessage, { id: 'words.path', defaultMessage: 'Path' }), InputProps: { startAdornment: rootPath ? React.createElement(InputAdornment, { position: 'start', sx: { mr: 0 } }, startAdornment, rootPath) : UNDEFINED, endAdornment: isChecking ? React.createElement( InputAdornment, { position: 'end', sx: { width: 20, height: 20 } }, React.createElement(CircularProgress, { variant: 'indeterminate', size: 20 }) ) : pathExists === true ? React.createElement( InputAdornment, { position: 'end' }, React.createElement(CheckRounded, { color: 'success' }) ) : pathExists === false ? React.createElement( InputAdornment, { position: 'end' }, React.createElement(ErrorRounded, { color: 'error' }) ) : UNDEFINED } }), React.createElement( FormHelperText, { id: 'pathInputTextFieldHelper', error: pathExists === false }, pathExists ? React.createElement(FormattedMessage, { id: 'pathSelectionInput.found', defaultMessage: 'Path found' }) : pathExists === false ? React.createElement(FormattedMessage, { id: 'pathSelectionInput.invalidPath', defaultMessage: "The entered path doesn't exist" }) : React.createElement(FormattedMessage, { id: 'pathSelectionInput.description', defaultMessage: 'Enter a path and press `enter` to validate' }) ) ); } export default PathSelectionInput;