Merge branch 'master' of github.com:ONLYOFFICE/CommunityServer-AspNetCore

This commit is contained in:
Alexey Safronov 2019-09-18 16:55:54 +03:00
commit c9311e53c8
12 changed files with 520 additions and 170 deletions

View File

@ -337,6 +337,7 @@ class SectionBodyContent extends React.Component {
}}
dropDownMaxHeight={200}
scaled={true}
scaledOptions={true}
size="content"
/>
</FieldContainer>

View File

@ -1,6 +1,6 @@
{
"name": "asc-web-components",
"version": "1.0.87",
"version": "1.0.90",
"description": "Ascensio System SIA component library",
"license": "AGPL-3.0",
"main": "dist/asc-web-components.js",

View File

@ -468,6 +468,7 @@ class AdvancedSelector extends React.Component {
selectedOption={currentGroup}
dropDownMaxHeight={200}
scaled={true}
scaledOptions={true}
size="content"
onSelect={this.onCurrentGroupChange}
/>

View File

@ -619,6 +619,7 @@ class Calendar extends Component {
<ComboBoxMonthStyle size={size}>
<ComboBox
scaled={true}
scaledOptions={true}
dropDownMaxHeight={dropDownSizeMonth}
onSelect={this.onSelectMonth}
selectedOption={selectedOptionMonth}
@ -629,6 +630,7 @@ class Calendar extends Component {
<ComboBoxDateStyle>
<ComboBox
scaled={true}
scaledOptions={true}
dropDownMaxHeight={dropDownSizeYear}
onSelect={this.onSelectYear}
selectedOption={selectedOptionYear}

View File

@ -83,6 +83,7 @@ const options = [
dropDownMaxHeight={200}
noBorder={false}
scale={true}
scaledOptions={true}
size='content'
onSelect={option => console.log('selected', option)}
/>
@ -90,14 +91,60 @@ const options = [
#### Properties
| Props | Type | Required | Values | Default | Description |
| ------------------- | --------- | :------: | ------------------------------------------ | ------- | --------------------------------------------------------- |
| `options` | `array` | ✅ | - | - | Combo box options |
| `isDisabled` | `bool` | - | - | `false` | Indicates that component is disabled |
| `noBorder` | `bool` | - | - | `false` | Indicates that component is displayed without borders |
| `selectedOption` | `object` | ✅ | - | - | Selected option |
| `onSelect` | `func` | - | - | - | Will be triggered whenever an ComboBox is selected option |
| `dropDownMaxHeight` | `number` | - | - | - | Height of Dropdown |
| `scaled` | `bool` | - | - | `true` | Indicates that component is scaled by parent |
| `size` | `oneOf` | - | `base`, `middle`, `big`, `huge`, `content` | `base` | Select component width, one of default |
| `advancedOptions` | `element` | - | - | - | If you need display options not basic options |
| Props | Type | Required | Values | Default | Description |
| ------------------- | --------- | :------: | ------------------------------------------ | ------- | ----------------------------------------------------------- |
| `options` | `array` | ✅ | - | - | Combo box options |
| `isDisabled` | `bool` | - | - | `false` | Indicates that component is disabled |
| `noBorder` | `bool` | - | - | `false` | Indicates that component is displayed without borders |
| `selectedOption` | `object` | ✅ | - | - | Selected option |
| `onSelect` | `func` | - | - | - | Will be triggered whenever an ComboBox is selected option |
| `dropDownMaxHeight` | `number` | - | - | - | Height of Dropdown |
| `scaled` | `bool` | - | - | `true` | Indicates that component is scaled by parent |
| `scaledOptions` | `bool` | - | - | `false` | Indicates that component`s options is scaled by ComboButton |
| `size` | `oneOf` | - | `base`, `middle`, `big`, `huge`, `content` | `base` | Select component width, one of default |
| `advancedOptions` | `element` | - | - | - | If you need display options not basic options |
## ComboButton
#### Description
> This description is for reference only, the component described below is not exported.
To create designs using combobox logic, there is a child component ComboButton.
This is an independent element that responds to changes in parameters and serves only to demonstrate set values.
```js
<ComboButton
noBorder={false}
isDisabled={false}
selectedOption={{
key: 0,
label: "Select"
}}
withOptions={false}
optionsLength={0}
withAdvancedOptions={true}
innerContainer={<>Demo container</>}
innerContainerClassName="optionalBlock"
isOpen={false}
size="content"
scaled={false}
/>
```
#### Properties
| Props | Type | Required | Values | Default | Description |
| ------------------------- | -------- | :------: | -------------------------------- | ---------------- | -------------------------------------------------------- |
| `isDisabled` | `bool` | - | - | `false` | Indicates that component is disabled |
| `noBorder` | `bool` | - | - | `false` | Indicates that component is displayed without borders |
| `selectedOption` | `object` | - | - | - | Selected option |
| `withOptions` | `bool` | - | - | `true` | Lets you style as ComboBox with options |
| `optionsLength` | `number` | - | - | - | Lets you style as ComboBox with options |
| `withAdvancedOptions` | `bool` | - | - | `false` | Lets you style as a ComboBox with advanced options |
| `innerContainer` | `node` | - | - | - | Allows displaying third-party element inside ComboButton |
| `innerContainerClassName` | `string` | - | - | `innerContainer` | Required to access third-party container |
| `isOpen` | `bool` | - | - | `false` | Lets you style as ComboBox arrow |
| `scaled` | `bool` | - | - | `false` | Indicates that component is scaled by parent |
| `size` | `oneOf` | - | `base`, `...`, `huge`, `content` | `content` | Select component width, one of default |
| `onClick` | `func` | - | - | - | Will be triggered whenever an ComboButton is clicked |

View File

@ -58,7 +58,7 @@ storiesOf('Components|Input', module)
];
const needScrollDropDown = boolean('Need scroll dropdown', false);
const dropDownMaxHeight = needScrollDropDown && number('dropDownMaxHeight', 200);
const dropDownMaxHeight = needScrollDropDown ? number('dropDownMaxHeight', 200) : null;
const optionsMultiSelect = options('children',
{
button: 'button',
@ -125,6 +125,7 @@ storiesOf('Components|Input', module)
noBorder={boolean('noBorder', false)}
dropDownMaxHeight={dropDownMaxHeight}
scaled={boolean('scaled', false)}
scaledOptions={boolean('scaledOptions', false)}
size={select('size', sizeOptions, 'content')}
>
{childrenItems}
@ -146,7 +147,6 @@ storiesOf('Components|Input', module)
>
<Icons.NavLogoIcon size="medium" key='comboIcon' />
</ComboBox>
</td>
</tr>
</tbody>

View File

@ -3,12 +3,11 @@ import PropTypes from 'prop-types'
import styled from 'styled-components';
import DropDownItem from '../drop-down-item'
import DropDown from '../drop-down'
import { Icons } from '../icons'
import { handleAnyClick } from '../../utils/event';
import isEqual from 'lodash/isEqual';
import ComboButton from './sub-components/combo-button'
const StyledComboBox = styled.div`
color: ${props => props.isDisabled ? '#D0D5DA' : '#333333'};
width: ${props =>
(props.scaled && '100%') ||
(props.size === 'base' && '173px') ||
@ -19,92 +18,6 @@ const StyledComboBox = styled.div`
};
position: relative;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background: #FFFFFF;
${props => !props.noBorder && `
border: 1px solid #D0D5DA;
border-radius: 3px;
`}
${props => props.isDisabled && !props.noBorder && `
border-color: #ECEEF1;
background: #F8F9F9;
`}
${props => !props.noBorder && `
height: 32px;
`}
:hover{
border-color: ${state => state.isOpen ? '#2DA7DB' : '#A3A9AE' };
cursor: ${props => (props.isDisabled || !props.options.length ) ? (props.advancedOptions) ? 'pointer' : 'default' : 'pointer'};
${props => props.isDisabled && `
border-color: #ECEEF1;
`}
}
`;
const StyledComboButton = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: ${props => props.noBorder ? `18px` : `30px`};
margin-left: 8px;
`;
const StyledIcon = styled.div`
width: 16px;
margin-right: 8px;
margin-top: -2px;
`;
const StyledOptionalItem = styled.div`
margin-right: 8px;
`;
const StyledLabel = styled.div`
font-family: Open Sans;
font-style: normal;
font-weight: 600;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 8px;
${props => props.noBorder && `
line-height: 11px;
border-bottom: 1px dashed transparent;
:hover{
border-bottom: 1px dashed;
}
`};
`;
const StyledArrowIcon = styled.div`
display: flex;
align-self: start;
width: ${props => props.needDisplay ? '8px' : '0px'};
flex: 0 0 ${props => props.needDisplay ? '8px' : '0px'};
margin-top: ${props => props.noBorder ? `5px` : `12px`};
margin-right: ${props => props.needDisplay ? '8px' : '0px'};
margin-left: ${props => props.needDisplay ? 'auto' : '0px'};
${props => props.isOpen && `
transform: scale(1, -1);
`}
`;
class ComboBox extends React.Component {
@ -137,11 +50,11 @@ class ComboBox extends React.Component {
};
optionClick = (option) => {
this.toggle(!this.state.isOpen);
this.setState({
isOpen: !this.state.isOpen,
selectedOption: option
});
this.props.onSelect && this.props.onSelect(option);
};
@ -149,7 +62,7 @@ class ComboBox extends React.Component {
handleAnyClick(false, this.handleClick);
}
shouldComponentUpdate(nextProps,nextState) {
shouldComponentUpdate(nextProps, nextState) {
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
}
@ -171,61 +84,57 @@ class ComboBox extends React.Component {
//console.log("ComboBox render");
const {
dropDownMaxHeight,
isDisabled,
directionX,
directionY,
scaled,
children,
size,
options,
advancedOptions,
isDisabled,
children,
noBorder,
advancedOptions
} = this.props;
scaledOptions } = this.props;
const { isOpen, selectedOption } = this.state;
const dropDownMaxHeightProp = dropDownMaxHeight ? { maxHeight: dropDownMaxHeight } : {};
const dropDownManualWidthProp = scaled ? { manualWidth: '100%' } : {};
const boxIconColor = isDisabled ? '#D0D5DA' : '#333333';
const arrowIconColor = isDisabled ? '#D0D5DA' : '#A3A9AE';
const dropDownMaxHeightProp = dropDownMaxHeight
? { maxHeight: dropDownMaxHeight }
: {};
const dropDownManualWidthProp = scaledOptions
? { manualWidth: '100%' }
: {};
const optionsLength = options.length
? options.length
: 0;
const advancedOptionsLength = advancedOptions
&& advancedOptions.props.children.length
? advancedOptions.props.children.length
: 0;
return (
<StyledComboBox ref={this.ref}
{...this.props}
{...this.state}
<StyledComboBox
ref={this.ref}
isDisabled={isDisabled}
scaled={scaled}
size={size}
data={selectedOption}
onClick={this.comboBoxClick}
onSelect={this.stopAction}
{...this.props}
>
<StyledComboButton noBorder={noBorder}>
{children &&
<StyledOptionalItem className='optionalBlock'>
{children}
</StyledOptionalItem>
}
{selectedOption && selectedOption.icon &&
<StyledIcon>
{React.createElement(Icons[selectedOption.icon],
{
size: 'scale',
color: boxIconColor,
isfill: true
})
}
</StyledIcon>
}
<StyledLabel noBorder={noBorder}>
{selectedOption.label}
</StyledLabel>
<StyledArrowIcon needDisplay={options.length > 0 || advancedOptions !== undefined} noBorder={noBorder} isOpen={isOpen}>
{(options.length > 0 || advancedOptions !== undefined) &&
React.createElement(Icons['ExpanderDownIcon'],
{
size: 'scale',
color: arrowIconColor,
isfill: true
})
}
</StyledArrowIcon>
</StyledComboButton>
<ComboButton
noBorder={noBorder}
isDisabled={isDisabled}
selectedOption={selectedOption}
withOptions={optionsLength > 0}
optionsLength={optionsLength}
withAdvancedOptions={advancedOptionsLength > 0}
innerContainer={children}
innerContainerClassName='optionalBlock'
isOpen={isOpen}
size={size}
scaled={scaled}
/>
<DropDown
directionX={directionX}
directionY={directionY}
@ -235,14 +144,16 @@ class ComboBox extends React.Component {
{...dropDownManualWidthProp}
>
{advancedOptions
? advancedOptions
: options.map((option) =>
<DropDownItem {...option}
key={option.key}
disabled={option.disabled || (option.label === selectedOption.label)}
onClick={this.optionClick.bind(this, option)}
/>
)}
? advancedOptions
: options.map((option) =>
<DropDownItem {...option}
key={option.key}
disabled={
option.disabled
|| (option.label === selectedOption.label)}
onClick={this.optionClick.bind(this, option)}
/>
)}
</DropDown>
</StyledComboBox>
);
@ -264,14 +175,16 @@ ComboBox.propTypes = {
size: PropTypes.oneOf(['base', 'middle', 'big', 'huge', 'content']),
directionX: PropTypes.oneOf(['left', 'right']),
directionY: PropTypes.oneOf(['bottom', 'top']),
scaled: PropTypes.bool
scaled: PropTypes.bool,
scaledOptions: PropTypes.bool
}
ComboBox.defaultProps = {
noBorder: false,
isDisabled: false,
size: 'base',
scaled: true
scaled: true,
scaledOptions: false
}
export default ComboBox;

View File

@ -0,0 +1,202 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components';
import { Icons } from '../../icons'
const StyledComboButton = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: ${props => props.noBorder ? `18px` : `30px`};
width: ${props =>
(props.scaled && '100%') ||
(props.size === 'base' && '173px') ||
(props.size === 'middle' && '300px') ||
(props.size === 'big' && '350px') ||
(props.size === 'huge' && '500px') ||
(props.size === 'content' && 'fit-content')
};
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
padding-left: 8px;
background: ${props => !props.noBorder ? '#FFFFFF' : 'none'};
color: ${props => props.isDisabled ? '#D0D5DA' : '#333333'};
${props => !props.noBorder && `
border: 1px solid #D0D5DA;
border-radius: 3px;
`}
${props => props.isDisabled && !props.noBorder && `
border-color: #ECEEF1;
background: #F8F9F9;
`}
${props => !props.noBorder && `
height: 32px;
`}
:hover{
border-color: ${props => props.isOpen ? '#2DA7DB' : '#A3A9AE'};
cursor: ${props => (props.isDisabled || !props.containOptions) ? (props.advancedOptions) ? 'pointer' : 'default' : 'pointer'};
${props => props.isDisabled && `
border-color: #ECEEF1;
`}
}
`;
const StyledOptionalItem = styled.div`
margin-right: 8px;
`;
const StyledIcon = styled.div`
width: 16px;
margin-right: 8px;
margin-top: -2px;
`;
const StyledLabel = styled.div`
font-family: Open Sans;
font-style: normal;
font-weight: 600;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 8px;
${props => props.noBorder && `
line-height: 11px;
border-bottom: 1px dashed transparent;
:hover{
border-bottom: 1px dashed;
}
`};
`;
const StyledArrowIcon = styled.div`
display: flex;
align-self: start;
width: ${props => props.needDisplay ? '8px' : '0px'};
flex: 0 0 ${props => props.needDisplay ? '8px' : '0px'};
margin-top: ${props => props.noBorder ? `5px` : `12px`};
margin-right: ${props => props.needDisplay ? '8px' : '0px'};
margin-left: ${props => props.needDisplay ? 'auto' : '0px'};
${props => props.isOpen && `
transform: scale(1, -1);
`}
`;
class ComboButton extends React.Component {
render() {
const {
noBorder,
onClick,
isDisabled,
innerContainer,
innerContainerClassName,
selectedOption,
optionsLength,
withOptions,
withAdvancedOptions,
isOpen,
scaled,
size } = this.props;
const boxIconColor = isDisabled ? '#D0D5DA' : '#333333';
const arrowIconColor = isDisabled ? '#D0D5DA' : '#A3A9AE';
return (
<StyledComboButton
isOpen={isOpen}
isDisabled={isDisabled}
noBorder={noBorder}
containOptions={optionsLength}
onClick={onClick}
scaled={scaled}
size={size}
>
{innerContainer &&
<StyledOptionalItem className={innerContainerClassName}>
{innerContainer}
</StyledOptionalItem>
}
{selectedOption && selectedOption.icon &&
<StyledIcon>
{React.createElement(Icons[selectedOption.icon],
{
size: 'scale',
color: boxIconColor,
isfill: true
})
}
</StyledIcon>
}
<StyledLabel noBorder={noBorder}>
{selectedOption.label}
</StyledLabel>
<StyledArrowIcon
needDisplay={withOptions || withAdvancedOptions}
noBorder={noBorder}
isOpen={isOpen}>
{(withOptions || withAdvancedOptions) &&
React.createElement(Icons['ExpanderDownIcon'],
{
size: 'scale',
color: arrowIconColor,
isfill: true
})
}
</StyledArrowIcon>
</StyledComboButton>
);
}
}
ComboButton.propTypes = {
noBorder: PropTypes.bool,
isDisabled: PropTypes.bool,
selectedOption: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.object),
PropTypes.object
]),
withOptions: PropTypes.bool,
optionsLength: PropTypes.number,
withAdvancedOptions: PropTypes.bool,
innerContainer: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
innerContainerClassName: PropTypes.string,
isOpen: PropTypes.bool,
size: PropTypes.oneOf(['base', 'middle', 'big', 'huge', 'content']),
scaled: PropTypes.bool,
onClick: PropTypes.func
}
ComboButton.defaultProps = {
noBorder: false,
isDisabled: false,
withOptions: true,
withAdvancedOptions: false,
innerContainerClassName: 'innerContainer',
isOpen: false,
size: 'content',
scaled: false
}
export default ComboButton;

View File

@ -57,7 +57,7 @@ class DatePicker extends Component {
if (
!isNaN(date) &&
this.compareDates(date) &&
this.compareDate(date) &&
targetValue.indexOf("_") === -1
) {
//console.log("Mask complete");
@ -94,7 +94,7 @@ class DatePicker extends Component {
}
};
compareDates = date => {
compareDate = date => {
const { minDate, maxDate } = this.props;
if (date < minDate || date > maxDate) {
return false;

View File

@ -11,6 +11,7 @@ import ModalDialog from "../modal-dialog";
import FieldContainer from "../field-container";
import TextInput from "../text-input";
import ComboBox from "../combobox";
import ComboButton from '../combobox/sub-components/combo-button'
const groups = [
{
@ -263,6 +264,7 @@ storiesOf("EXAMPLES|AdvancedSelector", module)
}}
dropDownMaxHeight={200}
scaled={true}
scaledOptions={true}
size="content"
/>
</FieldContainer>
@ -292,4 +294,186 @@ storiesOf("EXAMPLES|AdvancedSelector", module)
</BooleanValue>
</Section>
);
})
.add("people user selector as advanced ComboBox", () => {
const optionsCount = number("Users count", 1000);
const options = Array.from({ length: optionsCount }, (v, index) => {
const additional_group = groups[getRandomInt(1, 6)];
groups[0].total++;
additional_group.total++;
return {
key: `user${index}`,
groups: ["group-all", additional_group.key],
label: `User${index + 1} (All groups, ${additional_group.label})`
};
});
let selectedOptionsHead = [];
const getSelectedOption = (count, maxCount) => {
return {
key: 0,
//icon: 'icon_name', //if you need insert ComboBox styled image
label: `Selected (${count}/${maxCount})`
}
}
return (
<Section>
<BooleanValue
defaultValue={false}
onChange={() => action("modalVisible changed")}
>
{({ value: modalVisible, toggle: toggleModalVisible }) => (
<BooleanValue
defaultValue={true}
onChange={() => action("isOpen changed")}
>
{({ value: isOpen, toggle }) => (
<div style={{ position: "relative" }}>
<ComboButton
label="Toggle dropdown"
options={options}
isOpen={isOpen}
selectedOption={getSelectedOption(selectedOptionsHead.length, options.length)}
//innerContainer={react.node} // if you need insert custom node element inside ComboBox
onClick={toggle}
/>
<ArrayValue
defaultValue={options}
onChange={() => action("options onChange")}
>
{({ value, set }) => (
<>
<AdvancedSelector
isDropDown={true}
isOpen={isOpen}
size="full"
placeholder={text("placeholder", "Search")}
onSearchChanged={value => {
action("onSearchChanged")(value);
set(
options.filter(option => {
return option.label.indexOf(value) > -1;
})
);
}}
options={value}
groups={groups}
isMultiSelect={boolean("isMultiSelect", true)}
buttonLabel={text("buttonLabel", "Add departments")}
selectAllLabel={text("selectAllLabel", "Select all")}
onSelect={selectedOptions => {
action("onSelect")(selectedOptions);
selectedOptionsHead = selectedOptions;
toggle();
}}
onCancel={toggle}
allowCreation={boolean("allowCreation", true)}
onAddNewClick={toggleModalVisible}
allowAnyClickClose={!modalVisible}
/>
<ModalDialog
zIndex={1001}
visible={modalVisible}
headerContent="New User"
bodyContent={
<div className="create_new_user_modal">
<FieldContainer
isVertical={true}
isRequired={true}
hasError={false}
labelText={"First name:"}
>
<TextInput
value={""}
hasError={false}
className="firstName-input"
scale={true}
autoComplete="off"
onChange={e => {
//set(e.target.value);
}}
/>
</FieldContainer>
<FieldContainer
isVertical={true}
isRequired={true}
hasError={false}
labelText={"Last name:"}
>
<TextInput
value={""}
hasError={false}
className="lastName-input"
scale={true}
autoComplete="off"
onChange={e => {
//set(e.target.value);
}}
/>
</FieldContainer>
<FieldContainer
isVertical={true}
isRequired={true}
hasError={false}
labelText={"E-mail:"}
>
<TextInput
value={""}
hasError={false}
className="email-input"
scale={true}
autoComplete="off"
onChange={e => {
//set(e.target.value);
}}
/>
</FieldContainer>
<FieldContainer
isVertical={true}
isRequired={true}
hasError={false}
labelText={"Group:"}
>
<ComboBox
options={groups}
className="group-input"
onSelect={option =>
console.log("Selected option", option)
}
selectedOption={{
key: 0,
label: "Select"
}}
dropDownMaxHeight={200}
scaled={true}
size="content"
scaledOptions={true}
/>
</FieldContainer>
</div>
}
footerContent={[
<Button
key="CreateBtn"
label="Create"
primary={true}
size="big"
onClick={e => {
console.log("CreateBtn click", e);
toggleModalVisible();
}}
/>
]}
onClose={toggleModalVisible}
/>
</>
)}
</ArrayValue>
</div>
)}
</BooleanValue>
)}
</BooleanValue>
</Section>
);
});

View File

@ -120,10 +120,9 @@ class SortComboBox extends React.Component {
advancedOptions={advancedOptions}
isDisabled={this.props.isDisabled}
selectedOption={this.props.selectedOption}
scaled={false}
scaled={true}
size="content"
directionX="right"
>
<StyledIconButton sortDirection={!!this.state.sortDirection}>
<IconButton

View File

@ -82,6 +82,7 @@ const Paging = props => {
<StyledOnPage>
<ComboBox
directionY={openDirection}
directionX='right'
options={countItems}
onSelect={onSelectCountAction}
selectedOption={selectedCountItem}/>