Merge branch 'master' into feature/asc-web-common
# Conflicts: # web/ASC.Web.Client/src/components/pages/Settings/Layout/index.js
This commit is contained in:
commit
d13e729282
@ -352,7 +352,7 @@ class ProfileInfo extends React.PureComponent {
|
||||
offsetLeft={50}
|
||||
offsetRight={0}
|
||||
tooltipContent={tooltipLanguage}
|
||||
HelpButtonHeaderContent={t('Language')}
|
||||
helpButtonHeaderContent={t('Language')}
|
||||
/>
|
||||
</TooltipIcon>
|
||||
|
||||
|
@ -22,7 +22,7 @@ class RadioField extends React.Component {
|
||||
radioOnChange,
|
||||
|
||||
tooltipContent,
|
||||
HelpButtonHeaderContent
|
||||
helpButtonHeaderContent
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -31,7 +31,7 @@ class RadioField extends React.Component {
|
||||
hasError={hasError}
|
||||
labelText={labelText}
|
||||
tooltipContent={tooltipContent}
|
||||
HelpButtonHeaderContent={HelpButtonHeaderContent}
|
||||
helpButtonHeaderContent={helpButtonHeaderContent}
|
||||
>
|
||||
<RadioButtonGroup
|
||||
name={radioName}
|
||||
|
@ -33,7 +33,7 @@ class TextChangeField extends React.Component {
|
||||
buttonTabIndex,
|
||||
|
||||
tooltipContent,
|
||||
HelpButtonHeaderContent
|
||||
helpButtonHeaderContent
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -42,7 +42,7 @@ class TextChangeField extends React.Component {
|
||||
hasError={hasError}
|
||||
labelText={labelText}
|
||||
tooltipContent={tooltipContent}
|
||||
HelpButtonHeaderContent={HelpButtonHeaderContent}
|
||||
helpButtonHeaderContent={helpButtonHeaderContent}
|
||||
>
|
||||
<InputContainer>
|
||||
<TextInput
|
||||
|
@ -22,7 +22,7 @@ class TextField extends React.Component {
|
||||
inputAutoFocussed,
|
||||
inputTabIndex,
|
||||
tooltipContent,
|
||||
HelpButtonHeaderContent
|
||||
helpButtonHeaderContent
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -31,7 +31,7 @@ class TextField extends React.Component {
|
||||
hasError={hasError}
|
||||
labelText={labelText}
|
||||
tooltipContent={tooltipContent}
|
||||
HelpButtonHeaderContent={HelpButtonHeaderContent}
|
||||
helpButtonHeaderContent={helpButtonHeaderContent}
|
||||
>
|
||||
<TextInput
|
||||
name={inputName}
|
||||
|
@ -371,7 +371,7 @@ class CreateUserForm extends React.Component {
|
||||
inputOnChange={this.onInputChange}
|
||||
inputTabIndex={3}
|
||||
|
||||
HelpButtonHeaderContent={t("Mail")}
|
||||
helpButtonHeaderContent={t("Mail")}
|
||||
tooltipContent={
|
||||
<Trans i18nKey="EmailPopupHelper" i18n={i18n}>
|
||||
The main e-mail is needed to restore access to the portal in case of loss of the password and send notifications. <p className="tooltip_email" style={{marginTop: "1rem", marginBottom: "1rem"}} >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.</p> The main e-mail can be used as a login when logging in to the portal.
|
||||
|
@ -443,35 +443,70 @@ class UpdateUserForm extends React.Component {
|
||||
const contacts = getUserContacts(profile.contacts);
|
||||
const tooltipTypeContent =
|
||||
<>
|
||||
<Text.Body style={{paddingBottom: 17}} fontSize={13}>{t("ProfileTypePopupHelper")}</Text.Body>
|
||||
<Table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<Th>{t("ProductsAndInstruments_Products")}</Th><Th>{t("Employee")}</Th><Th>{t("GuestCaption")}</Th>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("Mail")}</Td><Td>review</Td><Td>-</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("DocumentsProduct")}</Td><Td>full access</Td><Td>view</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("ProjectsProduct")}</Td><Td>review</Td><Td>-</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("CommunityProduct")}</Td><Td>full access</Td><Td>view</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("People")}</Td><Td>review</Td><Td>-</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("Message")}</Td><Td>review</Td><Td>review</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("Calendar")}</Td><Td>review</Td><Td>review</Td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</Table>
|
||||
<Text.Body
|
||||
style={{paddingBottom: 17}}
|
||||
fontSize={13}>
|
||||
{t("ProfileTypePopupHelper")}
|
||||
</Text.Body>
|
||||
|
||||
<Text.Body fontSize={12}>
|
||||
<Table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<Th>
|
||||
<Text.Body isBold fontSize={13}>
|
||||
{t("ProductsAndInstruments_Products")}
|
||||
</Text.Body>
|
||||
</Th>
|
||||
<Th>
|
||||
<Text.Body isBold fontSize={13}>
|
||||
{t("Employee")}
|
||||
</Text.Body>
|
||||
</Th>
|
||||
<Th>
|
||||
<Text.Body isBold fontSize={13}>
|
||||
{t("GuestCaption")}
|
||||
</Text.Body>
|
||||
</Th>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("Mail")}</Td>
|
||||
<Td>review</Td>
|
||||
<Td>-</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("DocumentsProduct")}</Td>
|
||||
<Td>full access</Td>
|
||||
<Td>view</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("ProjectsProduct")}</Td>
|
||||
<Td>review</Td>
|
||||
<Td>-</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("CommunityProduct")}</Td>
|
||||
<Td>full access</Td>
|
||||
<Td>view</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("People")}</Td>
|
||||
<Td>review</Td>
|
||||
<Td>-</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("Message")}</Td>
|
||||
<Td>review</Td>
|
||||
<Td>review</Td>
|
||||
</tr>
|
||||
<tr>
|
||||
<Td>{t("Calendar")}</Td>
|
||||
<Td>review</Td>
|
||||
<Td>review</Td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</Table>
|
||||
</Text.Body>
|
||||
<Link
|
||||
color="#316DAA"
|
||||
isHovered={true}
|
||||
@ -517,11 +552,18 @@ class UpdateUserForm extends React.Component {
|
||||
buttonOnClick={this.onEmailChange}
|
||||
buttonTabIndex={1}
|
||||
|
||||
HelpButtonHeaderContent={t("Mail")}
|
||||
helpButtonHeaderContent={t("Mail")}
|
||||
tooltipContent={
|
||||
<Trans i18nKey="EmailPopupHelper" i18n={i18n}>
|
||||
The main e-mail is needed to restore access to the portal in case of loss of the password and send notifications. <p style={{height: "0", visibility: "hidden"}}>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.</p> The main e-mail can be used as a login when logging in to the portal.
|
||||
</Trans>
|
||||
<Text.Body fontSize={13}>
|
||||
<Trans i18nKey="EmailPopupHelper" i18n={i18n}>
|
||||
The main e-mail is needed to restore access to the portal in case of loss of the password and send notifications.
|
||||
<p style={{marginTop: "1rem"/*, height: "0", visibility: "hidden"*/}}>
|
||||
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.
|
||||
</p>
|
||||
The main e-mail can be used as a login when logging in to the portal.
|
||||
</Trans>
|
||||
</Text.Body>
|
||||
}
|
||||
/>
|
||||
<TextChangeField
|
||||
@ -595,7 +637,7 @@ class UpdateUserForm extends React.Component {
|
||||
radioOnChange={this.onUserTypeChange}
|
||||
|
||||
tooltipContent={tooltipTypeContent}
|
||||
HelpButtonHeaderContent={t('UserType')}
|
||||
helpButtonHeaderContent={t('UserType')}
|
||||
/>
|
||||
<DateField
|
||||
calendarHeaderContent={t("CalendarSelectDate")}
|
||||
|
@ -178,7 +178,7 @@ class Customization extends React.Component {
|
||||
className='margin-top field-container-width'
|
||||
labelText={`${t("Language")}:`}
|
||||
tooltipContent={tooltipLanguage}
|
||||
HelpButtonHeaderContent={t("Language")}
|
||||
helpButtonHeaderContent={t("Language")}
|
||||
isVertical={true}>
|
||||
<ComboBox
|
||||
id='comboBoxLanguage'
|
||||
|
@ -1,9 +1,8 @@
|
||||
import React, { lazy } from "react";
|
||||
import React from "react";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { withRouter } from "react-router";
|
||||
|
||||
const CustomizationSettings = lazy(() => import("./customization"));
|
||||
const WhiteLabel = lazy(() => import("./whitelabel"));
|
||||
import CustomizationSettings from "./customization";
|
||||
import WhiteLabel from "./whitelabel";
|
||||
|
||||
const Common = ({ match }) => {
|
||||
const basePath = '/settings/common';
|
||||
@ -15,13 +14,11 @@ const Common = ({ match }) => {
|
||||
path={[`${basePath}/customization`, '/common', match.path]}
|
||||
component={CustomizationSettings}
|
||||
/>
|
||||
|
||||
<Route
|
||||
exact
|
||||
path={`${basePath}/whitelabel`}
|
||||
component={WhiteLabel}
|
||||
/>
|
||||
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { Component, lazy } from "react";
|
||||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router";
|
||||
import i18n from "../../i18n";
|
||||
@ -6,9 +6,9 @@ import { I18nextProvider, withTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { TabContainer } from "asc-web-components";
|
||||
|
||||
const OwnerSettings = lazy(() => import("./sub-components/owner"));
|
||||
const AdminsSettings = lazy(() => import("./sub-components/admins"));
|
||||
const ModulesSettings = lazy(() => import("./sub-components/modules"));
|
||||
import OwnerSettings from "./sub-components/owner";
|
||||
import AdminsSettings from "./sub-components/admins";
|
||||
import ModulesSettings from "./sub-components/modules";
|
||||
|
||||
const MainContainer = styled.div`
|
||||
padding-bottom: 16px;
|
||||
|
@ -31,12 +31,6 @@ import {
|
||||
import { getUserRole } from "../../../../../../store/settings/selectors";
|
||||
import isEmpty from "lodash/isEmpty";
|
||||
|
||||
const AdminsContainer = styled.div`
|
||||
.hidden-icon {
|
||||
position: fixed;
|
||||
visibility: hidden;
|
||||
}
|
||||
`;
|
||||
const ToggleContentContainer = styled.div`
|
||||
.buttons_container {
|
||||
display: flex;
|
||||
@ -337,10 +331,7 @@ class PureAdminsSettings extends Component {
|
||||
console.log("Admins render_");
|
||||
|
||||
return (
|
||||
/*TODO: delete after resolve icon button problem*/
|
||||
<AdminsContainer>
|
||||
<IconButton className="hidden-icon" iconName="SearchIcon" />
|
||||
|
||||
<>
|
||||
{showLoader ? (
|
||||
<Loader className="pageLoader" type="rombs" size={40} />
|
||||
) : (
|
||||
@ -528,7 +519,7 @@ class PureAdminsSettings extends Component {
|
||||
</ToggleContentContainer>
|
||||
</>
|
||||
)}
|
||||
</AdminsContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,29 @@
|
||||
import React, { lazy } from "react";
|
||||
import React from "react";
|
||||
import { Route, Switch, Redirect } from "react-router-dom";
|
||||
import { withRouter } from "react-router";
|
||||
import Layout from './Layout';
|
||||
|
||||
const CommonSettings = lazy(() => import("./categories/common"));
|
||||
const SecuritySettings = lazy(() => import("./categories/security"));
|
||||
|
||||
import CommonSettings from "./categories/common";
|
||||
import SecuritySettings from "./categories/security";
|
||||
|
||||
const Settings = () => {
|
||||
|
||||
const basePath = '/settings';
|
||||
|
||||
return (
|
||||
<Layout key='1'>
|
||||
<Switch>
|
||||
|
||||
<Route
|
||||
path={`${basePath}/security`}
|
||||
component={SecuritySettings}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path={[`${basePath}/common`, basePath]}
|
||||
component={CommonSettings}
|
||||
/>
|
||||
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: "/error/404",
|
||||
}}
|
||||
/>
|
||||
|
||||
</Switch>
|
||||
</Layout>
|
||||
);
|
||||
|
@ -275,7 +275,7 @@ const Form = props => {
|
||||
/>
|
||||
<TooltipStyle>
|
||||
<HelpButton
|
||||
HelpButtonHeaderContent={t('CookieSettingsTitle')}
|
||||
helpButtonHeaderContent={t('CookieSettingsTitle')}
|
||||
tooltipContent={
|
||||
<Text.Body fontSize={12}>{t("RememberHelper")}</Text.Body>
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-components",
|
||||
"version": "1.0.185",
|
||||
"version": "1.0.190",
|
||||
"description": "Ascensio System SIA component library",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/asc-web-components.js",
|
||||
@ -97,6 +97,7 @@
|
||||
"dependencies": {
|
||||
"bootstrap": "^4.3.1",
|
||||
"email-addresses": "^3.0.3",
|
||||
"html-to-react": "^1.4.2",
|
||||
"lodash": "4.17.15",
|
||||
"lodash-es": "4.17.15",
|
||||
"moment": "^2.24.0",
|
||||
|
@ -25,6 +25,8 @@ class AvatarEditor extends React.Component {
|
||||
this.onLoadFileError = this.onLoadFileError.bind(this);
|
||||
this.onLoadFile = this.onLoadFile.bind(this);
|
||||
this.onPositionChange = this.onPositionChange.bind(this);
|
||||
this.onSizeChange = this.onSizeChange.bind(this);
|
||||
|
||||
this.onDeleteImage = this.onDeleteImage.bind(this);
|
||||
}
|
||||
|
||||
@ -40,6 +42,9 @@ class AvatarEditor extends React.Component {
|
||||
})
|
||||
if (typeof this.props.onDeleteImage === 'function') this.props.onDeleteImage();
|
||||
}
|
||||
onSizeChange(data){
|
||||
this.setState(data);
|
||||
}
|
||||
onPositionChange(data) {
|
||||
this.setState(data);
|
||||
}
|
||||
@ -83,6 +88,7 @@ class AvatarEditor extends React.Component {
|
||||
<AvatarEditorBody
|
||||
onImageChange={this.onImageChange}
|
||||
onPositionChange={this.onPositionChange}
|
||||
onSizeChange={this.onSizeChange}
|
||||
onLoadFileError={this.onLoadFileError}
|
||||
onLoadFile={this.onLoadFile}
|
||||
deleteImage={this.onDeleteImage}
|
||||
|
@ -190,6 +190,10 @@ class AvatarEditorBody extends React.Component {
|
||||
this.setState({
|
||||
scale: scale < 1 ? 1 : scale > 5 ? 5 : scale
|
||||
});
|
||||
this.props.onSizeChange({
|
||||
width: this.setEditorRef.current.getImage().width,
|
||||
height: this.setEditorRef.current.getImage().height
|
||||
});
|
||||
}
|
||||
}
|
||||
onTouchEnd(evt) {
|
||||
@ -217,6 +221,10 @@ class AvatarEditorBody extends React.Component {
|
||||
this.setState({
|
||||
scale: scale < 1 ? 1 : scale > 5 ? 5 : scale
|
||||
});
|
||||
this.props.onSizeChange({
|
||||
width: this.setEditorRef.current.getImage().width,
|
||||
height: this.setEditorRef.current.getImage().height
|
||||
});
|
||||
}
|
||||
|
||||
handleScale = e => {
|
||||
@ -319,6 +327,7 @@ class AvatarEditorBody extends React.Component {
|
||||
AvatarEditorBody.propTypes = {
|
||||
onImageChange: PropTypes.func,
|
||||
onPositionChange: PropTypes.func,
|
||||
onSizeChange: PropTypes.func,
|
||||
onLoadFileError: PropTypes.func,
|
||||
onLoadFile: PropTypes.func,
|
||||
deleteImage: PropTypes.func,
|
||||
|
@ -22,6 +22,6 @@ import { FieldContainer } from "asc-web-components";
|
||||
| `isRequired` | `bool` | - | - | `false` | Indicates that the field is required to fill |
|
||||
| `hasError` | `bool` | - | - | `false` | Indicates that the field is incorrect |
|
||||
| `labelText` | `string` | - | - | - | Field label text |
|
||||
| `tooltipContent` | `object`,`string` | ✅ | - | - | Tooltip content |
|
||||
| `HelpButtonHeaderContent` | `string` | - | - | - | Tooltip header content (tooltip opened in aside) |
|
||||
| `tooltipContent` | `object`,`string` | - | - | - | Tooltip content |
|
||||
| `helpButtonHeaderContent` | `string` | - | - | - | Tooltip header content (tooltip opened in aside) |
|
||||
| `horLabelWidth` | `string` | - | - | `110px` | Label width in horizontal alignment |
|
||||
|
@ -13,33 +13,6 @@ storiesOf("Components|FieldContainer", module)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add("base", () => (
|
||||
<StringValue
|
||||
onChange={e => {
|
||||
action("onChange")(e);
|
||||
}}
|
||||
>
|
||||
{({ value, set }) => (
|
||||
<Section>
|
||||
<FieldContainer
|
||||
isVertical={boolean("isVertical", false)}
|
||||
isRequired={boolean("isRequired", false)}
|
||||
hasError={boolean("hasError", false)}
|
||||
labelText={text("labelText", "Name:")}
|
||||
>
|
||||
<TextInput
|
||||
value={value}
|
||||
hasError={boolean("hasError", false)}
|
||||
className="field-input"
|
||||
onChange={e => {
|
||||
set(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</Section>
|
||||
)}
|
||||
</StringValue>
|
||||
))
|
||||
.add("with tooltip", () => (
|
||||
<StringValue
|
||||
onChange={e => {
|
||||
action("onChange")(e);
|
||||
@ -53,26 +26,9 @@ storiesOf("Components|FieldContainer", module)
|
||||
isRequired={boolean("isRequired", false)}
|
||||
hasError={boolean("hasError", false)}
|
||||
labelText={text("labelText", "Name:")}
|
||||
tooltipContent={"Paste you tooltip content here"}
|
||||
place="top"
|
||||
>
|
||||
<TextInput
|
||||
value={value}
|
||||
hasError={boolean("hasError", false)}
|
||||
className="field-input"
|
||||
onChange={e => {
|
||||
set(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</div>
|
||||
<div style={{ marginTop: 200, marginLeft: 50 }}>
|
||||
<FieldContainer
|
||||
isVertical={boolean("isVertical", false)}
|
||||
isRequired={boolean("isRequired", false)}
|
||||
hasError={boolean("hasError", false)}
|
||||
labelText={text("labelText", "Name:")}
|
||||
tooltipContent={"Paste you tooltip content here"}
|
||||
horLabelWidth={text("horLabelWidth", "110px")}
|
||||
tooltipContent={text("tooltipContent", "Paste you tooltip content here")}
|
||||
helpButtonHeaderContent={text("helpButtonHeaderContent", "Tooltip header")}
|
||||
place="top"
|
||||
>
|
||||
<TextInput
|
||||
|
@ -85,7 +85,7 @@ class FieldContainer extends React.Component {
|
||||
children,
|
||||
tooltipContent,
|
||||
place,
|
||||
HelpButtonHeaderContent,
|
||||
helpButtonHeaderContent,
|
||||
horLabelWidth
|
||||
} = this.props;
|
||||
|
||||
@ -103,7 +103,7 @@ class FieldContainer extends React.Component {
|
||||
<HelpButton
|
||||
tooltipContent={tooltipContent}
|
||||
place={place}
|
||||
HelpButtonHeaderContent={HelpButtonHeaderContent}
|
||||
helpButtonHeaderContent={helpButtonHeaderContent}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@ -128,7 +128,7 @@ FieldContainer.propTypes = {
|
||||
]),
|
||||
tooltipContent: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
place: PropTypes.string,
|
||||
HelpButtonHeaderContent: PropTypes.string,
|
||||
helpButtonHeaderContent: PropTypes.string,
|
||||
horLabelWidth: PropTypes.string
|
||||
};
|
||||
|
||||
|
@ -52,4 +52,4 @@ import { HelpButton } from "asc-web-components";
|
||||
| `tooltipContent` | `object`,`string` | ✅ | - | - | Tooltip content |
|
||||
| `place` | `string` | - | `top`, `right`, `bottom`, `left` | `top` | Tooltip placement |
|
||||
| `displayType` | `oneOf` | - | `dropdown`, `aside`, `auto` | `auto` | Tooltip display type |
|
||||
| `HelpButtonHeaderContent` | `string` | - | - | - | Tooltip header content (tooltip opened in aside) |
|
||||
| `helpButtonHeaderContent` | `string` | - | - | - | Tooltip header content (tooltip opened in aside) |
|
||||
|
@ -36,7 +36,7 @@ storiesOf("Components|Buttons", module)
|
||||
/>
|
||||
<HelpButton
|
||||
displayType="aside"
|
||||
HelpButtonHeaderContent="Aside position HelpButton"
|
||||
helpButtonHeaderContent="Aside position HelpButton"
|
||||
tooltipContent={
|
||||
<Text.Body>
|
||||
You tooltip content with{" "}
|
||||
@ -51,7 +51,7 @@ storiesOf("Components|Buttons", module)
|
||||
/>
|
||||
<HelpButton
|
||||
displayType="auto"
|
||||
HelpButtonHeaderContent="Auto position HelpButton"
|
||||
helpButtonHeaderContent="Auto position HelpButton"
|
||||
tooltipContent={
|
||||
<>
|
||||
<p>You can put every thing here</p>
|
||||
|
@ -125,7 +125,7 @@ class HelpButton extends React.Component {
|
||||
offsetRight,
|
||||
offsetLeft,
|
||||
zIndex,
|
||||
HelpButtonHeaderContent
|
||||
helpButtonHeaderContent
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -156,13 +156,16 @@ class HelpButton extends React.Component {
|
||||
<Backdrop onClick={this.onClose} visible={isOpen} zIndex={zIndex} />
|
||||
<Aside visible={isOpen} scale={false} zIndex={zIndex}>
|
||||
<Content>
|
||||
<Header>
|
||||
<HeaderText>
|
||||
<Text.Body isBold={true} fontSize={21}>
|
||||
{HelpButtonHeaderContent}
|
||||
</Text.Body>
|
||||
</HeaderText>
|
||||
</Header>
|
||||
{
|
||||
helpButtonHeaderContent &&
|
||||
<Header>
|
||||
<HeaderText>
|
||||
<Text.Body isBold={true} fontSize={21}>
|
||||
{helpButtonHeaderContent}
|
||||
</Text.Body>
|
||||
</HeaderText>
|
||||
</Header>
|
||||
}
|
||||
<Body>{tooltipContent}</Body>
|
||||
</Content>
|
||||
</Aside>
|
||||
@ -178,7 +181,7 @@ HelpButton.propTypes = {
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node
|
||||
]),
|
||||
tooltipContent: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
tooltipContent: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
|
||||
offsetRight: PropTypes.number,
|
||||
tooltipMaxWidth: PropTypes.number,
|
||||
tooltipId: PropTypes.string,
|
||||
@ -186,7 +189,7 @@ HelpButton.propTypes = {
|
||||
offsetLeft: PropTypes.number,
|
||||
zIndex: PropTypes.number,
|
||||
displayType: PropTypes.oneOf(["dropdown", "aside", "auto"]),
|
||||
HelpButtonHeaderContent: PropTypes.string
|
||||
helpButtonHeaderContent: PropTypes.string
|
||||
};
|
||||
|
||||
HelpButton.defaultProps = {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled, { css } from 'styled-components';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import {Parser} from 'html-to-react'
|
||||
|
||||
const iconSizes = {
|
||||
small: 12,
|
||||
@ -38,11 +40,33 @@ const getSizeStyle = size => {
|
||||
|
||||
export default function createStyledIcon(Component, displayName, fillPath="*", strokePath="*") {
|
||||
|
||||
const Icon = ({ isfill, isStroke, color, stroke, fillPath, strokePath, ...props }) => {
|
||||
//console.log(`Icon render ${displayName}`);
|
||||
return (<Component {...props}></Component>);
|
||||
};
|
||||
class Icon extends React.Component {
|
||||
|
||||
render_xml(id, xml_string){
|
||||
var doc = new DOMParser().parseFromString(xml_string, 'application/xml');
|
||||
var el = document.getElementById(id)
|
||||
el.appendChild(
|
||||
el.ownerDocument.importNode(doc.documentElement, true)
|
||||
)
|
||||
}
|
||||
render() {
|
||||
const { isfill, isStroke, color, stroke, fillPath, strokePath, ...props } = this.props;
|
||||
|
||||
var svg = ReactDOMServer.renderToString(<Component {...props}></Component>);
|
||||
const matchResult = svg.match(/\s*mask id="(\w*)"\s/);
|
||||
|
||||
if(matchResult != null){
|
||||
if(matchResult.length > 1){
|
||||
svg = svg.replace(new RegExp(matchResult[1],'g'), Math.random().toString(36).substring(2, 5) + Math.random().toString(36).substring(2, 5))
|
||||
var htmlToReactParser = new Parser();
|
||||
var reactComponent = htmlToReactParser.parse(svg);
|
||||
return reactComponent;
|
||||
}
|
||||
}
|
||||
return (<Component {...props}></Component>);
|
||||
}
|
||||
}
|
||||
|
||||
const StyledIcon = styled(Icon)(
|
||||
props => `
|
||||
${props.fillPath} {
|
||||
|
@ -2,12 +2,162 @@ import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Layout from '.';
|
||||
|
||||
const baseProps = {
|
||||
isBackdropVisible: false,
|
||||
isNavHoverEnabled: true,
|
||||
isNavOpened: false,
|
||||
isAsideVisible: false,
|
||||
currentUser: null,
|
||||
currentUserActions: [],
|
||||
availableModules: []
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const later = (delay) => new Promise(function (resolve) {
|
||||
setTimeout(resolve, delay);
|
||||
});
|
||||
|
||||
describe('<Layout />', () => {
|
||||
it('renders without error', () => {
|
||||
const wrapper = mount(
|
||||
<Layout />
|
||||
<Layout {...baseProps} />
|
||||
);
|
||||
|
||||
expect(wrapper).toExist();
|
||||
});
|
||||
|
||||
it('renders with modules', () => {
|
||||
const modules = [
|
||||
{
|
||||
id: 'test',
|
||||
separator: true
|
||||
},
|
||||
{
|
||||
id: 'demo',
|
||||
title: 'demo',
|
||||
iconName: 'CalendarCheckedIcon',
|
||||
notifications: 0
|
||||
},
|
||||
{
|
||||
id: 'demo1',
|
||||
title: 'demo1',
|
||||
iconName: 'CalendarCheckedIcon',
|
||||
notifications: 0,
|
||||
isolateMode: true
|
||||
}
|
||||
];
|
||||
|
||||
const wrapper = mount(
|
||||
<Layout availableModules={modules} currentModuleId='demo' />
|
||||
).instance();
|
||||
|
||||
expect(wrapper.props.availableModules).toBe(modules);
|
||||
});
|
||||
|
||||
it("componentDidUpdate() test", () => {
|
||||
const wrapper = mount(
|
||||
<Layout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.componentDidUpdate(wrapper.props);
|
||||
|
||||
expect(wrapper.props).toBe(wrapper.props);
|
||||
|
||||
wrapper.componentDidUpdate(
|
||||
{
|
||||
currentModuleId: 'demo',
|
||||
currentUser: {
|
||||
id: 'test',
|
||||
displayName: 'test test',
|
||||
email: 'test',
|
||||
avatarSmall: 'test'
|
||||
},
|
||||
availableModules: [
|
||||
{
|
||||
id: 'test',
|
||||
separator: true
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(wrapper.props).toBe(wrapper.props);
|
||||
});
|
||||
|
||||
it("call backdropClick()", () => {
|
||||
const wrapper = mount(
|
||||
<Layout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.backdropClick();
|
||||
|
||||
expect(wrapper.state.isBackdropVisible).toBe(false);
|
||||
expect(wrapper.state.isNavOpened).toBe(false);
|
||||
expect(wrapper.state.isAsideVisible).toBe(false);
|
||||
});
|
||||
|
||||
it("call showNav()", () => {
|
||||
const wrapper = mount(
|
||||
<Layout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.showNav();
|
||||
|
||||
expect(wrapper.state.isBackdropVisible).toBe(true);
|
||||
expect(wrapper.state.isNavOpened).toBe(true);
|
||||
expect(wrapper.state.isAsideVisible).toBe(false);
|
||||
expect(wrapper.state.isNavHoverEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("call toggleAside()", () => {
|
||||
const wrapper = mount(
|
||||
<Layout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.toggleAside();
|
||||
|
||||
expect(wrapper.state.isBackdropVisible).toBe(true);
|
||||
expect(wrapper.state.isNavOpened).toBe(false);
|
||||
expect(wrapper.state.isAsideVisible).toBe(true);
|
||||
expect(wrapper.state.isNavHoverEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("call handleNavMouseEnter()", async () => {
|
||||
const wrapper = mount(
|
||||
<Layout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.setState({ isNavHoverEnabled: false });
|
||||
|
||||
wrapper.handleNavMouseEnter();
|
||||
|
||||
expect(wrapper.state.isNavOpened).toBe(false);
|
||||
|
||||
wrapper.setState({ isNavHoverEnabled: true });
|
||||
|
||||
wrapper.handleNavMouseEnter();
|
||||
|
||||
await later(400);
|
||||
|
||||
expect(wrapper.state.isNavOpened).toBe(true);
|
||||
});
|
||||
|
||||
it("call handleNavMouseLeave()", () => {
|
||||
const wrapper = mount(
|
||||
<Layout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.setState({ isNavHoverEnabled: false });
|
||||
|
||||
wrapper.handleNavMouseLeave();
|
||||
|
||||
expect(wrapper.state.isNavOpened).toBe(false);
|
||||
|
||||
wrapper.setState({ isNavHoverEnabled: true });
|
||||
|
||||
wrapper.timeout = 1;
|
||||
|
||||
wrapper.handleNavMouseLeave();
|
||||
|
||||
expect(wrapper.state.isNavOpened).toBe(false);
|
||||
});
|
||||
});
|
||||
|
31
web/ASC.Web.Components/src/components/page-layout/README.md
Normal file
31
web/ASC.Web.Components/src/components/page-layout/README.md
Normal file
@ -0,0 +1,31 @@
|
||||
# PageLayout
|
||||
|
||||
Default page layout
|
||||
|
||||
### Usage
|
||||
|
||||
```js
|
||||
import { PageLayout } from "asc-web-components";
|
||||
```
|
||||
|
||||
```jsx
|
||||
<PageLayout
|
||||
articleHeaderContent={articleHeaderContent}
|
||||
articleMainButtonContent={articleMainButtonContent}
|
||||
articleBodyContent={articleBodyContent}
|
||||
sectionHeaderContent={sectionHeaderContent}
|
||||
sectionFilterContent={sectionFilterContent}
|
||||
sectionBodyContent={sectionBodyContent}
|
||||
sectionPagingContent={sectionPagingContent}
|
||||
/>
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Props | Type | Required | Values | Default | Description |
|
||||
| ------------------- | :----: | :------: | :----: | :-----: | ----------------------------------------- |
|
||||
| `isBackdropVisible` | `bool` | - | - | `false` | If you need display Backdrop |
|
||||
| `isNavHoverEnabled` | `bool` | - | - | `true` | If you need hover navigation on Backdrop |
|
||||
| `isNavOpened` | `bool` | - | - | `false` | If you need display navigation |
|
||||
| `isAsideVisible` | `bool` | - | - | `false` | If you need display aside |
|
||||
| `withBodyScroll` | `bool` | - | - | `true` | If you need display scroll inside content |
|
@ -0,0 +1,141 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import styled from '@emotion/styled';
|
||||
import Layout from '../layout';
|
||||
import PageLayout from '.';
|
||||
import { Text } from '../text';
|
||||
import IconButton from '../icon-button';
|
||||
import ContextMenuButton from '../context-menu-button';
|
||||
import MainButton from '../main-button';
|
||||
import SearchInput from '../search-input';
|
||||
import Paging from '../paging';
|
||||
import withReadme from 'storybook-readme/with-readme';
|
||||
import { boolean, withKnobs } from '@storybook/addon-knobs/react';
|
||||
import Readme from './README.md';
|
||||
|
||||
const HeaderContent = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
& > * {
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const pageItems = [
|
||||
{
|
||||
key: '1',
|
||||
label: '1 of 2',
|
||||
onClick: (e) => action('set paging 1 of 2')(e)
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: '2 of 2',
|
||||
onClick: (e) => action('set paging 2 of 2')(e)
|
||||
}
|
||||
];
|
||||
|
||||
const perPageItems = [
|
||||
{
|
||||
key: '1-1',
|
||||
label: '25 per page',
|
||||
onClick: (e) => action('set paging 25 action')(e)
|
||||
},
|
||||
{
|
||||
key: '1-2',
|
||||
label: '50 per page',
|
||||
onClick: (e) => action('set paging 50 action')(e)
|
||||
}
|
||||
];
|
||||
|
||||
const articleHeaderContent = <Text.MenuHeader>Article Header</Text.MenuHeader>;
|
||||
|
||||
const articleMainButtonContent = <MainButton
|
||||
text='Actions'
|
||||
clickAction={(e) => action('MainButton Clicked')(e)}
|
||||
/>;
|
||||
|
||||
const articleBodyContent = <p style={{ padding: 40 }}>Article Content</p>;
|
||||
|
||||
const sectionHeaderContent = <HeaderContent>
|
||||
<IconButton
|
||||
iconName={"ArrowPathIcon"}
|
||||
size='16'
|
||||
onClick={(e) => action('ArrowPathIcon Clicked')(e)}
|
||||
/>
|
||||
<Text.ContentHeader>Section Header</Text.ContentHeader>
|
||||
<IconButton
|
||||
iconName={"PlusIcon"}
|
||||
size='16'
|
||||
onClick={(e) => action('PlusIcon Clicked')(e)}
|
||||
/>
|
||||
<ContextMenuButton
|
||||
title="Actions"
|
||||
getData={() => [
|
||||
{
|
||||
key: 'key',
|
||||
label: 'label',
|
||||
onClick: (e) => action('label Clicked')(e)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</HeaderContent>;
|
||||
|
||||
const sectionFilterContent = <SearchInput
|
||||
isNeedFilter={true}
|
||||
getFilterData={() => [
|
||||
{
|
||||
key: 'filter-example',
|
||||
group: 'filter-example',
|
||||
label: 'example group',
|
||||
isHeader: true
|
||||
},
|
||||
{
|
||||
key: 'filter-example-test',
|
||||
group: 'filter-example',
|
||||
label: 'Test'
|
||||
}
|
||||
]}
|
||||
onSearchClick={(result) => { console.log(result) }}
|
||||
onChangeFilter={(result) => { console.log(result) }}
|
||||
/>
|
||||
|
||||
const sectionBodyContent = <p style={{ padding: 40 }}>Section Content</p>;
|
||||
|
||||
const sectionPagingContent = <Paging
|
||||
previousLabel="Previous"
|
||||
nextLabel="Next"
|
||||
pageItems={pageItems}
|
||||
perPageItems={perPageItems}
|
||||
selectedPageItem={pageItems[0]}
|
||||
selectedCountItem={perPageItems[0]}
|
||||
onSelectPage={(a) => console.log(a)}
|
||||
onSelectCount={(a) => console.log(a)}
|
||||
previousAction={(e) => action('Prev Clicked')(e)}
|
||||
nextAction={(e) => action('Next Clicked')(e)}
|
||||
openDirection="top"
|
||||
/>
|
||||
|
||||
storiesOf('Components|PageLayout', module)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add('base', () => (
|
||||
<Layout
|
||||
isBackdropVisible={boolean("isBackdropVisible", false)}
|
||||
isNavHoverEnabled={boolean("isNavHoverEnabled", true)}
|
||||
isNavOpened={boolean("isNavOpened", false)}
|
||||
isAsideVisible={boolean("isAsideVisible", false)}
|
||||
>
|
||||
<PageLayout
|
||||
articleHeaderContent={articleHeaderContent}
|
||||
articleMainButtonContent={articleMainButtonContent}
|
||||
articleBodyContent={articleBodyContent}
|
||||
sectionHeaderContent={sectionHeaderContent}
|
||||
sectionFilterContent={sectionFilterContent}
|
||||
sectionBodyContent={sectionBodyContent}
|
||||
sectionPagingContent={sectionPagingContent}
|
||||
/>
|
||||
</Layout>
|
||||
|
||||
));
|
@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import PageLayout from '.';
|
||||
|
||||
const baseProps = {
|
||||
isBackdropVisible: false,
|
||||
isArticleVisible: false,
|
||||
isArticlePinned: false,
|
||||
withBodyScroll: true
|
||||
}
|
||||
|
||||
describe('<PageLayout />', () => {
|
||||
it('renders without error', () => {
|
||||
const wrapper = mount(
|
||||
<PageLayout {...baseProps} />
|
||||
);
|
||||
|
||||
expect(wrapper).toExist();
|
||||
});
|
||||
|
||||
it("componentDidUpdate() test re-render", () => {
|
||||
const wrapper = mount(
|
||||
<PageLayout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.componentDidUpdate({ withBodyScroll: false });
|
||||
|
||||
expect(wrapper.props).toBe(wrapper.props);
|
||||
});
|
||||
|
||||
it("componentDidUpdate() test no re-render", () => {
|
||||
const wrapper = mount(
|
||||
<PageLayout
|
||||
{...baseProps}
|
||||
articleHeaderContent={<>1</>}
|
||||
articleMainButtonContent={<>2</>}
|
||||
articleBodyContent={<>3</>}
|
||||
sectionHeaderContent={<>4</>}
|
||||
sectionFilterContent={<>5</>}
|
||||
sectionBodyContent={<>6</>}
|
||||
sectionPagingContent={<>7</>}
|
||||
withBodyScroll={false}
|
||||
/>
|
||||
).instance();
|
||||
|
||||
wrapper.componentDidUpdate(wrapper.props);
|
||||
|
||||
expect(wrapper.props.withBodyScroll).toBe(false);
|
||||
|
||||
wrapper.componentDidUpdate(wrapper.props);
|
||||
|
||||
expect(wrapper.props).toBe(wrapper.props);
|
||||
});
|
||||
|
||||
it("call backdropClick()", () => {
|
||||
const wrapper = mount(
|
||||
<PageLayout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.backdropClick();
|
||||
|
||||
expect(wrapper.state.isBackdropVisible).toBe(false);
|
||||
expect(wrapper.state.isArticleVisible).toBe(false);
|
||||
expect(wrapper.state.isArticlePinned).toBe(false);
|
||||
});
|
||||
|
||||
it("call pinArticle()", () => {
|
||||
const wrapper = mount(
|
||||
<PageLayout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.pinArticle();
|
||||
|
||||
expect(wrapper.state.isBackdropVisible).toBe(false);
|
||||
expect(wrapper.state.isArticleVisible).toBe(true);
|
||||
expect(wrapper.state.isArticlePinned).toBe(true);
|
||||
});
|
||||
|
||||
it("call unpinArticle()", () => {
|
||||
const wrapper = mount(
|
||||
<PageLayout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.unpinArticle();
|
||||
|
||||
expect(wrapper.state.isBackdropVisible).toBe(true);
|
||||
expect(wrapper.state.isArticleVisible).toBe(true);
|
||||
expect(wrapper.state.isArticlePinned).toBe(false);
|
||||
});
|
||||
|
||||
it("call showArticle()", () => {
|
||||
const wrapper = mount(
|
||||
<PageLayout {...baseProps} />
|
||||
).instance();
|
||||
|
||||
wrapper.showArticle();
|
||||
|
||||
expect(wrapper.state.isBackdropVisible).toBe(true);
|
||||
expect(wrapper.state.isArticleVisible).toBe(true);
|
||||
expect(wrapper.state.isArticlePinned).toBe(false);
|
||||
});
|
||||
});
|
@ -4,12 +4,11 @@ import styled from "styled-components";
|
||||
import { Text } from "../text";
|
||||
import Scrollbar from "../scrollbar";
|
||||
|
||||
const TabsContainer = styled.div`
|
||||
.scrollbar {
|
||||
width: 100% !important;
|
||||
height: 50px !important;
|
||||
}
|
||||
const StyledScrollbar = styled(Scrollbar)`
|
||||
width: 100% !important;
|
||||
height: 50px !important;
|
||||
`;
|
||||
|
||||
const NavItem = styled.div`
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
@ -76,7 +75,8 @@ class TabContainer extends Component {
|
||||
}
|
||||
|
||||
this.state = {
|
||||
activeTab: this.props.selectedItem
|
||||
activeTab: this.props.selectedItem,
|
||||
onScrollHide: true
|
||||
};
|
||||
|
||||
this.scrollRef = React.createRef();
|
||||
@ -89,39 +89,132 @@ class TabContainer extends Component {
|
||||
delete newItem.content;
|
||||
this.props.onSelect && this.props.onSelect(newItem);
|
||||
|
||||
const position = ref.current.offsetLeft - 40;
|
||||
this.scrollRef.current.scrollLeft(position);
|
||||
this.setTabPosition(index, ref);
|
||||
}
|
||||
};
|
||||
|
||||
getWidthElements = () => {
|
||||
const arrayWidths = [];
|
||||
const length = this.arrayRefs.length - 1;
|
||||
let widthItem = 0;
|
||||
while (length + 1 !== widthItem) {
|
||||
arrayWidths.push(this.arrayRefs[widthItem].current.offsetWidth);
|
||||
widthItem++;
|
||||
}
|
||||
|
||||
return arrayWidths;
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { activeTab } = this.state;
|
||||
const { activeTab, onScrollHide } = this.state;
|
||||
const { isDisabled } = this.props;
|
||||
if (
|
||||
activeTab === nextState.activeTab &&
|
||||
isDisabled === nextProps.isDisabled
|
||||
isDisabled === nextProps.isDisabled &&
|
||||
onScrollHide === nextState.onScrollHide
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { activeTab } = this.state;
|
||||
if (activeTab !== 0 && this.arrayRefs[activeTab].current !== null) {
|
||||
this.secondFunction(activeTab);
|
||||
}
|
||||
}
|
||||
|
||||
setTabPosition = (index, currentRef) => {
|
||||
const arrayOfWidths = this.getWidthElements(); //get tabs widths
|
||||
const scrollLeft = this.scrollRef.current.getScrollLeft(); // get scroll position relative to left side
|
||||
const staticScroll = this.scrollRef.current.getScrollWidth(); //get static scroll width
|
||||
const containerWidth = this.scrollRef.current.getClientWidth(); //get main container width
|
||||
const currentTabWidth = currentRef.current.offsetWidth;
|
||||
const marginRight = 8;
|
||||
|
||||
//get tabs of left side
|
||||
let leftTabs = 0;
|
||||
let leftFullWidth = 0;
|
||||
while (leftTabs !== index) {
|
||||
leftTabs++;
|
||||
leftFullWidth += arrayOfWidths[leftTabs] + marginRight;
|
||||
}
|
||||
leftFullWidth += arrayOfWidths[0] + marginRight;
|
||||
|
||||
//get tabs of right side
|
||||
let rightTabs = this.arrayRefs.length - 1;
|
||||
let rightFullWidth = 0;
|
||||
while (rightTabs !== index - 1) {
|
||||
rightFullWidth += arrayOfWidths[rightTabs] + marginRight;
|
||||
rightTabs--;
|
||||
}
|
||||
|
||||
//Out of range of left side
|
||||
if (leftFullWidth > containerWidth + scrollLeft) {
|
||||
let prevIndex = index - 1;
|
||||
let widthBlocksInContainer = 0;
|
||||
while (prevIndex !== -1) {
|
||||
widthBlocksInContainer += arrayOfWidths[prevIndex] + marginRight;
|
||||
prevIndex--;
|
||||
}
|
||||
|
||||
const difference = containerWidth - widthBlocksInContainer;
|
||||
const currentContainerWidth = currentTabWidth;
|
||||
|
||||
this.scrollRef.current.scrollLeft(
|
||||
difference * -1 + currentContainerWidth + marginRight
|
||||
);
|
||||
}
|
||||
//Out of range of left side
|
||||
else if (rightFullWidth > staticScroll - scrollLeft) {
|
||||
this.scrollRef.current.scrollLeft(staticScroll - rightFullWidth);
|
||||
}
|
||||
};
|
||||
|
||||
secondFunction = index => {
|
||||
const arrayOfWidths = this.getWidthElements(); //get tabs widths
|
||||
const marginRight = 8;
|
||||
let rightTabs = this.arrayRefs.length - 1;
|
||||
let rightFullWidth = 0;
|
||||
while (rightTabs !== index - 1) {
|
||||
rightFullWidth += arrayOfWidths[rightTabs] + marginRight;
|
||||
rightTabs--;
|
||||
}
|
||||
|
||||
const staticScroll = this.scrollRef.current.getScrollWidth(); //get static scroll width
|
||||
this.scrollRef.current.scrollLeft(staticScroll - rightFullWidth);
|
||||
};
|
||||
|
||||
onMouseEnter = () => {
|
||||
this.setState({ onScrollHide: false });
|
||||
};
|
||||
|
||||
onMouseLeave = () => {
|
||||
this.setState({ onScrollHide: true });
|
||||
};
|
||||
|
||||
render() {
|
||||
//console.log("Tabs container render");
|
||||
|
||||
const { isDisabled, children } = this.props;
|
||||
const { activeTab } = this.state;
|
||||
const { activeTab, onScrollHide } = this.state;
|
||||
|
||||
return (
|
||||
<TabsContainer>
|
||||
<Scrollbar
|
||||
values={this.onScrollFrame}
|
||||
autoHide
|
||||
<>
|
||||
<StyledScrollbar
|
||||
autoHide={onScrollHide}
|
||||
autoHideDuration={500}
|
||||
autoHideTimeout={1000}
|
||||
stype="preMediumBlack"
|
||||
className="scrollbar"
|
||||
ref={this.scrollRef}
|
||||
>
|
||||
<NavItem className="className_items">
|
||||
<NavItem
|
||||
onMouseMove={this.onMouseEnter}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
className="className_items"
|
||||
>
|
||||
{children.map((item, index) => (
|
||||
<Label
|
||||
ref={this.arrayRefs[index]}
|
||||
@ -141,9 +234,9 @@ class TabContainer extends Component {
|
||||
</Label>
|
||||
))}
|
||||
</NavItem>
|
||||
</Scrollbar>
|
||||
</StyledScrollbar>
|
||||
<BodyContainer>{children[activeTab].content}</BodyContainer>
|
||||
</TabsContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -106,66 +106,289 @@ const scrollArrayItems = [
|
||||
key: "tab0",
|
||||
title: "First long tab container",
|
||||
content: (
|
||||
<div>
|
||||
<button>button</button>
|
||||
<button>button</button>
|
||||
<button>button</button>
|
||||
</div>
|
||||
<>
|
||||
<label>Tab_0 Tab_0 Tab_0</label>
|
||||
<br />
|
||||
<label>Tab_0 Tab_0 Tab_0</label>
|
||||
<br />
|
||||
<label>Tab_0 Tab_0 Tab_0</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab1",
|
||||
title: "Short",
|
||||
content: (
|
||||
<div>
|
||||
<label>label</label>
|
||||
<label>label</label>
|
||||
<label>label</label>
|
||||
</div>
|
||||
<>
|
||||
<label>Tab_1 Tab_1 Tab_1</label>
|
||||
<br />
|
||||
<label>Tab_1 Tab_1 Tab_1</label>
|
||||
<br />
|
||||
<label>Tab_1 Tab_1 Tab_1</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab2",
|
||||
title: "Third long tab container",
|
||||
title: "Second long tab container",
|
||||
content: (
|
||||
<div>
|
||||
<input />
|
||||
<input />
|
||||
<input />
|
||||
</div>
|
||||
<>
|
||||
<label>Tab_2 Tab_2 Tab_2</label>
|
||||
<br />
|
||||
<label>Tab_2 Tab_2 Tab_2</label>
|
||||
<br />
|
||||
<label>Tab_2 Tab_2 Tab_2</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab3",
|
||||
title: "Short2",
|
||||
content: (
|
||||
<div>
|
||||
<input />
|
||||
<input />
|
||||
<input />
|
||||
</div>
|
||||
<>
|
||||
<label>Tab_3 Tab_3 Tab_3</label>
|
||||
<br />
|
||||
<label>Tab_3 Tab_3 Tab_3</label>
|
||||
<br />
|
||||
<label>Tab_3 Tab_3 Tab_3</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab4",
|
||||
title: "Third long tab container",
|
||||
title: "Third long tab container header",
|
||||
content: (
|
||||
<div>
|
||||
<input />
|
||||
<input />
|
||||
<input />
|
||||
</div>
|
||||
<>
|
||||
<label>Tab_4 Tab_4 Tab_4</label>
|
||||
<br />
|
||||
<label>Tab_4 Tab_4 Tab_4</label>
|
||||
<br />
|
||||
<label>Tab_4 Tab_4 Tab_4</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab5",
|
||||
title: "Short3",
|
||||
content: (
|
||||
<div>
|
||||
<input />
|
||||
<input />
|
||||
<input />
|
||||
</div>
|
||||
<>
|
||||
<label>Tab_5 Tab_5 Tab_5</label>
|
||||
<br />
|
||||
<label>Tab_5 Tab_5 Tab_5</label>
|
||||
<br />
|
||||
<label>Tab_5 Tab_5 Tab_5</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab6",
|
||||
title: "tab container",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_6 Tab_6 Tab_6</label>
|
||||
<br />
|
||||
<label>Tab_6 Tab_6 Tab_6</label>
|
||||
<br />
|
||||
<label>Tab_6 Tab_6 Tab_6</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab7",
|
||||
title: "Very long tabs-container field",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_7 Tab_7 Tab_7</label>
|
||||
<br />
|
||||
<label>Tab_7 Tab_7 Tab_7</label>
|
||||
<br />
|
||||
<label>Tab_7 Tab_7 Tab_7</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab8",
|
||||
title: "tab container",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_8 Tab_8 Tab_8</label>
|
||||
<br />
|
||||
<label>Tab_8 Tab_8 Tab_8</label>
|
||||
<br />
|
||||
<label>Tab_8 Tab_8 Tab_8</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab9",
|
||||
title: "Short_04",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_9 Tab_9 Tab_9</label>
|
||||
<br />
|
||||
<label>Tab_9 Tab_9 Tab_9</label>
|
||||
<br />
|
||||
<label>Tab_9 Tab_9 Tab_9</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab10",
|
||||
title: "Short__05",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_10 Tab_10 Tab_10</label>
|
||||
<br />
|
||||
<label>Tab_10 Tab_10 Tab_10</label>
|
||||
<br />
|
||||
<label>Tab_10 Tab_10 Tab_10</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab11",
|
||||
title: "TabsContainer",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_11 Tab_11 Tab_11</label>
|
||||
<br />
|
||||
<label>Tab_11 Tab_11 Tab_11</label>
|
||||
<br />
|
||||
<label>Tab_11 Tab_11 Tab_11</label>
|
||||
</>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const tabsItems = [
|
||||
{
|
||||
key: "tab0",
|
||||
title: "Title00000000",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_0 Tab_0 Tab_0</label>
|
||||
<br />
|
||||
<label>Tab_0 Tab_0 Tab_0</label>
|
||||
<br />
|
||||
<label>Tab_0 Tab_0 Tab_0</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab1",
|
||||
title: "Title00000001",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_1 Tab_1 Tab_1</label>
|
||||
<br />
|
||||
<label>Tab_1 Tab_1 Tab_1</label>
|
||||
<br />
|
||||
<label>Tab_1 Tab_1 Tab_1</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab2",
|
||||
title: "Title00000002",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_2 Tab_2 Tab_2</label>
|
||||
<br />
|
||||
<label>Tab_2 Tab_2 Tab_2</label>
|
||||
<br />
|
||||
<label>Tab_2 Tab_2 Tab_2</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab3",
|
||||
title: "Title00000003",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_3 Tab_3 Tab_3</label>
|
||||
<br />
|
||||
<label>Tab_3 Tab_3 Tab_3</label>
|
||||
<br />
|
||||
<label>Tab_3 Tab_3 Tab_3</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab4",
|
||||
title: "Title00000004",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_4 Tab_4 Tab_4</label>
|
||||
<br />
|
||||
<label>Tab_4 Tab_4 Tab_4</label>
|
||||
<br />
|
||||
<label>Tab_4 Tab_4 Tab_4</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab5",
|
||||
title: "Title00000005",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_5 Tab_5 Tab_5</label>
|
||||
<br />
|
||||
<label>Tab_5 Tab_5 Tab_5</label>
|
||||
<br />
|
||||
<label>Tab_5 Tab_5 Tab_5</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab6",
|
||||
title: "Title00000006",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_6 Tab_6 Tab_6</label>
|
||||
<br />
|
||||
<label>Tab_6 Tab_6 Tab_6</label>
|
||||
<br />
|
||||
<label>Tab_6 Tab_6 Tab_6</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab7",
|
||||
title: "Title00000007",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_7 Tab_7 Tab_7</label>
|
||||
<br />
|
||||
<label>Tab_7 Tab_7 Tab_7</label>
|
||||
<br />
|
||||
<label>Tab_7 Tab_7 Tab_7</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab8",
|
||||
title: "Title00000008",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_8 Tab_8 Tab_8</label>
|
||||
<br />
|
||||
<label>Tab_8 Tab_8 Tab_8</label>
|
||||
<br />
|
||||
<label>Tab_8 Tab_8 Tab_8</label>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "tab9",
|
||||
title: "Title00000009",
|
||||
content: (
|
||||
<>
|
||||
<label>Tab_9 Tab_9 Tab_9</label>
|
||||
<br />
|
||||
<label>Tab_9 Tab_9 Tab_9</label>
|
||||
<br />
|
||||
<label>Tab_9 Tab_9 Tab_9</label>
|
||||
</>
|
||||
)
|
||||
}
|
||||
];
|
||||
@ -187,12 +410,27 @@ storiesOf("Components|TabContainer", module)
|
||||
|
||||
<div style={{ marginTop: 32, maxWidth: 430 }}>
|
||||
<h5 style={{ marginTop: 100, marginBottom: 20 }}>
|
||||
TabsContainer with auto scroll:
|
||||
Autoscrolling with different tab widths:
|
||||
</h5>
|
||||
<TabContainer isDisabled={boolean("isDisabled", false)}>
|
||||
<TabContainer
|
||||
isDisabled={boolean("isDisabled", false)}
|
||||
selectedItem={3}
|
||||
>
|
||||
{scrollArrayItems}
|
||||
</TabContainer>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 32, maxWidth: 430 }}>
|
||||
<h5 style={{ marginTop: 100, marginBottom: 20 }}>
|
||||
Autoscrolling with the same tabs width:
|
||||
</h5>
|
||||
<TabContainer
|
||||
isDisabled={boolean("isDisabled", false)}
|
||||
selectedItem={5}
|
||||
>
|
||||
{tabsItems}
|
||||
</TabContainer>
|
||||
</div>
|
||||
</Section>
|
||||
);
|
||||
});
|
||||
|
@ -18,9 +18,11 @@ import { ToggleButton } from "asc-web-components";
|
||||
|
||||
#### Properties
|
||||
|
||||
| Props | Type | Required | Values | Default | Description |
|
||||
| ------------ | :------: | :------: | :----: | :-----: | -------------------------------------------------------------- |
|
||||
| `label` | `string` | - | - | - | Label of the input |
|
||||
| `isChecked` | `bool` | - | - | - | The checked property sets the checked state of a ToggleButton. |
|
||||
| `isDisabled` | `bool` | - | - | - | Disables the ToggleButton |
|
||||
| `onChange` | `func` | ✅ | - | - | Will be triggered whenever an ToggleButton is clicked |
|
||||
| Props | Type | Required | Values | Default | Description |
|
||||
| ------------ | :----------------: | :------: | :----: | :-----: | -------------------------------------------------------------- |
|
||||
| `label` | `string` | - | - | - | Label of the input |
|
||||
| `isChecked` | `bool` | - | - | - | The checked property sets the checked state of a ToggleButton. |
|
||||
| `isDisabled` | `bool` | - | - | - | Disables the ToggleButton |
|
||||
| `onChange` | `func` | ✅ | - | - | Will be triggered whenever an ToggleButton is clicked |
|
||||
| `className` | `string` | - | - | - | Class name |
|
||||
| `id` | `string`, `number` | - | - | - | Set component id |
|
||||
|
@ -73,7 +73,11 @@ class ToggleButton extends Component {
|
||||
//console.log("ToggleButton render");
|
||||
|
||||
return (
|
||||
<ToggleButtonContainer id={id} className={className} isDisabled={isDisabled}>
|
||||
<ToggleButtonContainer
|
||||
id={id}
|
||||
className={className}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
<HiddenInput
|
||||
type="checkbox"
|
||||
checked={this.state.checked}
|
||||
@ -96,7 +100,7 @@ ToggleButton.propTypes = {
|
||||
isDisabled: PropTypes.bool,
|
||||
onChange: PropTypes.func,
|
||||
label: PropTypes.string,
|
||||
id: PropTypes.string,
|
||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
className: PropTypes.string
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,7 @@ import Readme from "./README.md";
|
||||
import ToggleButton from ".";
|
||||
import Section from "../../../.storybook/decorators/section";
|
||||
|
||||
storiesOf("Components|Input", module)
|
||||
storiesOf("Components|Buttons", module)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add("toggle button", () => {
|
||||
@ -17,6 +17,8 @@ storiesOf("Components|Input", module)
|
||||
<BooleanValue>
|
||||
{({ value, toggle }) => (
|
||||
<ToggleButton
|
||||
id={text("id", "toggle id")}
|
||||
className={text("className", "toggle className")}
|
||||
isChecked={value}
|
||||
isDisabled={boolean("isDisabled", false)}
|
||||
label={text("label", "label text")}
|
||||
|
@ -4542,6 +4542,14 @@ dom-serializer@0:
|
||||
domelementtype "^2.0.1"
|
||||
entities "^2.0.0"
|
||||
|
||||
dom-serializer@^0.2.1:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
|
||||
integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==
|
||||
dependencies:
|
||||
domelementtype "^2.0.1"
|
||||
entities "^2.0.0"
|
||||
|
||||
dom-serializer@~0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
|
||||
@ -4584,6 +4592,13 @@ domhandler@^2.3.0:
|
||||
dependencies:
|
||||
domelementtype "1"
|
||||
|
||||
domhandler@^3.0, domhandler@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.0.0.tgz#51cd13efca31da95bbb0c5bee3a48300e333b3e9"
|
||||
integrity sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==
|
||||
dependencies:
|
||||
domelementtype "^2.0.1"
|
||||
|
||||
domutils@1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
|
||||
@ -4600,6 +4615,15 @@ domutils@^1.5.1, domutils@^1.7.0:
|
||||
dom-serializer "0"
|
||||
domelementtype "1"
|
||||
|
||||
domutils@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.0.0.tgz#15b8278e37bfa8468d157478c58c367718133c08"
|
||||
integrity sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg==
|
||||
dependencies:
|
||||
dom-serializer "^0.2.1"
|
||||
domelementtype "^2.0.1"
|
||||
domhandler "^3.0.0"
|
||||
|
||||
dot-prop@^4.1.1:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
|
||||
@ -6036,6 +6060,16 @@ html-minifier@^4.0.0:
|
||||
relateurl "^0.2.7"
|
||||
uglify-js "^3.5.1"
|
||||
|
||||
html-to-react@^1.4.2:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/html-to-react/-/html-to-react-1.4.2.tgz#7b628ab56cd63a52f2d0b79d0fa838a51f088a57"
|
||||
integrity sha512-TdTfxd95sRCo6QL8admCkE7mvNNrXtGoVr1dyS+7uvc8XCqAymnf/6ckclvnVbQNUo2Nh21VPwtfEHd0khiV7g==
|
||||
dependencies:
|
||||
domhandler "^3.0"
|
||||
htmlparser2 "^4.0"
|
||||
lodash.camelcase "^4.3.0"
|
||||
ramda "^0.26"
|
||||
|
||||
html-webpack-plugin@^4.0.0-beta.2:
|
||||
version "4.0.0-beta.8"
|
||||
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.8.tgz#d9a8d4322d8cf310f1568f6f4f585a80df0ad378"
|
||||
@ -6060,6 +6094,16 @@ htmlparser2@^3.3.0, htmlparser2@^3.9.1:
|
||||
inherits "^2.0.1"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
htmlparser2@^4.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.0.0.tgz#6034658db65b7713a572a9ebf79f650832dceec8"
|
||||
integrity sha512-cChwXn5Vam57fyXajDtPXL1wTYc8JtLbr2TN76FYu05itVVVealxLowe2B3IEznJG4p9HAYn/0tJaRlGuEglFQ==
|
||||
dependencies:
|
||||
domelementtype "^2.0.1"
|
||||
domhandler "^3.0.0"
|
||||
domutils "^2.0.0"
|
||||
entities "^2.0.0"
|
||||
|
||||
http-errors@1.7.2:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
|
||||
@ -9412,6 +9456,11 @@ ramda@^0.21.0:
|
||||
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35"
|
||||
integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=
|
||||
|
||||
ramda@^0.26:
|
||||
version "0.26.1"
|
||||
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
|
||||
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==
|
||||
|
||||
randexp@0.4.6:
|
||||
version "0.4.6"
|
||||
resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
|
||||
|
Loading…
Reference in New Issue
Block a user