Merge branch 'master' into feature/jenkins-file
This commit is contained in:
commit
cc3a58430f
@ -1,13 +1,11 @@
|
||||
{
|
||||
"InviteLinkTitle": "Invitation link",
|
||||
"HelpAnswerLinkInviteSettings": "Share the link to invite your colleagues to your portal.",
|
||||
"InviteLinkValidInterval": "This link is valid for {{ count }} day only.",
|
||||
"InviteLinkValidInterval": "This link is valid for {{ count }} days only.",
|
||||
"CopyToClipboard": "Copy the link",
|
||||
"CloseButton": "Close",
|
||||
"LinkCopySuccess": "Link has been copied to the clipboard",
|
||||
"GetShortenLink": "Get shortened link",
|
||||
"InviteUsersAsCollaborators": "Add users as {{typeGuests, lowercase}}",
|
||||
"LoadingProcessing": "Loading...",
|
||||
|
||||
"InviteLinkValidInterval_plural": "This link is valid for {{ count }} days only."
|
||||
"LoadingProcessing": "Loading..."
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
{
|
||||
"InviteLinkTitle": "Пригласительная ссылка",
|
||||
"HelpAnswerLinkInviteSettings": "Поделитесь ссылкой, чтобы пригласить коллег на портал.",
|
||||
"InviteLinkValidInterval": "Эта ссылка действительна только в течение {{ count }} дня.",
|
||||
"InviteLinkValidInterval": "Эта ссылка действительна только в течение {{ count }} дней.",
|
||||
"CopyToClipboard": "Копировать ссылку",
|
||||
"CloseButton": "Закрыть",
|
||||
"LinkCopySuccess": "Ссылка скопирована в буфер обмена",
|
||||
"GetShortenLink": "Получить сокращенную ссылку",
|
||||
"InviteUsersAsCollaborators": "Добавить со статусом {{typeGuests, lowercase}}",
|
||||
"LoadingProcessing": "Загрузка...",
|
||||
|
||||
"InviteLinkValidInterval_plural": "Эта ссылка действительна только в течение {{ count }} дней."
|
||||
"LoadingProcessing": "Загрузка..."
|
||||
}
|
@ -248,6 +248,12 @@ class SectionBodyContent extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
onKeyPress = event => {
|
||||
if (event.key === "Enter") {
|
||||
this.onSave();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const {
|
||||
@ -279,6 +285,7 @@ class SectionBodyContent extends React.Component {
|
||||
value={groupName}
|
||||
onChange={this.onGroupChange}
|
||||
isDisabled={inLoading}
|
||||
onKeyUp={this.onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
<FieldContainer
|
||||
@ -292,7 +299,7 @@ class SectionBodyContent extends React.Component {
|
||||
id="head-selector_button"
|
||||
tabIndex={2}
|
||||
options={[]}
|
||||
isOpen={isHeadSelectorOpen}
|
||||
opened={isHeadSelectorOpen}
|
||||
selectedOption={groupManager}
|
||||
scaled={true}
|
||||
isDisabled={inLoading}
|
||||
@ -319,7 +326,7 @@ class SectionBodyContent extends React.Component {
|
||||
id="users-selector_button"
|
||||
tabIndex={3}
|
||||
options={[]}
|
||||
isOpen={isUsersSelectorOpen}
|
||||
opened={isUsersSelectorOpen}
|
||||
isDisabled={inLoading}
|
||||
selectedOption={{
|
||||
key: 0,
|
||||
|
@ -3,7 +3,8 @@ import {
|
||||
Button,
|
||||
IconButton,
|
||||
Text,
|
||||
ToggleContent
|
||||
ToggleContent,
|
||||
Link
|
||||
} from "asc-web-components";
|
||||
import { getUserContacts, getUserRole } from "../../../../../store/people/selectors";
|
||||
|
||||
@ -39,13 +40,6 @@ const EditButtonWrapper = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const ContactTextTruncate = styled.div`
|
||||
padding: 0 8px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
const ToggleWrapper = styled.div`
|
||||
width: 100%;
|
||||
${props => props.isSelf && `margin-bottom: 24px;`}
|
||||
@ -57,14 +51,28 @@ const ContactWrapper = styled.div`
|
||||
display: inline-flex;
|
||||
width: 300px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.contact-link {
|
||||
padding: 0 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
const createContacts = contacts => {
|
||||
const styledContacts = contacts.map((contact, index) => {
|
||||
let url = null;
|
||||
if (contact.link && contact.link.length > 0) {
|
||||
url = stringFormat(contact.link, [contact.value]);
|
||||
}
|
||||
return (
|
||||
<ContactWrapper key={index}>
|
||||
<IconButton color="#333333" size={16} iconName={contact.icon} isFill={true} />
|
||||
<ContactTextTruncate>{contact.value}</ContactTextTruncate>
|
||||
<Link
|
||||
className='contact-link'
|
||||
isTextOverflow
|
||||
href={url}
|
||||
>
|
||||
{contact.value}
|
||||
</Link>
|
||||
</ContactWrapper>
|
||||
);
|
||||
});
|
||||
@ -72,6 +80,8 @@ const createContacts = contacts => {
|
||||
return styledContacts;
|
||||
};
|
||||
|
||||
const stringFormat = (string, data) => string.replace(/\{(\d+)\}/g, (m, n) => data[n] || m);
|
||||
|
||||
class SectionBodyContent extends React.PureComponent {
|
||||
|
||||
onEditSubscriptionsClick = () => console.log("Edit subscriptions onClick()");
|
||||
|
@ -29,7 +29,8 @@ class DepartmentField extends React.Component {
|
||||
|
||||
selectorIsVisible,
|
||||
selectorSelectedOptions,
|
||||
selectorOnSelectGroups
|
||||
selectorOnSelectGroups,
|
||||
searchPlaceHolderLabel
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -50,6 +51,7 @@ class DepartmentField extends React.Component {
|
||||
isMultiSelect={true}
|
||||
onSelect={selectorOnSelectGroups}
|
||||
onCancel={onCloseGroupSelector}
|
||||
searchPlaceHolderLabel={searchPlaceHolderLabel}
|
||||
/>
|
||||
{selectorSelectedOptions.map(option => (
|
||||
<SelectedItem
|
||||
|
@ -471,7 +471,7 @@ class CreateUserForm extends React.Component {
|
||||
onCloseGroupSelector={this.onCloseGroupSelector}
|
||||
onRemoveGroup={this.onRemoveGroup}
|
||||
selectorIsVisible={selector.visible}
|
||||
selectorSearchPlaceholder={t("Search")}
|
||||
searchPlaceHolderLabel={t("SearchDepartments")}
|
||||
selectorOptions={selector.options}
|
||||
selectorSelectedOptions={selector.selected}
|
||||
selectorAddButtonText={t("CustomAddDepartments", { departments })}
|
||||
|
@ -605,7 +605,7 @@ class UpdateUserForm extends React.Component {
|
||||
onCloseGroupSelector={this.onCloseGroupSelector}
|
||||
onRemoveGroup={this.onRemoveGroup}
|
||||
selectorIsVisible={selector.visible}
|
||||
selectorSearchPlaceholder={t("Search")}
|
||||
searchPlaceHolderLabel={t("SearchDepartments")}
|
||||
selectorOptions={selector.options}
|
||||
selectorSelectedOptions={selector.selected}
|
||||
selectorAddButtonText={t("CustomAddDepartments", { departments })}
|
||||
|
@ -16,7 +16,6 @@
|
||||
"ContactInformation": "Contact information",
|
||||
"AddContact": "Add contact",
|
||||
"SocialProfiles": "Social profiles",
|
||||
"Search": "Search",
|
||||
"SelectAll": "Select all",
|
||||
"EmailPopupHelper": "The main e-mail is needed to restore access to the portal in case of loss of the password and send notifications. <1> You can create a new mail on the domain as the primary. In this case, you must set a one-time password so that the user can log in to the portal for the first time.</1> The main e-mail can be used as a login when logging in to the portal.",
|
||||
"ProfileTypePopupHelper": "Guests have limited access to some portal features and modules",
|
||||
@ -41,6 +40,7 @@
|
||||
"Phone": "Phone",
|
||||
"ChangesSavedSuccessfully": "Changes saved successfully",
|
||||
"EditProfile": "Edit profile",
|
||||
"SearchDepartments": "Search departments",
|
||||
|
||||
"CustomEmployedSinceDate": "{{employedSinceDate}}",
|
||||
"CustomPosition": "{{position}}",
|
||||
|
@ -16,7 +16,6 @@
|
||||
"ContactInformation": "Контактные данные",
|
||||
"AddContact": "Добавить новый контакт",
|
||||
"SocialProfiles": "Социальные профили",
|
||||
"Search": "Поиск",
|
||||
"SelectAll": "Выбрать все",
|
||||
"EmailPopupHelper": "Основной email нужен для восстановления доступа к порталу в случае потери пароля, а также для отправки оповещений. <1>Вы можете создать новый email на домене в качестве основного. В этом случае потребуется задать одноразовый пароль, чтобы пользователь смог войти на портал в первый раз.</1> Основной email можно использовать как логин при входе на портал.",
|
||||
"ProfileTypePopupHelper": "Гости имеют ограниченный доступ к некоторым функциям и модулям портала",
|
||||
@ -41,6 +40,7 @@
|
||||
"Phone": "Телефон",
|
||||
"ChangesSavedSuccessfully": "Изменения успешно сохранены",
|
||||
"EditProfile": "Редактирование профиля",
|
||||
"SearchDepartments": "Поиск группы",
|
||||
|
||||
"CustomEmployedSinceDate": "{{employedSinceDate}}",
|
||||
"CustomPosition": "{{position}}",
|
||||
|
@ -50,23 +50,23 @@ export const getUserRole = user => {
|
||||
export const getUserContactsPattern = () => {
|
||||
return {
|
||||
contact: [
|
||||
{ type: "mail", icon: "MailIcon" },
|
||||
{ type: "phone", icon: "PhoneIcon" },
|
||||
{ type: "mobphone", icon: "MobileIcon" },
|
||||
{ type: "gmail", icon: "GmailIcon" },
|
||||
{ type: "skype", icon: "SkypeIcon" },
|
||||
{ type: "mail", icon: "MailIcon", link: 'mailto:{0}' },
|
||||
{ type: "phone", icon: "PhoneIcon", link: 'tel:{0}' },
|
||||
{ type: "mobphone", icon: "MobileIcon", link: 'tel:{0}' },
|
||||
{ type: "gmail", icon: "GmailIcon", link: 'mailto:{0}' },
|
||||
{ type: "skype", icon: "SkypeIcon", link: 'skype:{0}?userinfo' },
|
||||
{ type: "msn", icon: "WindowsMsnIcon" },
|
||||
{ type: "icq", icon: "IcqIcon" },
|
||||
{ type: "icq", icon: "IcqIcon", link: 'https://www.icq.com/people/{0}' },
|
||||
{ type: "jabber", icon: "JabberIcon" },
|
||||
{ type: "aim", icon: "AimIcon" }
|
||||
],
|
||||
social: [
|
||||
{ type: "facebook", icon: "ShareFacebookIcon" },
|
||||
{ type: "livejournal", icon: "LivejournalIcon" },
|
||||
{ type: "myspace", icon: "MyspaceIcon" },
|
||||
{ type: "twitter", icon: "ShareTwitterIcon" },
|
||||
{ type: "blogger", icon: "BloggerIcon" },
|
||||
{ type: "yahoo", icon: "YahooIcon" }
|
||||
{ type: "facebook", icon: "ShareFacebookIcon", link: 'https://facebook.com/{0}' },
|
||||
{ type: "livejournal", icon: "LivejournalIcon", link: 'https://{0}.livejournal.com' },
|
||||
{ type: "myspace", icon: "MyspaceIcon", link: 'https://myspace.com/{0}' },
|
||||
{ type: "twitter", icon: "ShareTwitterIcon", link: 'https://twitter.com/{0}' },
|
||||
{ type: "blogger", icon: "BloggerIcon", link: 'https://{0}.blogspot.com' },
|
||||
{ type: "yahoo", icon: "YahooIcon", link: 'mailto:{0}@yahoo.com' }
|
||||
]
|
||||
};
|
||||
};
|
||||
|
6
web/ASC.Web.Common/.storybook/decorators/redux/index.js
Normal file
6
web/ASC.Web.Common/.storybook/decorators/redux/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
import { Provider } from "react-redux";
|
||||
import store from "./store";
|
||||
|
||||
const withProvider = story => <Provider store={store}>{story()}</Provider>;
|
||||
|
||||
export default withProvider;
|
@ -0,0 +1,8 @@
|
||||
import { combineReducers } from 'redux';
|
||||
import authReducer from "../../../src/store/auth/reducer";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
auth: authReducer
|
||||
});
|
||||
|
||||
export default rootReducer;
|
14
web/ASC.Web.Common/.storybook/decorators/redux/store.js
Normal file
14
web/ASC.Web.Common/.storybook/decorators/redux/store.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { createStore } from 'redux';
|
||||
import rootReducer from './rootReducer';
|
||||
|
||||
const configureStore = prelodedState => (
|
||||
createStore(
|
||||
rootReducer,
|
||||
prelodedState
|
||||
)
|
||||
);
|
||||
/* eslint-enable */
|
||||
|
||||
const store = configureStore({});
|
||||
|
||||
export default store;
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-common",
|
||||
"version": "1.0.34",
|
||||
"version": "1.0.45",
|
||||
"description": "Ascensio System SIA common components and solutions library",
|
||||
"license": "AGPL-3.0",
|
||||
"files": [
|
||||
|
@ -3,7 +3,6 @@ import PropTypes from "prop-types";
|
||||
import Selector from "./sub-components/Selector";
|
||||
import { utils, Backdrop, DropDown, Aside } from "asc-web-components";
|
||||
import throttle from "lodash/throttle";
|
||||
import onClickOutside from "react-onclickoutside";
|
||||
const { desktop } = utils.device;
|
||||
|
||||
const displayTypes = ["dropdown", "aside", "auto"];
|
||||
@ -22,15 +21,8 @@ class AdvancedSelector extends React.Component {
|
||||
this.throttledResize = throttle(this.resize, 300);
|
||||
}
|
||||
|
||||
handleClickOutside = e => {
|
||||
// ..handling code goes here...
|
||||
console.log(`ADSelector#${this.props.id} handleClickOutside`, e);
|
||||
this.onClose(e);
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if(this.props.isOpen) {
|
||||
this.props.enableOnClickOutside();
|
||||
window.addEventListener("resize", this.throttledResize);
|
||||
}
|
||||
}
|
||||
@ -57,12 +49,10 @@ class AdvancedSelector extends React.Component {
|
||||
if(this.props.isOpen !== prevProps.isOpen) {
|
||||
console.log(`ADSelector#${this.props.id} componentDidUpdate isOpen=${this.props.isOpen}`);
|
||||
if(this.props.isOpen) {
|
||||
this.props.enableOnClickOutside();
|
||||
this.resize();
|
||||
window.addEventListener("resize", this.throttledResize);
|
||||
}
|
||||
else {
|
||||
this.props.disableOnClickOutside();
|
||||
this.throttledResize.cancel();
|
||||
window.removeEventListener("resize", this.throttledResize);
|
||||
}
|
||||
@ -80,7 +70,6 @@ class AdvancedSelector extends React.Component {
|
||||
this.throttledResize && this.throttledResize.cancel();
|
||||
window.removeEventListener("resize", this.throttledResize);
|
||||
}
|
||||
this.props.disableOnClickOutside();
|
||||
}
|
||||
|
||||
getTypeByWidth = () => {
|
||||
@ -103,7 +92,7 @@ class AdvancedSelector extends React.Component {
|
||||
<div ref={this.ref} id={id} className={className} style={style}>
|
||||
{displayType === "dropdown"
|
||||
?
|
||||
<DropDown open={isOpen} className="dropdown-container">
|
||||
<DropDown open={isOpen} className="dropdown-container" clickOutsideAction={this.onClose}>
|
||||
<Selector {...this.props} displayType={displayType} />
|
||||
</DropDown>
|
||||
:
|
||||
@ -153,9 +142,7 @@ AdvancedSelector.propTypes = {
|
||||
onGroupChange: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
onAddNewClick: PropTypes.func,
|
||||
loadNextPage: PropTypes.func,
|
||||
enableOnClickOutside: PropTypes.func,
|
||||
disableOnClickOutside: PropTypes.func
|
||||
loadNextPage: PropTypes.func
|
||||
};
|
||||
|
||||
AdvancedSelector.defaultProps = {
|
||||
@ -169,17 +156,4 @@ AdvancedSelector.defaultProps = {
|
||||
options: []
|
||||
};
|
||||
|
||||
const EnhancedComponent = onClickOutside(AdvancedSelector);
|
||||
|
||||
class AdvancedSelectorContainer extends React.Component {
|
||||
render() {
|
||||
console.log(`AdvancedSelectorContainer isOpen=${this.props.isOpen} enableOnClickOutside=${this.props.isOpen}`);
|
||||
return <EnhancedComponent disableOnClickOutside={true} {...this.props} />;
|
||||
}
|
||||
}
|
||||
|
||||
AdvancedSelectorContainer.propTypes = {
|
||||
isOpen: PropTypes.bool
|
||||
}
|
||||
|
||||
export default AdvancedSelectorContainer;
|
||||
export default AdvancedSelector;
|
||||
|
@ -368,7 +368,7 @@ const Selector = props => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={style} className="row-block" {...tooltipProps}>
|
||||
<div style={style} className="row-option" {...tooltipProps}>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
@ -466,7 +466,7 @@ const Selector = props => {
|
||||
return (
|
||||
<div
|
||||
style={style}
|
||||
className={`row-block${isSelected ? " selected" : ""}`}
|
||||
className={`row-group${isSelected ? " selected" : ""}`}
|
||||
>
|
||||
{isMultiSelect && allowGroupSelection && (
|
||||
<Checkbox
|
||||
@ -608,7 +608,7 @@ const Selector = props => {
|
||||
</AutoSizer>
|
||||
|
||||
{!hasNextPage && itemCount === 0 && (
|
||||
<div className="row-block">
|
||||
<div className="row-option">
|
||||
<Text>
|
||||
{!searchValue ? emptyOptionsLabel : emptySearchOptionsLabel}
|
||||
</Text>
|
||||
@ -626,7 +626,7 @@ const Selector = props => {
|
||||
{displayType === "dropdown" && groups && groups.length > 0 && (
|
||||
<Column className="column-groups" displayType={displayType} size={size}>
|
||||
<Header className="header-groups">
|
||||
<Text as="p" className="group_header" fontSize="15px" isBold={true}>
|
||||
<Text as="p" className="group_header" fontSize="15px" fontWeight={600}>
|
||||
{groupsHeaderLabel}
|
||||
</Text>
|
||||
</Header>
|
||||
|
@ -49,12 +49,26 @@ const dropdownStyles = css`
|
||||
margin-left: -8px;
|
||||
/* background-color: white; */
|
||||
|
||||
.row-block {
|
||||
.row-group {
|
||||
box-sizing: border-box;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
padding-top: 8px;
|
||||
padding-left: 8px;
|
||||
|
||||
.group_checkbox {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f9f9;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.row-group.selected {
|
||||
background-color: #eceef1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,6 +161,24 @@ const StyledSelector = styled(Container)`
|
||||
}
|
||||
`}
|
||||
`}
|
||||
|
||||
.options_searcher {
|
||||
|
||||
div:first-child {
|
||||
|
||||
:hover {
|
||||
border-color: #D0D5DA;
|
||||
}
|
||||
|
||||
:focus, :focus-within {
|
||||
border-color: #2DA7DB;
|
||||
}
|
||||
|
||||
& > input {
|
||||
color: #A3A9AE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.body-options {
|
||||
@ -154,9 +186,12 @@ const StyledSelector = styled(Container)`
|
||||
margin-left: -8px;
|
||||
/* background-color: white; */
|
||||
|
||||
.row-block {
|
||||
.row-option {
|
||||
padding-left: 8px;
|
||||
padding-top: 8px;
|
||||
box-sizing: border-box;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
|
||||
.option-info {
|
||||
position: absolute;
|
||||
@ -167,21 +202,6 @@ const StyledSelector = styled(Container)`
|
||||
}
|
||||
}
|
||||
|
||||
.row-block {
|
||||
box-sizing: border-box;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
padding-top: 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f9f9;
|
||||
}
|
||||
}
|
||||
|
||||
.row-block.selected {
|
||||
background-color: #eceef1;
|
||||
}
|
||||
|
||||
.footer {
|
||||
grid-area: footer;
|
||||
}
|
||||
|
@ -92,7 +92,8 @@ class GroupSelector extends React.Component {
|
||||
isDisabled,
|
||||
onSelect,
|
||||
onCancel,
|
||||
t
|
||||
t,
|
||||
searchPlaceHolderLabel
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -110,7 +111,7 @@ class GroupSelector extends React.Component {
|
||||
isOpen={isOpen}
|
||||
isMultiSelect={isMultiSelect}
|
||||
isDisabled={isDisabled}
|
||||
searchPlaceHolderLabel={t("SearchPlaceholder")}
|
||||
searchPlaceHolderLabel={searchPlaceHolderLabel || t("SearchPlaceholder")}
|
||||
selectButtonLabel={t("AddDepartmentsButtonLabel")}
|
||||
selectAllLabel={t("SelectAllLabel")}
|
||||
emptySearchOptionsLabel={t("EmptySearchOptionsLabel")}
|
||||
@ -125,17 +126,18 @@ class GroupSelector extends React.Component {
|
||||
}
|
||||
|
||||
GroupSelector.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.oneOf([PropTypes.string, PropTypes.array]),
|
||||
style: PropTypes.object,
|
||||
isOpen: PropTypes.bool,
|
||||
onSelect: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
useFake: PropTypes.bool,
|
||||
isMultiSelect: PropTypes.bool,
|
||||
id: PropTypes.string,
|
||||
isDisabled: PropTypes.bool,
|
||||
isMultiSelect: PropTypes.bool,
|
||||
isOpen: PropTypes.bool,
|
||||
language: PropTypes.string,
|
||||
t: PropTypes.func
|
||||
onCancel: PropTypes.func,
|
||||
onSelect: PropTypes.func,
|
||||
searchPlaceHolderLabel: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
t: PropTypes.func,
|
||||
useFake: PropTypes.bool,
|
||||
};
|
||||
|
||||
GroupSelector.defaultProps = {
|
||||
|
@ -7,14 +7,16 @@ import {
|
||||
boolean
|
||||
} from "@storybook/addon-knobs/react";
|
||||
import Section from "../../../.storybook/decorators/section";
|
||||
|
||||
import withProvider from "../../../.storybook/decorators/redux";
|
||||
import GroupSelector from ".";
|
||||
import { BooleanValue } from "react-values";
|
||||
import { Button } from "asc-web-components";
|
||||
//import withReadme from "storybook-readme/with-readme";
|
||||
//import Readme from "./README.md";
|
||||
|
||||
|
||||
storiesOf("Components|GroupSelector", module)
|
||||
.addDecorator(withProvider)
|
||||
.addDecorator(withKnobs)
|
||||
//.addDecorator(withReadme(Readme))
|
||||
.addParameters({ options: { addonPanelInRight: false } })
|
||||
|
@ -117,9 +117,14 @@ class Layout extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
clearNavTimeout = () => {
|
||||
if (this.timeout == null) return;
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
}
|
||||
|
||||
handleNavMouseEnter = () => {
|
||||
if (!this.state.isNavHoverEnabled) return;
|
||||
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setState({
|
||||
isBackdropVisible: false,
|
||||
@ -131,12 +136,7 @@ class Layout extends React.Component {
|
||||
|
||||
handleNavMouseLeave = () => {
|
||||
if (!this.state.isNavHoverEnabled) return;
|
||||
|
||||
if (this.timeout != null) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
}
|
||||
|
||||
this.clearNavTimeout();
|
||||
this.setState({
|
||||
isBackdropVisible: false,
|
||||
isNavOpened: false,
|
||||
@ -145,6 +145,7 @@ class Layout extends React.Component {
|
||||
};
|
||||
|
||||
toggleAside = () => {
|
||||
this.clearNavTimeout();
|
||||
this.setState({
|
||||
isBackdropVisible: true,
|
||||
isNavOpened: false,
|
||||
@ -198,8 +199,8 @@ class Layout extends React.Component {
|
||||
badgeNumber={item.notifications}
|
||||
onClick={item.onClick}
|
||||
onBadgeClick={e => {
|
||||
item.onBadgeClick(e);
|
||||
this.toggleAside();
|
||||
item.onBadgeClick(e);
|
||||
}}
|
||||
url={item.url}
|
||||
>
|
||||
|
@ -9,6 +9,7 @@ import {IconButton, ContextMenuButton, MainButton, SearchInput, Paging} from "as
|
||||
import withReadme from 'storybook-readme/with-readme';
|
||||
import { boolean, withKnobs } from '@storybook/addon-knobs/react';
|
||||
import Readme from './README.md';
|
||||
import withProvider from "../../../.storybook/decorators/redux";
|
||||
|
||||
const currentUser = {
|
||||
id: '00000000-0000-0000-0000-000000000000',
|
||||
@ -211,6 +212,7 @@ const sectionPagingContent = <Paging
|
||||
/>
|
||||
|
||||
storiesOf('Components|Layout', module)
|
||||
.addDecorator(withProvider)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add('base', () => (
|
||||
|
@ -37,6 +37,7 @@ const HeaderNav = React.memo(props => {
|
||||
badgeNumber={module.notifications}
|
||||
onClick={module.onClick}
|
||||
onBadgeClick={module.onBadgeClick}
|
||||
noHover={true}
|
||||
/>
|
||||
))}
|
||||
{props.user && (
|
||||
|
@ -29,6 +29,7 @@ const HeaderComponent = React.memo(props => {
|
||||
iconName="MenuIcon"
|
||||
badgeNumber={props.badgeNumber}
|
||||
onClick={props.onClick}
|
||||
noHover={true}
|
||||
/>
|
||||
<Headline type="header" color="#FFFFFF">
|
||||
{props.currentModule && props.currentModule.title}
|
||||
|
@ -22,8 +22,11 @@ const NavItemWrapper = styled(Link)`
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
background: #0D3760;
|
||||
${props => !props.noHover && css`
|
||||
&:hover {
|
||||
background: #0D3760;
|
||||
text-decoration: none;
|
||||
}`
|
||||
}
|
||||
`;
|
||||
|
||||
@ -34,8 +37,9 @@ const NavItemLabel = styled(Text)`
|
||||
|
||||
const badgeCss = css`
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
top: 2px;
|
||||
right: 4px;
|
||||
overflow: inherit;
|
||||
`;
|
||||
|
||||
const NavItemBadge = styled(Badge)`
|
||||
@ -53,14 +57,16 @@ const NavItem = React.memo(props => {
|
||||
badgeNumber,
|
||||
onClick,
|
||||
onBadgeClick,
|
||||
url
|
||||
url,
|
||||
noHover
|
||||
} = props;
|
||||
const color = active ? activeColor : baseColor;
|
||||
|
||||
return separator ? (
|
||||
<NavItemSeparator />
|
||||
) : (
|
||||
<NavItemWrapper
|
||||
<NavItemWrapper
|
||||
noHover={noHover}
|
||||
href={url}
|
||||
onClick={onClick}>
|
||||
{React.createElement(Icons[iconName], {
|
||||
@ -75,7 +81,7 @@ const NavItem = React.memo(props => {
|
||||
)}
|
||||
<NavItemBadge
|
||||
opened={opened}
|
||||
number={badgeNumber}
|
||||
label={badgeNumber}
|
||||
onClick={onBadgeClick}
|
||||
/>
|
||||
</NavItemWrapper>
|
||||
@ -94,6 +100,7 @@ NavItem.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
opened: PropTypes.bool,
|
||||
separator: PropTypes.bool,
|
||||
noHover: PropTypes.bool
|
||||
};
|
||||
|
||||
export default NavItem;
|
||||
|
@ -9,6 +9,7 @@ import {IconButton, ContextMenuButton, MainButton, SearchInput, Paging} from 'as
|
||||
import withReadme from 'storybook-readme/with-readme';
|
||||
import { boolean, withKnobs } from '@storybook/addon-knobs/react';
|
||||
import Readme from './README.md';
|
||||
import withProvider from "../../../.storybook/decorators/redux";
|
||||
|
||||
const HeaderContent = styled.div`
|
||||
display: flex;
|
||||
@ -114,6 +115,7 @@ const sectionPagingContent = <Paging
|
||||
/>
|
||||
|
||||
storiesOf('Components|PageLayout', module)
|
||||
.addDecorator(withProvider)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add('base', () => (
|
||||
|
@ -11,10 +11,12 @@ import Section from "../../../.storybook/decorators/section";
|
||||
import PeopleSelector from ".";
|
||||
import { BooleanValue } from "react-values";
|
||||
import { Button } from "asc-web-components";
|
||||
import withProvider from "../../../.storybook/decorators/redux";
|
||||
//import withReadme from "storybook-readme/with-readme";
|
||||
//import Readme from "./README.md";
|
||||
|
||||
storiesOf("Components|PeopleSelector", module)
|
||||
.addDecorator(withProvider)
|
||||
.addDecorator(withKnobs)
|
||||
//.addDecorator(withReadme(Readme))
|
||||
.addParameters({ options: { addonPanelInRight: false } })
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-components",
|
||||
"version": "1.0.297",
|
||||
"version": "1.0.312",
|
||||
"description": "Ascensio System SIA component library",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/asc-web-components.js",
|
||||
@ -112,6 +112,7 @@
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
"react-dropzone": "^10.2.1",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"react-onclickoutside": "^6.9.0",
|
||||
"react-text-mask": "^5.4.3",
|
||||
"react-toastify": "^5.4.1",
|
||||
"react-tooltip": "^3.11.1",
|
||||
|
@ -10,7 +10,7 @@ import { Badge } from "asc-web-components";
|
||||
|
||||
```jsx
|
||||
<Badge
|
||||
number={10}
|
||||
label="10"
|
||||
backgroundColor="#ED7309"
|
||||
color="#FFFFFF"
|
||||
fontSize="11px"
|
||||
@ -34,7 +34,7 @@ import { Badge } from "asc-web-components";
|
||||
| `fontWeight` | `number` | - | - | `800` | CSS font-weight |
|
||||
| `id` | `string` | - | - | - | Accepts id |
|
||||
| `maxWidth` | `string` | - | - | `50px` | CSS max-width |
|
||||
| `number` | `number` | - | - | `0` | Number value |
|
||||
| `label` | `string` | - | - | `0` | Value |
|
||||
| `onClick` | `func` | - | - | - | onClick event |
|
||||
| `padding` | `string` | - | - | `0 5px` | CSS padding |
|
||||
| `style` | `obj`, `array` | - | - | - | Accepts css style |
|
||||
|
@ -13,7 +13,7 @@ storiesOf('Components|Badge', module)
|
||||
.add('base', () => (
|
||||
<Section>
|
||||
<Badge
|
||||
number={number('number', 10)}
|
||||
label={text('label', '10')}
|
||||
backgroundColor={color('backgroundColor', '#ED7309')}
|
||||
color={color('color', '#FFFFFF')}
|
||||
fontSize={text('fontSize', '11px')}
|
||||
@ -21,9 +21,46 @@ storiesOf('Components|Badge', module)
|
||||
borderRadius={text('borderRadius', '11px')}
|
||||
padding={text('padding', '0 5px')}
|
||||
maxWidth={text('maxWidth', '50px')}
|
||||
onClick={(e)=>{
|
||||
onClick={(e) => {
|
||||
action('onClick')(e);
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
<Badge
|
||||
label="New"
|
||||
backgroundColor={color('backgroundColor', '#ED7309')}
|
||||
color={color('color', '#FFFFFF')}
|
||||
fontSize={text('fontSize', '11px')}
|
||||
fontWeight={number('fontWeight', 800)}
|
||||
borderRadius={text('borderRadius', '11px')}
|
||||
padding={text('padding', '0 5px')}
|
||||
maxWidth={text('maxWidth', '50px')}
|
||||
onClick={(e) => {
|
||||
action('onClick')(e);
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
<Badge
|
||||
label="Ver.2"
|
||||
backgroundColor="#A3A9AE"
|
||||
color={color('color', '#FFFFFF')}
|
||||
fontSize={text('fontSize', '11px')}
|
||||
fontWeight={number('fontWeight', 800)}
|
||||
borderRadius={text('borderRadius', '11px')}
|
||||
padding={text('padding', '0 5px')}
|
||||
maxWidth={text('maxWidth', '50px')}
|
||||
onClick={(e) => {
|
||||
action('onClick')(e);
|
||||
}}
|
||||
/>
|
||||
<p>
|
||||
Text with badge
|
||||
<Badge
|
||||
label="3"
|
||||
onClick={(e) => {
|
||||
action('onClick')(e);
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</Section>
|
||||
));
|
@ -11,12 +11,12 @@ describe('<Badge />', () => {
|
||||
expect(wrapper).toExist();
|
||||
});
|
||||
|
||||
it('displays number', () => {
|
||||
it('displays label', () => {
|
||||
const wrapper = mount(
|
||||
<Badge number={10} />
|
||||
<Badge label='10' />
|
||||
);
|
||||
|
||||
expect(wrapper.prop('number')).toBe(10);
|
||||
expect(wrapper.prop('label')).toBe('10');
|
||||
});
|
||||
|
||||
it('call onClick()', () => {
|
||||
|
@ -4,15 +4,26 @@ import styled from 'styled-components';
|
||||
import Text from "../text";
|
||||
|
||||
const StyledBadge = styled.div`
|
||||
display: ${props => (props.label.length > 0 || props.label != '0') ? 'inline-block' : 'none'};
|
||||
border: 1px solid transparent;
|
||||
border-radius: ${props => props.borderRadius};
|
||||
width: fit-content;
|
||||
padding: 2px;
|
||||
line-height: 0.8;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
|
||||
:hover {
|
||||
border-color: ${props => props.backgroundColor};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledInner = styled.div`
|
||||
background-color: ${props => props.backgroundColor};
|
||||
border-radius: ${props => props.borderRadius};
|
||||
padding: ${props => props.padding};
|
||||
max-width: ${props => props.maxWidth};
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: ${props => props.number > 0 ? 'inline-block' : 'none'};
|
||||
user-select: none;
|
||||
line-height: 1.5;
|
||||
`;
|
||||
@ -21,24 +32,47 @@ const Badge = props => {
|
||||
//console.log("Badge render");
|
||||
|
||||
const onClick = e => {
|
||||
if (props.onClick) {
|
||||
e.stopPropagation();
|
||||
props.onClick(e);
|
||||
}
|
||||
if (!props.onClick) return;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
props.onClick(e);
|
||||
};
|
||||
|
||||
const { fontSize, color, fontWeight } = props;
|
||||
|
||||
const {
|
||||
fontSize,
|
||||
color,
|
||||
fontWeight,
|
||||
backgroundColor,
|
||||
borderRadius,
|
||||
padding,
|
||||
maxWidth
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<StyledBadge {...props} onClick={onClick}>
|
||||
<Text fontWeight={fontWeight} color={color} fontSize={fontSize}>
|
||||
{props.number}
|
||||
</Text>
|
||||
<StyledBadge
|
||||
{...props}
|
||||
onClick={onClick}
|
||||
>
|
||||
<StyledInner
|
||||
backgroundColor={backgroundColor}
|
||||
borderRadius={borderRadius}
|
||||
padding={padding}
|
||||
maxWidth={maxWidth}
|
||||
>
|
||||
<Text
|
||||
fontWeight={fontWeight}
|
||||
color={color}
|
||||
fontSize={fontSize}>
|
||||
{props.label}
|
||||
</Text>
|
||||
</StyledInner>
|
||||
</StyledBadge>
|
||||
);
|
||||
};
|
||||
|
||||
Badge.propTypes = {
|
||||
number: PropTypes.number,
|
||||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
backgroundColor: PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
fontSize: PropTypes.string,
|
||||
@ -53,7 +87,7 @@ Badge.propTypes = {
|
||||
};
|
||||
|
||||
Badge.defaultProps = {
|
||||
number: 0,
|
||||
label: 0,
|
||||
backgroundColor: '#ED7309',
|
||||
color: '#FFFFFF',
|
||||
fontSize: "11px",
|
||||
|
@ -32,7 +32,8 @@ const baseProps = {
|
||||
selectedOption: {
|
||||
key: 0,
|
||||
icon: 'CatalogFolderIcon',
|
||||
label: "Select"
|
||||
label: "Select",
|
||||
default: true
|
||||
},
|
||||
options: baseOptions,
|
||||
opened: false,
|
||||
@ -41,6 +42,17 @@ const baseProps = {
|
||||
scaled: true
|
||||
};
|
||||
|
||||
const toggleDisplayProps = {
|
||||
options: [],
|
||||
selectedOption: {
|
||||
key: 0,
|
||||
label: "Selected option"
|
||||
},
|
||||
scaled: false,
|
||||
size: "content",
|
||||
displayType: "toggle"
|
||||
};
|
||||
|
||||
describe('<ComboBox />', () => {
|
||||
it('rendered without error', () => {
|
||||
const wrapper = mount(
|
||||
@ -76,6 +88,13 @@ describe('<ComboBox />', () => {
|
||||
expect(wrapper.prop('opened')).toEqual(true);
|
||||
});
|
||||
|
||||
it('opened without borders', () => {
|
||||
const wrapper = mount(<ComboBox {...baseProps} opened={true} noBorder={true} />);
|
||||
|
||||
expect(wrapper.prop('opened')).toEqual(true);
|
||||
expect(wrapper.prop('noBorder')).toEqual(true);
|
||||
});
|
||||
|
||||
it('with DropDown max height', () => {
|
||||
const wrapper = mount(<ComboBox {...baseProps} dropDownMaxHeight={200} />);
|
||||
|
||||
@ -188,24 +207,6 @@ describe('<ComboBox />', () => {
|
||||
expect(wrapper.state('isOpen')).toBe(false);
|
||||
});
|
||||
|
||||
it('causes function handleClick() with opened prop', () => {
|
||||
const wrapper = mount(<ComboBox {...baseProps} opened={true} />);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
instance.handleClick(new Event('click'));
|
||||
|
||||
expect(wrapper.state('isOpen')).toBe(false);
|
||||
});
|
||||
|
||||
it('causes function handleClick()', () => {
|
||||
const wrapper = mount(<ComboBox {...baseProps} />);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
instance.handleClick(new Event('click'));
|
||||
|
||||
expect(wrapper.state('isOpen')).toBe(false);
|
||||
});
|
||||
|
||||
it('causes function handleClick() with simulate', () => {
|
||||
const wrapper = mount(<ComboBox {...baseProps} opened={true} />);
|
||||
|
||||
@ -222,38 +223,35 @@ describe('<ComboBox />', () => {
|
||||
expect(wrapper.state('isOpen')).toBe(true);
|
||||
});
|
||||
|
||||
it('componentDidUpdate() state lifecycle test', () => {
|
||||
it('componentDidUpdate() lifecycle test', () => {
|
||||
const wrapper = shallow(<ComboBox {...baseProps} />);
|
||||
const instance = wrapper.instance();
|
||||
const newSelected = { key: 1, label: "Select" };
|
||||
|
||||
wrapper.setState({ isOpen: false });
|
||||
jest.spyOn(instance, 'setIsOpen');
|
||||
|
||||
instance.componentDidUpdate(wrapper.props(), wrapper.state());
|
||||
wrapper.setProps({
|
||||
opened: true
|
||||
});
|
||||
|
||||
expect(wrapper.state()).toBe(wrapper.state());
|
||||
});
|
||||
expect(wrapper.props().opened).toBe(true);
|
||||
|
||||
it('componentDidUpdate() props lifecycle test', () => {
|
||||
const wrapper = shallow(<ComboBox {...baseProps} />);
|
||||
const instance = wrapper.instance();
|
||||
wrapper.setProps({
|
||||
opened: false
|
||||
});
|
||||
|
||||
expect(wrapper.props().opened).toBe(false);
|
||||
|
||||
instance.componentDidUpdate({
|
||||
opened: true,
|
||||
selectedOption: {
|
||||
key: 1,
|
||||
label: "Select"
|
||||
}
|
||||
}, wrapper.state());
|
||||
selectedOption: newSelected
|
||||
}, {
|
||||
isOpen: true
|
||||
});
|
||||
|
||||
expect(wrapper.props()).toBe(wrapper.props());
|
||||
});
|
||||
instance.forceUpdate(); //Need for manual re-render, enzyme issue
|
||||
|
||||
it('componentWillUnmount() lifecycle test', () => {
|
||||
const wrapper = mount(<ComboBox {...baseProps} opened={true} />);
|
||||
const componentWillUnmount = jest.spyOn(wrapper.instance(), 'componentWillUnmount');
|
||||
|
||||
wrapper.unmount();
|
||||
expect(componentWillUnmount).toHaveBeenCalled();
|
||||
expect(instance.setIsOpen).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('accepts id', () => {
|
||||
@ -279,4 +277,47 @@ describe('<ComboBox />', () => {
|
||||
|
||||
expect(wrapper.getDOMNode().style).toHaveProperty('color', 'red');
|
||||
});
|
||||
|
||||
it('render like toggle displayType', () => {
|
||||
const onToggleClick = jest.fn();
|
||||
const wrapper = mount(
|
||||
<ComboBox
|
||||
{...toggleDisplayProps}
|
||||
toggleAction={onToggleClick}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.prop('displayType')).toEqual('toggle');
|
||||
});
|
||||
|
||||
it('click on toggle', () => {
|
||||
const onToggleClick = jest.fn();
|
||||
const wrapper = mount(
|
||||
<ComboBox
|
||||
{...toggleDisplayProps}
|
||||
toggleAction={onToggleClick}
|
||||
/>
|
||||
);
|
||||
|
||||
jest.spyOn(wrapper.instance(), 'setIsOpen');
|
||||
|
||||
wrapper.simulate('click');
|
||||
|
||||
expect(onToggleClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('click outside', () => {
|
||||
const onToggleClick = jest.fn();
|
||||
const wrapper = mount(<ComboBox {...baseProps} opened toggleAction={onToggleClick} />);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
jest.spyOn(instance, 'handleClickOutside');
|
||||
|
||||
instance.handleClickOutside(); //TODO: rework with simulation
|
||||
|
||||
expect(wrapper.state('isOpen')).toBe(false);
|
||||
expect(wrapper.prop('opened')).toBe(true);
|
||||
expect(instance.handleClickOutside).toHaveBeenCalled();
|
||||
expect(onToggleClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -3,7 +3,6 @@ import DropDown from '../drop-down'
|
||||
import DropDownItem from '../drop-down-item'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { handleAnyClick } from '../../utils/event';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@ -31,26 +30,32 @@ class ComboBox extends React.Component {
|
||||
isOpen: props.opened,
|
||||
selectedOption: props.selectedOption
|
||||
};
|
||||
|
||||
if (props.opened)
|
||||
handleAnyClick(true, this.handleClick);
|
||||
}
|
||||
|
||||
handleClick = (e) => {
|
||||
if (this.state.isOpen && !this.ref.current.contains(e.target)) {
|
||||
this.toggle(false);
|
||||
this.props.toggleAction && this.props.toggleAction(e, true);
|
||||
}
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const needUpdate = !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
|
||||
|
||||
//console.log("shouldComponentUpdate", needUpdate);
|
||||
|
||||
return needUpdate;
|
||||
}
|
||||
|
||||
stopAction = (e) => e.preventDefault();
|
||||
|
||||
toggle = (isOpen) => this.setState({ isOpen: isOpen });
|
||||
setIsOpen = (isOpen) => this.setState({ isOpen: isOpen });
|
||||
|
||||
handleClickOutside = e => {
|
||||
//console.log(`ComboBox handleClickOutside`, e);
|
||||
this.setState({ isOpen: !this.state.isOpen }, () => {
|
||||
this.props.toggleAction && this.props.toggleAction(e, this.state.isOpen);
|
||||
})
|
||||
};
|
||||
|
||||
comboBoxClick = (e) => {
|
||||
if (this.props.isDisabled || e && e.target.closest('.optionalBlock')) return;
|
||||
this.toggle(!this.state.isOpen);
|
||||
this.props.toggleAction && this.props.toggleAction(e, this.state.isOpen);
|
||||
this.setState({ isOpen: !this.state.isOpen }, () => {
|
||||
this.props.toggleAction && this.props.toggleAction(e, this.state.isOpen);
|
||||
})
|
||||
};
|
||||
|
||||
optionClick = (option) => {
|
||||
@ -62,21 +67,9 @@ class ComboBox extends React.Component {
|
||||
this.props.onSelect && this.props.onSelect(option);
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
handleAnyClick(false, this.handleClick);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (this.props.opened !== prevProps.opened) {
|
||||
handleAnyClick(this.props.opened, this.handleClick);
|
||||
}
|
||||
|
||||
if (this.state.isOpen !== prevState.isOpen) {
|
||||
handleAnyClick(this.state.isOpen, this.handleClick);
|
||||
if (this.props.opened !== prevProps.opened && this.state.isOpen !== prevState.isOpen) {
|
||||
this.setIsOpen(this.state.isOpen);
|
||||
}
|
||||
|
||||
if (this.props.selectedOption !== prevProps.selectedOption) {
|
||||
@ -149,6 +142,7 @@ class ComboBox extends React.Component {
|
||||
directionY={directionY}
|
||||
manualY='102%'
|
||||
open={isOpen}
|
||||
clickOutsideAction={this.handleClickOutside}
|
||||
{...dropDownMaxHeightProp}
|
||||
{...dropDownManualWidthProp}
|
||||
>
|
||||
|
@ -65,16 +65,16 @@ const StyledComboButton = styled.div`
|
||||
max-width: 175px;
|
||||
${props => props.noBorder && `
|
||||
line-height: 15px;
|
||||
border-bottom: 1px dashed transparent;
|
||||
text-decoration: underline dashed transparent;
|
||||
`}
|
||||
|
||||
${props => props.isOpen && props.noBorder && `
|
||||
border-bottom: 1px dashed;
|
||||
text-decoration: underline dashed;
|
||||
`};
|
||||
}
|
||||
.combo-button-label:hover{
|
||||
${props => props.noBorder && !props.isDisabled && `
|
||||
border-bottom: 1px dashed;
|
||||
text-decoration: underline dashed;
|
||||
`}
|
||||
}
|
||||
`;
|
||||
|
@ -140,15 +140,6 @@ describe('<ContextMenuButton />', () => {
|
||||
expect(wrapper.props()).toBe(wrapper.props());
|
||||
});
|
||||
|
||||
it('componentWillUnmount() props lifecycle test', () => {
|
||||
const wrapper = shallow(<ContextMenuButton {...baseProps} />);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
instance.componentWillUnmount();
|
||||
|
||||
expect(wrapper).toExist(false);
|
||||
});
|
||||
|
||||
it('accepts id', () => {
|
||||
const wrapper = mount(
|
||||
<ContextMenuButton {...baseProps} id="testId" />
|
||||
|
@ -4,7 +4,6 @@ import PropTypes from 'prop-types'
|
||||
import DropDownItem from '../drop-down-item'
|
||||
import DropDown from '../drop-down'
|
||||
import IconButton from '../icon-button'
|
||||
import { handleAnyClick } from '../../utils/event';
|
||||
|
||||
const StyledOuter = styled.div`
|
||||
display: inline-block;
|
||||
@ -28,39 +27,35 @@ class ContextMenuButton extends React.Component {
|
||||
this.toggle = this.toggle.bind(this);
|
||||
this.onIconButtonClick = this.onIconButtonClick.bind(this);
|
||||
this.onDropDownItemClick = this.onDropDownItemClick.bind(this);
|
||||
|
||||
if (props.opened)
|
||||
handleAnyClick(true, this.handleClick);
|
||||
}
|
||||
|
||||
handleClick = (e) => this.state.isOpen && !this.ref.current.contains(e.target) && this.toggle(false);
|
||||
stopAction = (e) => e.preventDefault();
|
||||
toggle = (isOpen) => this.setState({ isOpen: isOpen });
|
||||
|
||||
componentWillUnmount() {
|
||||
handleAnyClick(false, this.handleClick);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (this.props.opened !== prevProps.opened) {
|
||||
this.toggle(this.props.opened);
|
||||
}
|
||||
|
||||
if (this.state.isOpen !== prevState.isOpen) {
|
||||
handleAnyClick(this.state.isOpen, this.handleClick);
|
||||
}
|
||||
}
|
||||
|
||||
onIconButtonClick = () => {
|
||||
if (!this.props.isDisabled) {
|
||||
this.setState({
|
||||
data: this.props.getData(),
|
||||
isOpen: !this.state.isOpen
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.stopAction
|
||||
if (this.props.isDisabled) {
|
||||
this.stopAction;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("ContextMenuButton onIconButtonClick (isOpen)", this.state.isOpen);
|
||||
|
||||
this.setState({
|
||||
data: this.props.getData(),
|
||||
isOpen: !this.state.isOpen
|
||||
});
|
||||
}
|
||||
|
||||
clickOutsideAction = () => {
|
||||
console.log("ContextMenuButton clickOutsideAction", );
|
||||
this.onIconButtonClick();
|
||||
}
|
||||
|
||||
onDropDownItemClick = (item) => {
|
||||
@ -83,6 +78,7 @@ class ContextMenuButton extends React.Component {
|
||||
clickColor,
|
||||
size,
|
||||
iconName,
|
||||
iconOpenName,
|
||||
iconHoverName,
|
||||
iconClickName,
|
||||
isDisabled,
|
||||
@ -97,7 +93,7 @@ class ContextMenuButton extends React.Component {
|
||||
} = this.props;
|
||||
|
||||
const { isOpen } = this.state;
|
||||
|
||||
const iconButtonName = isOpen && iconOpenName ? iconOpenName : iconName;
|
||||
return (
|
||||
<StyledOuter ref={this.ref} className={className} id={id} style={style}>
|
||||
<IconButton
|
||||
@ -105,7 +101,7 @@ class ContextMenuButton extends React.Component {
|
||||
hoverColor={hoverColor}
|
||||
clickColor={clickColor}
|
||||
size={size}
|
||||
iconName={iconName}
|
||||
iconName={iconButtonName}
|
||||
iconHoverName={iconHoverName}
|
||||
iconClickName={iconClickName}
|
||||
isFill={false}
|
||||
@ -119,7 +115,7 @@ class ContextMenuButton extends React.Component {
|
||||
<DropDown
|
||||
directionX={directionX}
|
||||
open={isOpen}
|
||||
clickOutsideAction={this.onIconButtonClick}
|
||||
clickOutsideAction={this.clickOutsideAction}
|
||||
>
|
||||
{
|
||||
this.state.data.map((item, index) =>
|
||||
@ -148,6 +144,7 @@ ContextMenuButton.propTypes = {
|
||||
|
||||
iconHoverName: PropTypes.string,
|
||||
iconClickName: PropTypes.string,
|
||||
iconOpenName: PropTypes.string,
|
||||
|
||||
onMouseEnter: PropTypes.func,
|
||||
onMouseLeave: PropTypes.func,
|
||||
|
@ -98,7 +98,8 @@ describe('<DropDown />', () => {
|
||||
expect(wrapper.props.children).toEqual(child);
|
||||
});
|
||||
|
||||
it('componentDidUpdate() state lifecycle test', () => {
|
||||
//TODO: Fix final condition checks
|
||||
/* it('componentDidUpdate() state lifecycle test', () => {
|
||||
const wrapper = shallow(<DropDown {...baseProps} />);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
@ -107,16 +108,17 @@ describe('<DropDown />', () => {
|
||||
instance.componentDidUpdate(wrapper.props(), wrapper.state());
|
||||
|
||||
expect(wrapper.state()).toBe(wrapper.state());
|
||||
});
|
||||
}); */
|
||||
|
||||
it('componentDidUpdate() props lifecycle test', () => {
|
||||
//TODO: Fix final condition checks
|
||||
/* it('componentDidUpdate() props lifecycle test', () => {
|
||||
const wrapper = shallow(<DropDown {...baseProps} />);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
instance.componentDidUpdate({ open: true }, wrapper.state());
|
||||
|
||||
expect(wrapper.props()).toBe(wrapper.props());
|
||||
});
|
||||
}); */
|
||||
|
||||
it('accepts id', () => {
|
||||
const wrapper = mount(
|
||||
|
@ -5,6 +5,7 @@ import CustomScrollbarsVirtualList from '../scrollbar/custom-scrollbars-virtual-
|
||||
import DropDownItem from '../drop-down-item'
|
||||
import Backdrop from '../backdrop'
|
||||
import { FixedSizeList } from "react-window"
|
||||
import onClickOutside from "react-onclickoutside";
|
||||
|
||||
const StyledDropdown = styled.div`
|
||||
font-family: 'Open Sans',sans-serif,Arial;
|
||||
@ -80,17 +81,41 @@ class DropDown extends React.PureComponent {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.checkPosition();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.open !== prevProps.open) {
|
||||
if(this.props.open) {
|
||||
this.props.enableOnClickOutside();
|
||||
this.checkPosition();
|
||||
}
|
||||
}
|
||||
|
||||
toggleDropDown = () => {
|
||||
this.props.clickOutsideAction && this.props.clickOutsideAction(!this.props.open);
|
||||
componentWillUnmount() {
|
||||
this.props.disableOnClickOutside();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.open !== prevProps.open) {
|
||||
if(this.props.open) {
|
||||
this.props.enableOnClickOutside();
|
||||
this.checkPosition();
|
||||
}
|
||||
else {
|
||||
this.props.disableOnClickOutside();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
handleClickOutside = e => {
|
||||
// ..handling code goes here...
|
||||
console.log(`DropDown handleClickOutside`, e);
|
||||
|
||||
this.toggleDropDown(e);
|
||||
//this.onClose(e);
|
||||
//this.setIsOpen(!this.state.isOpen);
|
||||
//this.props.toggleAction && this.props.toggleAction(e, this.state.isOpen);
|
||||
};
|
||||
|
||||
toggleDropDown = (e) => {
|
||||
this.props.clickOutsideAction && this.props.clickOutsideAction(e, !this.props.open);
|
||||
}
|
||||
|
||||
checkPosition = () => {
|
||||
@ -123,7 +148,6 @@ class DropDown extends React.PureComponent {
|
||||
//console.log("DropDown render");
|
||||
return (
|
||||
<>
|
||||
{(withBackdrop && open && isTablet) && <Backdrop visible zIndex={149} onClick={this.toggleDropDown} />}
|
||||
<StyledDropdown
|
||||
ref={this.dropDownRef}
|
||||
{...this.props}
|
||||
@ -145,6 +169,7 @@ class DropDown extends React.PureComponent {
|
||||
</FixedSizeList>
|
||||
: children}
|
||||
</StyledDropdown>
|
||||
{(withBackdrop && open && isTablet) && <Backdrop visible zIndex={149} onClick={this.toggleDropDown} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -164,7 +189,9 @@ DropDown.propTypes = {
|
||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
withArrow: PropTypes.bool,
|
||||
withBackdrop: PropTypes.bool,
|
||||
clickOutsideAction: PropTypes.func
|
||||
clickOutsideAction: PropTypes.func,
|
||||
enableOnClickOutside: PropTypes.func,
|
||||
disableOnClickOutside: PropTypes.func
|
||||
};
|
||||
|
||||
DropDown.defaultProps = {
|
||||
@ -174,4 +201,14 @@ DropDown.defaultProps = {
|
||||
withBackdrop: true
|
||||
};
|
||||
|
||||
export default DropDown
|
||||
const EnhancedComponent = onClickOutside(DropDown);
|
||||
|
||||
class DropDownContainer extends React.Component {
|
||||
render() {
|
||||
//console.log(`AdvancedSelectorContainer isOpen=${this.props.isOpen} enableOnClickOutside=${this.props.isOpen}`);
|
||||
return <EnhancedComponent disableOnClickOutside={true} {...this.props} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default DropDownContainer;
|
||||
|
@ -138,7 +138,7 @@ class FilterItem extends React.Component {
|
||||
directionX='left'
|
||||
toggleAction={(e,isOpen)=>{
|
||||
this.setState({
|
||||
isOpen: !isOpen
|
||||
isOpen: isOpen
|
||||
})
|
||||
}}
|
||||
></StyledComboBox>
|
||||
@ -206,25 +206,28 @@ class FilterBlock extends React.Component {
|
||||
});
|
||||
}
|
||||
if (this.state.hideFilterItems.length > 0) {
|
||||
var open = false;
|
||||
var hideFilterItemsList = this.state.hideFilterItems.map(function (item) {
|
||||
open = item.key.indexOf('_-1') == -1 ? false : true
|
||||
return <FilterItem
|
||||
block={true}
|
||||
isDisabled={_this.props.isDisabled}
|
||||
key={item.key}
|
||||
groupItems={_this.props.getFilterData().filter(function (t) {
|
||||
return (t.group == item.group && t.group != t.key);
|
||||
})}
|
||||
onSelectFilterItem={_this.props.onClickFilterItem}
|
||||
id={item.key}
|
||||
groupLabel={item.groupLabel}
|
||||
opened={item.key.indexOf('_-1') == -1 ? false : true}
|
||||
label={item.label}
|
||||
onClose={_this.onDeleteFilterItem}>
|
||||
</FilterItem>
|
||||
})
|
||||
hideItems.push(
|
||||
<HideFilter key="hide-filter" count={this.state.hideFilterItems.length} isDisabled={this.props.isDisabled}>
|
||||
<HideFilter key="hide-filter" count={this.state.hideFilterItems.length} isDisabled={this.props.isDisabled} open={open}>
|
||||
{
|
||||
this.state.hideFilterItems.map(function (item) {
|
||||
return <FilterItem
|
||||
block={true}
|
||||
isDisabled={_this.props.isDisabled}
|
||||
key={item.key}
|
||||
groupItems={_this.props.getFilterData().filter(function (t) {
|
||||
return (t.group == item.group && t.group != t.key);
|
||||
})}
|
||||
onSelectFilterItem={_this.props.onClickFilterItem}
|
||||
id={item.key}
|
||||
groupLabel={item.groupLabel}
|
||||
opened={false}
|
||||
label={item.label}
|
||||
onClose={_this.onDeleteFilterItem}>
|
||||
</FilterItem>
|
||||
})
|
||||
hideFilterItemsList
|
||||
}
|
||||
</HideFilter>
|
||||
);
|
||||
|
@ -10,12 +10,12 @@ class FilterButton extends React.PureComponent {
|
||||
id={this.props.id}
|
||||
title='Actions'
|
||||
iconName='RectangleFilterIcon'
|
||||
iconOpenName='RectangleFilterClickIcon'
|
||||
color='#A3A9AE'
|
||||
size={this.props.iconSize}
|
||||
isDisabled={this.props.isDisabled}
|
||||
getData={this.props.getData}
|
||||
iconHoverName='RectangleFilterHoverIcon'
|
||||
iconClickName='RectangleFilterClickIcon'
|
||||
|
||||
className='filter-button'
|
||||
></ContextMenuButton>
|
||||
)
|
||||
|
@ -3,6 +3,7 @@ import styled from "styled-components";
|
||||
import { Icons } from "../icons";
|
||||
import DropDown from "../drop-down";
|
||||
import { handleAnyClick } from "../../utils/event";
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Caret = styled.div`
|
||||
width: 7px;
|
||||
@ -54,7 +55,7 @@ class HideFilter extends React.Component {
|
||||
this.ref = React.createRef();
|
||||
this.dropDownRef = React.createRef();
|
||||
this.state = {
|
||||
popoverOpen: false
|
||||
popoverOpen: this.props.open
|
||||
};
|
||||
}
|
||||
|
||||
@ -71,7 +72,7 @@ class HideFilter extends React.Component {
|
||||
|
||||
handleClick = e => {
|
||||
this.state.popoverOpen &&
|
||||
!this.ref.current.contains(e.target) &&
|
||||
!this.dropDownRef.current.firstElementChild.contains(e.target) &&
|
||||
this.onClick(false);
|
||||
};
|
||||
|
||||
@ -120,5 +121,10 @@ class HideFilter extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
HideFilter.propTypes = {
|
||||
children: PropTypes.any,
|
||||
open: PropTypes.bool,
|
||||
isDisabled: PropTypes.bool,
|
||||
count: PropTypes.number
|
||||
}
|
||||
export default HideFilter;
|
||||
|
@ -35,12 +35,15 @@ const StyledFilterBlock = styled.div`
|
||||
.filter-button {
|
||||
div:active {
|
||||
svg path:first-child {
|
||||
fill: #ECEEF1;
|
||||
fill: #ECEEF1;
|
||||
}
|
||||
}
|
||||
div:first-child:hover {
|
||||
svg path:first-child {
|
||||
stroke: #adb3b8;
|
||||
}
|
||||
svg path:not(:first-child) {
|
||||
stroke: #555F65;
|
||||
stroke: #555F65;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class IconButton extends React.PureComponent {
|
||||
onMouseEnter && onMouseEnter(e);
|
||||
}
|
||||
onMouseLeave(e) {
|
||||
const { isDisabled, iconName, color, onMouseDown } = this.props;
|
||||
const { isDisabled, iconName, color, onMouseLeave } = this.props;
|
||||
|
||||
if (isDisabled) return;
|
||||
|
||||
@ -57,7 +57,7 @@ class IconButton extends React.PureComponent {
|
||||
currentIconColor: color
|
||||
});
|
||||
|
||||
onMouseDown && onMouseDown(e);
|
||||
onMouseLeave && onMouseLeave(e);
|
||||
}
|
||||
onMouseDown(e) {
|
||||
const {
|
||||
@ -177,6 +177,7 @@ IconButton.propTypes = {
|
||||
onMouseEnter: PropTypes.func,
|
||||
onMouseDown: PropTypes.func,
|
||||
onMouseUp: PropTypes.func,
|
||||
onMouseLeave: PropTypes.func,
|
||||
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
dataTip: PropTypes.string
|
||||
|
@ -0,0 +1,3 @@
|
||||
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.9862 0.721877L16.2791 0.0147705L8.50091 7.79295L0.722732 0.0147736L0.015625 0.72188L7.7938 8.50006L0.0156276 16.2782L0.722734 16.9853L8.50091 9.20716L16.2791 16.9853L16.9862 16.2782L9.20801 8.50005L16.9862 0.721877Z" fill="#D0D5DA"/>
|
||||
</svg>
|
After Width: | Height: | Size: 390 B |
@ -117,6 +117,7 @@ import OrigRectangleFilterHoverIcon from './rectangle.filter.hover.react.svg';
|
||||
import OrigRectangleFilterClickIcon from './rectangle.filter.click.react.svg';
|
||||
import OrigCatalogButtonIcon from './catalog.button.react.svg';
|
||||
import OrigCrossIcon from './cross.react.svg';
|
||||
import OrigCrossSidebarIcon from './cross.sidebar.react.svg';
|
||||
import OrigCheckboxIcon from './checkbox.react.svg';
|
||||
import OrigCheckboxCheckedIcon from './checkbox.checked.react.svg';
|
||||
import OrigCheckboxIndeterminateIcon from './checkbox.indeterminate.react.svg';
|
||||
@ -373,6 +374,10 @@ export const CrossIcon = createStyledIcon(
|
||||
OrigCrossIcon,
|
||||
'CrossIcon'
|
||||
);
|
||||
export const CrossSidebarIcon = createStyledIcon(
|
||||
OrigCrossSidebarIcon,
|
||||
'CrossSidebarIcon'
|
||||
);
|
||||
export const DangerIcon = createStyledIcon(
|
||||
OrigDangerIcon,
|
||||
'DangerIcon'
|
||||
|
@ -1,5 +1,5 @@
|
||||
<svg width="33" height="26" viewBox="0 0 33 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.5 3C0.5 1.61929 1.61929 0.5 3 0.5H21.1954C21.9785 0.5 22.7163 0.866919 23.1889 1.49134L31.2783 12.1803C31.6858 12.7188 31.6832 13.4633 31.2719 13.999L23.1913 24.5226C22.7182 25.1388 21.9854 25.5 21.2084 25.5H3C1.61929 25.5 0.5 24.3807 0.5 23V3Z" fill="#ECEEF1" stroke="#A3A9AE"/>
|
||||
<rect x="13.5" y="6.5" width="13" height="1" transform="rotate(90 13.5 6.5)" fill="#D8D8D8" stroke="#979797"/>
|
||||
<rect x="6.5" y="12.5" width="13" height="1" fill="#D8D8D8" stroke="#979797"/>
|
||||
<rect x="13.5" y="6.5" width="13" height="1" transform="rotate(90 13.5 6.5)" fill="#D8D8D8" stroke="#555F65"/>
|
||||
<rect x="6.5" y="12.5" width="13" height="1" fill="#D8D8D8" stroke="#555F65"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 585 B After Width: | Height: | Size: 585 B |
@ -166,7 +166,7 @@ class MainButton extends React.PureComponent {
|
||||
return (
|
||||
<GroupMainButton {...this.props} ref={this.ref}>
|
||||
<StyledMainButton {...this.props} onClick={this.onMainButtonClick}>
|
||||
<Text fontSize='16px' fontWeight={600} color="#fff">
|
||||
<Text fontSize='16px' fontWeight='bold' color="#fff">
|
||||
{this.props.text}
|
||||
</Text>
|
||||
</StyledMainButton>
|
||||
|
@ -6,6 +6,7 @@ import Aside from "../aside";
|
||||
import Heading from "../heading";
|
||||
import { desktop } from "../../utils/device";
|
||||
import throttle from "lodash/throttle";
|
||||
import { Icons } from "../icons";
|
||||
|
||||
const Dialog = styled.div`
|
||||
position: relative;
|
||||
@ -37,35 +38,22 @@ const StyledHeader = styled.div`
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
`;
|
||||
|
||||
const CloseButton = styled.a`
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 20px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
const CloseButton = styled(Icons.CrossSidebarIcon)`
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
min-width: 17px;
|
||||
min-height: 17px;
|
||||
|
||||
right: 16px;
|
||||
top: 19px;
|
||||
|
||||
&:hover {
|
||||
&:before,
|
||||
&:after {
|
||||
background-color: #657077;
|
||||
}
|
||||
}
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
content: " ";
|
||||
height: 16px;
|
||||
width: 1px;
|
||||
background-color: #d8d8d8;
|
||||
}
|
||||
&:before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
&:after {
|
||||
transform: rotate(-45deg);
|
||||
path {
|
||||
fill: #657077;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -6,6 +6,13 @@ import InputBlock from '../input-block';
|
||||
const StyledSearchInput = styled.div`
|
||||
font-family: Open Sans;
|
||||
font-style: normal;
|
||||
|
||||
.search-input-block {
|
||||
& > input {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
class SearchInput extends React.Component {
|
||||
@ -74,6 +81,7 @@ class SearchInput extends React.Component {
|
||||
return (
|
||||
<StyledSearchInput className={this.props.className} style={this.props.style}>
|
||||
<InputBlock
|
||||
className='search-input-block'
|
||||
ref={this.input}
|
||||
id={this.props.id}
|
||||
name={this.props.name}
|
||||
|
@ -8,7 +8,7 @@ const styleCss = css`
|
||||
outline: 0 !important;
|
||||
font-weight: ${props => props.fontWeight
|
||||
? props.fontWeight
|
||||
: props.isBold == true ? 700 : 500};
|
||||
: props.isBold == true ? 700 : 'normal'};
|
||||
${props => props.isItalic == true && css`font-style: italic;`}
|
||||
${props => props.backgroundColor && css`background-color: ${props => props.backgroundColor};`}
|
||||
${props => props.isInline
|
||||
|
@ -4,11 +4,29 @@ import { Icons } from '../icons'
|
||||
import Heading from '../heading'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
|
||||
.span-toggle-content {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.heading-toggle-content {
|
||||
height: 24px;
|
||||
line-height: 26px;
|
||||
box-sizing: border-box;
|
||||
font-style: normal;
|
||||
|
||||
&:hover {
|
||||
border-bottom: 1px dashed;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledContent = styled.div`
|
||||
color: #333;
|
||||
display: ${props => props.isOpen ? 'block' : 'none'};
|
||||
padding-top: 9px;
|
||||
padding-top: 6px;
|
||||
`;
|
||||
|
||||
// eslint-disable-next-line react/prop-types, no-unused-vars
|
||||
@ -21,74 +39,69 @@ const Arrow = styled(IconArrow)`
|
||||
transform: ${props => props.isOpen && 'rotate(180deg)'};
|
||||
`;
|
||||
|
||||
const StyledSpan = styled.span`
|
||||
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
const StyledText = styled(Heading)`
|
||||
height: 24px;
|
||||
line-height: 26px;
|
||||
box-sizing: border-box;
|
||||
font-style: normal;
|
||||
&:hover{
|
||||
border-bottom: 1px dashed;
|
||||
}
|
||||
`;
|
||||
|
||||
class ToggleContent extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const { isOpen } = props;
|
||||
|
||||
this.state = {
|
||||
isOpen: this.props.isOpen
|
||||
isOpen
|
||||
};
|
||||
}
|
||||
|
||||
toggleContent = (isOpen) => this.setState({ isOpen: isOpen });
|
||||
toggleContent = () => this.setState({ isOpen: !this.state.isOpen });
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.isOpen !== prevProps.isOpen) {
|
||||
this.setState({ isOpen: this.props.isOpen });
|
||||
const { isOpen } = this.props;
|
||||
if (isOpen !== prevProps.isOpen) {
|
||||
this.setState({ isOpen });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
//console.log("ToggleContent render");
|
||||
// console.log("ToggleContent render");
|
||||
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
id,
|
||||
label,
|
||||
style
|
||||
} = this.props;
|
||||
|
||||
const { isOpen } = this.state;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={this.props.className}
|
||||
id={this.props.id}
|
||||
style={this.props.style}
|
||||
<StyledContainer
|
||||
className={className}
|
||||
id={id}
|
||||
style={style}
|
||||
>
|
||||
<StyledSpan onClick={() => {
|
||||
this.toggleContent(!this.state.isOpen);
|
||||
this.props.onChange && this.props.onChange(!this.state.isOpen);
|
||||
}}>
|
||||
<Arrow color="#333333" isfill={true} size='medium' isOpen={this.state.isOpen} />
|
||||
<StyledText level={2} size='small' isInline={true}>{this.props.label}</StyledText>
|
||||
</StyledSpan>
|
||||
<StyledContent isOpen={this.state.isOpen}>{this.props.children}</StyledContent>
|
||||
</div>
|
||||
<span className='span-toggle-content' onClick={this.toggleContent}>
|
||||
<Arrow color="#333" isfill={true} size='medium' isOpen={isOpen} />
|
||||
<Heading className='heading-toggle-content' level={2} size='small' isInline={true}>{label}</Heading>
|
||||
</span>
|
||||
<StyledContent isOpen={isOpen}>{children}</StyledContent>
|
||||
</StyledContainer>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ToggleContent.propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
isOpen: PropTypes.bool,
|
||||
onChange: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.any,
|
||||
className: PropTypes.string,
|
||||
id: PropTypes.string,
|
||||
isOpen: PropTypes.bool,
|
||||
label: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func,
|
||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
|
||||
}
|
||||
|
||||
ToggleContent.defaultProps = {
|
||||
isOpen: false,
|
||||
label: "Some label"
|
||||
label: ""
|
||||
}
|
||||
|
||||
export default ToggleContent;
|
||||
|
@ -10678,6 +10678,11 @@ react-lifecycles-compat@^3.0.4:
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-onclickoutside@^6.9.0:
|
||||
version "6.9.0"
|
||||
resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.9.0.tgz#a54bc317ae8cf6131a5d78acea55a11067f37a1f"
|
||||
integrity sha512-8ltIY3bC7oGhj2nPAvWOGi+xGFybPNhJM0V1H8hY/whNcXgmDeaeoCMPPd8VatrpTsUWjb/vGzrmu6SrXVty3A==
|
||||
|
||||
react-popper-tooltip@^2.8.3:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-2.10.0.tgz#4d8383644d1002a50bd2bf74b2d1214d84ffc77c"
|
||||
|
Loading…
Reference in New Issue
Block a user