174 lines
4.7 KiB
JavaScript
174 lines
4.7 KiB
JavaScript
// Copyright 2021 99cloud
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
import { Col, Input, Row, Tag, Tooltip } from 'antd';
|
|
import { PlusOutlined } from '@ant-design/icons';
|
|
import { projectTagsColors } from 'src/utils/constants';
|
|
import PropTypes from 'prop-types';
|
|
|
|
const Tags = ({ tags: source, onChange, maxLength, maxCount }) => {
|
|
const [tags, setTags] = useState(source);
|
|
const [inputVisible, setInputVisible] = useState(false);
|
|
const [inputValue, setInputValue] = useState('');
|
|
const [editInputIdx, setEditInputIdx] = useState(-1);
|
|
const [editInputValue, setEditInputValue] = useState('');
|
|
const tagLength = maxLength && maxLength > 0 ? { maxLength } : {};
|
|
const tagCount = (maxCount && maxCount > 0) || -1;
|
|
|
|
function handleClose(removedTag) {
|
|
setTags(tags.filter((tag) => tag !== removedTag));
|
|
}
|
|
|
|
let editInput = null;
|
|
let saveInput = null;
|
|
const saveEditInputRef = (input) => {
|
|
editInput = input;
|
|
};
|
|
|
|
const saveInputRef = (input) => {
|
|
saveInput = input;
|
|
};
|
|
|
|
function handleEditInputChange(e) {
|
|
setEditInputValue(e.target.value);
|
|
}
|
|
|
|
function handleEditInputConfirm() {
|
|
const newTags = [...tags];
|
|
newTags[editInputIdx] = editInputValue;
|
|
setTags(newTags);
|
|
setEditInputValue('');
|
|
setEditInputIdx(-1);
|
|
}
|
|
|
|
function handleInputChange(e) {
|
|
setInputValue(e.target.value);
|
|
}
|
|
|
|
function handleInputConfirm() {
|
|
const retVal = inputValue.toLocaleLowerCase();
|
|
if (inputValue && !tags.some((tag) => tag.toLowerCase() === retVal)) {
|
|
if (tagCount !== -1 && tags.length < maxCount) {
|
|
setTags([...tags, inputValue]);
|
|
} else if (tagCount === -1) {
|
|
setTags([...tags, inputValue]);
|
|
}
|
|
}
|
|
setInputVisible(false);
|
|
setInputValue('');
|
|
}
|
|
|
|
function showInput() {
|
|
setInputVisible(true);
|
|
}
|
|
|
|
useEffect(() => {
|
|
saveInput && saveInput.focus();
|
|
}, [inputVisible]);
|
|
|
|
useEffect(() => {
|
|
editInput && editInput.focus();
|
|
}, [editInputIdx]);
|
|
|
|
useEffect(() => {
|
|
onChange(tags);
|
|
}, [tags]);
|
|
|
|
return (
|
|
<Row gutter={[0, 8]}>
|
|
{tags.map((tag, index) => {
|
|
if (editInputIdx === index) {
|
|
return (
|
|
<Input
|
|
ref={saveEditInputRef}
|
|
style={{ width: 78, marginRight: 8, verticalAlign: 'top' }}
|
|
key={tag}
|
|
size="small"
|
|
value={editInputValue}
|
|
onChange={handleEditInputChange}
|
|
onBlur={handleEditInputConfirm}
|
|
onPressEnter={handleEditInputConfirm}
|
|
{...tagLength}
|
|
/>
|
|
);
|
|
}
|
|
const isLongTag = tag.length > 20;
|
|
const tagText = isLongTag ? `${tag.slice(0, 20)}...` : tag;
|
|
const tagEl = (
|
|
<Tag
|
|
key={tag}
|
|
closable
|
|
onClose={() => handleClose(tag)}
|
|
color={projectTagsColors[index % 10]}
|
|
>
|
|
<span
|
|
style={{ whiteSpace: 'pre-wrap' }}
|
|
onDoubleClick={(e) => {
|
|
setEditInputIdx(index);
|
|
setEditInputValue(tag);
|
|
e.preventDefault();
|
|
}}
|
|
>
|
|
{tagText}
|
|
</span>
|
|
</Tag>
|
|
);
|
|
return (
|
|
<Col span={24} key={tag}>
|
|
{isLongTag ? (
|
|
<Tooltip
|
|
title={<span style={{ whiteSpace: 'pre-wrap' }}>{tag}</span>}
|
|
>
|
|
{tagEl}
|
|
</Tooltip>
|
|
) : (
|
|
tagEl
|
|
)}
|
|
</Col>
|
|
);
|
|
})}
|
|
<Col span={24}>
|
|
{inputVisible && (
|
|
<Input
|
|
ref={saveInputRef}
|
|
style={{ width: 78, marginRight: 8, verticalAlign: 'top' }}
|
|
type="text"
|
|
size="small"
|
|
value={inputValue}
|
|
onChange={handleInputChange}
|
|
onBlur={handleInputConfirm}
|
|
onPressEnter={handleInputConfirm}
|
|
{...tagLength}
|
|
/>
|
|
)}
|
|
{!inputVisible && (
|
|
<Tag onClick={showInput}>
|
|
<PlusOutlined /> New Tag
|
|
</Tag>
|
|
)}
|
|
</Col>
|
|
</Row>
|
|
);
|
|
};
|
|
|
|
Tags.propTypes = {
|
|
tags: PropTypes.array,
|
|
onChange: PropTypes.func,
|
|
maxLength: PropTypes.number,
|
|
maxCount: PropTypes.number,
|
|
};
|
|
|
|
export default Tags;
|