Removed packages/common
This commit is contained in:
parent
0e7055ae30
commit
fa6c400f69
@ -2,32 +2,28 @@
|
||||
"folders": [
|
||||
{
|
||||
"name": "🌐 root",
|
||||
"path": "."
|
||||
"path": ".",
|
||||
},
|
||||
{
|
||||
"name": "🚀 @docspace/client",
|
||||
"path": "packages/client"
|
||||
"path": "packages/client",
|
||||
},
|
||||
{
|
||||
"name": "🔑 @docspace/login",
|
||||
"path": "packages/login"
|
||||
"path": "packages/login",
|
||||
},
|
||||
{
|
||||
"name": "📄 @docspace/editor",
|
||||
"path": "packages/editor"
|
||||
"path": "packages/editor",
|
||||
},
|
||||
{
|
||||
"name": "🗂 @docspace/management",
|
||||
"path": "packages/management"
|
||||
},
|
||||
{
|
||||
"name": "📦 @docspace/common",
|
||||
"path": "packages/common"
|
||||
"path": "packages/management",
|
||||
},
|
||||
{
|
||||
"name": "📦 @docspace/shared",
|
||||
"path": "packages/shared"
|
||||
}
|
||||
"path": "packages/shared",
|
||||
},
|
||||
],
|
||||
"settings": {
|
||||
"window.zoomLevel": 0,
|
||||
@ -42,10 +38,10 @@
|
||||
"🚀 @docspace/client",
|
||||
"📄 @docspace/editor",
|
||||
"📦 @docspace/common",
|
||||
"🗂 @docspace/management"
|
||||
"🗂 @docspace/management",
|
||||
],
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
},
|
||||
"VsCodeTaskButtons.tasks": [
|
||||
{
|
||||
@ -54,55 +50,55 @@
|
||||
{
|
||||
"label": "Docker : Build-EE",
|
||||
"task": "Backend | build EE",
|
||||
"tooltip": "🛠️ Start the \"backend docker build EE\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker build EE\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : ReBuild-EE",
|
||||
"task": "Backend | rebuild EE",
|
||||
"tooltip": "🛠️ Start the \"backend docker rebuild EE\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker rebuild EE\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : Build-CE",
|
||||
"task": "Backend | build CE",
|
||||
"tooltip": "🛠️ Start the \"backend docker build CE\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker build CE\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : Build-SAAS + dnsmasq",
|
||||
"task": "Backend | build SAAS + dnsmasq",
|
||||
"tooltip": "🛠️ Start the \"backend docker build SAAS + dnsmasq\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker build SAAS + dnsmasq\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : ReBuild-SAAS + dnsmasq",
|
||||
"task": "Backend | rebuild SAAS + dnsmasq",
|
||||
"tooltip": "🛠️ Start the \"backend docker rebuild SAAS + dnsmasq\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker rebuild SAAS + dnsmasq\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : Build-EE + dnsmasq",
|
||||
"task": "Backend | build EE + dnsmasq",
|
||||
"tooltip": "🛠️ Start the \"backend docker build EE + dnsmasq\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker build EE + dnsmasq\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : Clear",
|
||||
"task": "Backend | clear",
|
||||
"tooltip": "🛠️ Start the \"backend docker clear\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker clear\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : Stop",
|
||||
"task": "Backend | stop",
|
||||
"tooltip": "🛠️ Start the \"backend docker stop\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker stop\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : Start",
|
||||
"task": "Backend | start",
|
||||
"tooltip": "🛠️ Start the \"backend docker start\" task"
|
||||
"tooltip": "🛠️ Start the \"backend docker start\" task",
|
||||
},
|
||||
{
|
||||
"label": "Docker : Restart",
|
||||
"task": "Backend | restart",
|
||||
"tooltip": "🛠️ Start the \"backend docker restart\" task"
|
||||
}
|
||||
"tooltip": "🛠️ Start the \"backend docker restart\" task",
|
||||
},
|
||||
],
|
||||
"tooltip": "🛠️ Server tasks"
|
||||
"tooltip": "🛠️ Server tasks",
|
||||
},
|
||||
{
|
||||
"label": "Client",
|
||||
@ -110,55 +106,55 @@
|
||||
{
|
||||
"label": "Install",
|
||||
"task": "Frontend | install",
|
||||
"tooltip": "🛠️ Start the \"frontend install packages\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend install packages\" task",
|
||||
},
|
||||
{
|
||||
"label": "Update yarn.lock",
|
||||
"task": "Frontend | update yarn.lock",
|
||||
"tooltip": "🛠️ Start the \"frontend update yarn.lock\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend update yarn.lock\" task",
|
||||
},
|
||||
{
|
||||
"label": "Build",
|
||||
"task": "Frontend | build",
|
||||
"tooltip": "🛠️ Start the \"frontend build\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend build\" task",
|
||||
},
|
||||
{
|
||||
"label": "Build and start prod",
|
||||
"task": "Frontend | build-and-start-prod",
|
||||
"tooltip": "🛠️ Start the \"frontend build and start production\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend build and start production\" task",
|
||||
},
|
||||
{
|
||||
"label": "Start",
|
||||
"task": "Frontend | start",
|
||||
"tooltip": "🛠️ Start the \"frontend start\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend start\" task",
|
||||
},
|
||||
{
|
||||
"label": "Start prod",
|
||||
"task": "Frontend | start-prod",
|
||||
"tooltip": "🛠️ Start the \"frontend start production\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend start production\" task",
|
||||
},
|
||||
{
|
||||
"label": "Start storybook",
|
||||
"task": "Frontend | storybook",
|
||||
"tooltip": "🛠️ Start the \"frontend start storybook\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend start storybook\" task",
|
||||
},
|
||||
{
|
||||
"label": "Start storybook prod",
|
||||
"task": "Frontend | storybook prod",
|
||||
"tooltip": "🛠️ Start the \"frontend start storybook\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend start storybook\" task",
|
||||
},
|
||||
{
|
||||
"label": "Lint",
|
||||
"task": "Frontend | Eslint",
|
||||
"tooltip": "🛠️ Start the \"frontend start storybook\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend start storybook\" task",
|
||||
},
|
||||
{
|
||||
"label": "Lint:fix",
|
||||
"task": "Frontend | Eslint:fix",
|
||||
"tooltip": "🛠️ Start the \"frontend start storybook\" task"
|
||||
}
|
||||
"tooltip": "🛠️ Start the \"frontend start storybook\" task",
|
||||
},
|
||||
],
|
||||
"tooltip": "🛠️ Client tasks"
|
||||
"tooltip": "🛠️ Client tasks",
|
||||
},
|
||||
{
|
||||
"label": "Tests",
|
||||
@ -166,27 +162,27 @@
|
||||
{
|
||||
"label": "translations",
|
||||
"task": "Test | frontend-translations",
|
||||
"tooltip": "🛠️ Start the \"frontend translation tests\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend translation tests\" task",
|
||||
},
|
||||
{
|
||||
"label": "spellcheck",
|
||||
"task": "Test | frontend-translations-spellcheck",
|
||||
"tooltip": "🛠️ Start the \"frontend translation spellcheck tests\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend translation spellcheck tests\" task",
|
||||
},
|
||||
{
|
||||
"label": "spellcheck-force-save",
|
||||
"task": "Test | frontend-translations-spellcheck-force-save",
|
||||
"tooltip": "🛠️ Start the \"frontend translation spellcheck tests\" task"
|
||||
"tooltip": "🛠️ Start the \"frontend translation spellcheck tests\" task",
|
||||
},
|
||||
{
|
||||
"label": "unit",
|
||||
"task": "Test | Jest:unit",
|
||||
"tooltip": "🛠️ Start the \"Test | Jest:unit\" task"
|
||||
}
|
||||
"tooltip": "🛠️ Start the \"Test | Jest:unit\" task",
|
||||
},
|
||||
],
|
||||
"tooltip": "🛠️ Client tests tasks",
|
||||
},
|
||||
],
|
||||
"tooltip": "🛠️ Client tests tasks"
|
||||
}
|
||||
]
|
||||
},
|
||||
"extensions": {
|
||||
"recommendations": [
|
||||
@ -199,7 +195,7 @@
|
||||
"formulahendry.auto-complete-tag",
|
||||
"formulahendry.auto-rename-tag",
|
||||
"mrmlnc.vscode-duplicate",
|
||||
"ms-python.python"
|
||||
]
|
||||
}
|
||||
"ms-python.python",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
module.exports = [
|
||||
'>0.25%',
|
||||
'not ie 11',
|
||||
'not op_mini all',
|
||||
'not dead',
|
||||
'Firefox ESR',
|
||||
];
|
@ -1,208 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { tablet, mobile } from "@docspace/shared/utils";
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
|
||||
import Selector from "./sub-components/Selector";
|
||||
import { Backdrop } from "@docspace/shared/components/backdrop";
|
||||
|
||||
import CrossIcon from "PUBLIC_DIR/images/cross.react.svg";
|
||||
|
||||
const StyledBlock = styled.div`
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl" ? `left: 0;` : `right: 0;`}
|
||||
|
||||
width: 480px;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
|
||||
z-index: 400;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
background: ${(props) => props.theme.filterInput.filter.background};
|
||||
|
||||
@media ${tablet} {
|
||||
max-width: calc(100% - 69px);
|
||||
}
|
||||
|
||||
${isMobile &&
|
||||
css`
|
||||
max-width: calc(100% - 69px);
|
||||
`}
|
||||
|
||||
@media ${mobile} {
|
||||
bottom: 0;
|
||||
top: unset;
|
||||
height: calc(100% - 64px);
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.people-selector {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.selector-wrapper,
|
||||
.column-options {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
StyledBlock.defaultProps = { theme: Base };
|
||||
|
||||
const StyledControlContainer = styled.div`
|
||||
display: flex;
|
||||
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
position: absolute;
|
||||
|
||||
border-radius: 100px;
|
||||
cursor: pointer;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 450;
|
||||
|
||||
top: 18px;
|
||||
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl" ? `right: -27px;` : `left: -27px;`}
|
||||
|
||||
${isMobile &&
|
||||
css`
|
||||
top: 18px;
|
||||
`}
|
||||
|
||||
@media ${mobile} {
|
||||
top: -27px;
|
||||
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
left: 10px;
|
||||
right: unset;
|
||||
`
|
||||
: css`
|
||||
right: 10px;
|
||||
left: unset;
|
||||
`}
|
||||
}
|
||||
`;
|
||||
|
||||
StyledControlContainer.defaultProps = { theme: Base };
|
||||
|
||||
const StyledCrossIcon = styled(CrossIcon)`
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
z-index: 455;
|
||||
path {
|
||||
fill: ${(props) => props.theme.catalog.control.fill};
|
||||
}
|
||||
`;
|
||||
|
||||
StyledCrossIcon.defaultProps = { theme: Base };
|
||||
|
||||
class AdvancedSelector extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.ref = React.createRef();
|
||||
}
|
||||
|
||||
onClose = (e) => {
|
||||
//console.log("onClose");
|
||||
//this.setState({ isOpen: false });
|
||||
this.props.onCancel && this.props.onCancel(e);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isOpen, id, className, style, withoutAside } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
{isOpen && (
|
||||
<div id={id} className={className} style={style}>
|
||||
{withoutAside ? (
|
||||
<Selector {...this.props} />
|
||||
) : (
|
||||
<>
|
||||
<Backdrop
|
||||
onClick={this.onClose}
|
||||
visible={isOpen}
|
||||
zIndex={310}
|
||||
isAside={true}
|
||||
/>
|
||||
<StyledBlock>
|
||||
<Selector {...this.props} />
|
||||
|
||||
<StyledControlContainer onClick={this.onClose}>
|
||||
<StyledCrossIcon />
|
||||
</StyledControlContainer>
|
||||
</StyledBlock>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AdvancedSelector.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
||||
style: PropTypes.object,
|
||||
options: PropTypes.array,
|
||||
selectedOptions: PropTypes.array,
|
||||
groups: PropTypes.array,
|
||||
selectedGroups: PropTypes.array,
|
||||
|
||||
value: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
selectAllLabel: PropTypes.string,
|
||||
buttonLabel: PropTypes.string,
|
||||
|
||||
maxHeight: PropTypes.number,
|
||||
|
||||
isMultiSelect: PropTypes.bool,
|
||||
isDisabled: PropTypes.bool,
|
||||
selectedAll: PropTypes.bool,
|
||||
isOpen: PropTypes.bool,
|
||||
allowGroupSelection: PropTypes.bool,
|
||||
allowCreation: PropTypes.bool,
|
||||
allowAnyClickClose: PropTypes.bool,
|
||||
hasNextPage: PropTypes.bool,
|
||||
isNextPageLoading: PropTypes.bool,
|
||||
withoutAside: PropTypes.bool,
|
||||
|
||||
onSearchChanged: PropTypes.func,
|
||||
onSelect: PropTypes.func,
|
||||
onGroupChange: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
onAddNewClick: PropTypes.func,
|
||||
loadNextPage: PropTypes.func,
|
||||
isDefaultDisplayDropDown: PropTypes.bool,
|
||||
};
|
||||
|
||||
AdvancedSelector.defaultProps = {
|
||||
isMultiSelect: false,
|
||||
size: "full",
|
||||
buttonLabel: "Add members",
|
||||
selectAllLabel: "Select all",
|
||||
allowGroupSelection: false,
|
||||
allowAnyClickClose: true,
|
||||
options: [],
|
||||
isDefaultDisplayDropDown: true,
|
||||
};
|
||||
|
||||
export default AdvancedSelector;
|
@ -1,258 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from "react";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
import {
|
||||
withKnobs,
|
||||
text,
|
||||
number,
|
||||
boolean,
|
||||
select,
|
||||
} from "@storybook/addon-knobs/react";
|
||||
import withReadme from "storybook-readme/with-readme";
|
||||
import Readme from "./README.md";
|
||||
import AdvancedSelector2 from ".";
|
||||
import Section from "../../../.storybook/decorators/section";
|
||||
import { Button } from "@docspace/shared/components/button";
|
||||
import equal from "fast-deep-equal/react";
|
||||
import UserTooltip from "@docspace/client/src/components/PeopleSelector/UserTooltip";
|
||||
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
const sizes = ["compact", "full"];
|
||||
const displayTypes = ["dropdown", "aside", "auto"];
|
||||
|
||||
class ADSelectorExample extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const { isOpen, total } = props;
|
||||
|
||||
const groups = this.generateGroups();
|
||||
const users = this.generateUsers(total, groups);
|
||||
|
||||
this.state = this.getDefaultState(isOpen, groups, users);
|
||||
}
|
||||
|
||||
getDefaultState = (isOpen, groups, allOptions) => {
|
||||
return {
|
||||
isOpen: isOpen,
|
||||
allOptions,
|
||||
options: [],
|
||||
groups,
|
||||
hasNextPage: true,
|
||||
isNextPageLoading: false,
|
||||
};
|
||||
};
|
||||
|
||||
generateGroups = () => {
|
||||
return [
|
||||
{
|
||||
key: "group-administration",
|
||||
label: "Administration",
|
||||
total: 0,
|
||||
},
|
||||
{
|
||||
key: "group-dev",
|
||||
label: "Development",
|
||||
total: 0,
|
||||
},
|
||||
{
|
||||
key: "group-management",
|
||||
label: "Management",
|
||||
total: 0,
|
||||
},
|
||||
{
|
||||
key: "group-marketing",
|
||||
label: "Marketing",
|
||||
total: 0,
|
||||
},
|
||||
{
|
||||
key: "group-mobile",
|
||||
label: "Mobile",
|
||||
total: 0,
|
||||
},
|
||||
{
|
||||
key: "group-support",
|
||||
label: "Support",
|
||||
total: 0,
|
||||
},
|
||||
{
|
||||
key: "group-web",
|
||||
label: "Web",
|
||||
total: 0,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
generateUsers = (count, groups) => {
|
||||
return Array.from({ length: count }, (v, index) => {
|
||||
const additional_group = groups[getRandomInt(0, 6)];
|
||||
//groups[0].total++;
|
||||
additional_group.total++;
|
||||
return {
|
||||
key: `user${index}`,
|
||||
groups: [additional_group.key],
|
||||
label: `Demo User ${index}`,
|
||||
avatarUrl: ``,
|
||||
position: `Demo`,
|
||||
email: `demo@demo.demo`,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
loadNextPage = ({ startIndex, searchValue, currentGroup }) => {
|
||||
console.log(
|
||||
`loadNextPage(startIndex=${startIndex}, searchValue="${searchValue}", currentGroup="${currentGroup}")`
|
||||
);
|
||||
this.setState({ isNextPageLoading: true }, () => {
|
||||
setTimeout(() => {
|
||||
const { options } = this.state;
|
||||
|
||||
let filtered = [...this.state.allOptions];
|
||||
|
||||
if (currentGroup) {
|
||||
filtered = filtered.filter(
|
||||
(o) => o.groups.indexOf(currentGroup) > -1
|
||||
);
|
||||
}
|
||||
|
||||
if (searchValue) {
|
||||
filtered = filtered.filter((o) => o.label.indexOf(searchValue) > -1);
|
||||
}
|
||||
|
||||
const newOptions = [...options].concat(
|
||||
filtered.slice(startIndex, startIndex + 100)
|
||||
);
|
||||
|
||||
this.setState({
|
||||
hasNextPage: newOptions.length < filtered.length,
|
||||
isNextPageLoading: false,
|
||||
options: newOptions,
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { total, options, isOpen } = this.props;
|
||||
if (!equal(prevProps.options, options)) {
|
||||
this.setState({
|
||||
options: options,
|
||||
});
|
||||
}
|
||||
|
||||
if (isOpen !== prevProps.isOpen) {
|
||||
this.setState({
|
||||
isOpen: isOpen,
|
||||
});
|
||||
}
|
||||
|
||||
if (total !== prevProps.total) {
|
||||
const groups = this.generateGroups();
|
||||
const users = this.generateUsers(total, groups);
|
||||
this.setState(this.getDefaultState(isOpen, groups, users));
|
||||
}
|
||||
}
|
||||
|
||||
toggle = () => {
|
||||
this.setState({
|
||||
isOpen: !this.state.isOpen,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
isOpen,
|
||||
options,
|
||||
groups,
|
||||
selectedOptions,
|
||||
selectedGroups,
|
||||
hasNextPage,
|
||||
isNextPageLoading,
|
||||
} = this.state;
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
<Button label="Toggle dropdown" onClick={this.toggle} />
|
||||
<AdvancedSelector2
|
||||
options={options}
|
||||
groups={groups}
|
||||
hasNextPage={hasNextPage}
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
loadNextPage={this.loadNextPage}
|
||||
size={select("size", sizes, "full")}
|
||||
displayType={select("displayType", displayTypes, "auto")}
|
||||
selectedOptions={selectedOptions}
|
||||
selectedGroups={selectedGroups}
|
||||
isOpen={isOpen}
|
||||
isMultiSelect={boolean("isMultiSelect", true)}
|
||||
isDisabled={boolean("isDisabled", false)}
|
||||
searchPlaceHolderLabel={text(
|
||||
"searchPlaceHolderLabel",
|
||||
"Search users"
|
||||
)}
|
||||
selectButtonLabel={text("selectButtonLabel", "Add members")}
|
||||
selectAllLabel={text("selectAllLabel", "Select all")}
|
||||
groupsHeaderLabel={text("groupsHeaderLabel", "Groups")}
|
||||
emptySearchOptionsLabel={text(
|
||||
"emptySearchOptionsLabel",
|
||||
"There are no users with such name"
|
||||
)}
|
||||
emptyOptionsLabel={text("emptyOptionsLabel", "There are no users")}
|
||||
loadingLabel={text("loadingLabel", "Loading... Please wait...")}
|
||||
onSelect={(selectedOptions) => {
|
||||
action("onSelect")(selectedOptions);
|
||||
this.toggle();
|
||||
}}
|
||||
onSearchChanged={(value) => {
|
||||
action("onSearchChanged")(value);
|
||||
this.setState({ options: [], hasNextPage: true });
|
||||
}}
|
||||
onGroupChanged={(group) => {
|
||||
action("onGroupChanged")(group);
|
||||
this.setState({ options: [], hasNextPage: true });
|
||||
}}
|
||||
onCancel={() =>
|
||||
this.setState({
|
||||
isOpen: false,
|
||||
})
|
||||
}
|
||||
getOptionTooltipContent={(index) => {
|
||||
if (!index) return null;
|
||||
|
||||
const user = options[+index];
|
||||
|
||||
if (!user) return null;
|
||||
|
||||
// console.log("onOptionTooltipShow", index, user);
|
||||
|
||||
return (
|
||||
<UserTooltip
|
||||
avatarUrl={user.avatarUrl}
|
||||
label={user.label}
|
||||
email={user.email}
|
||||
position={user.position}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
storiesOf("Components|AdvancedSelector", module)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.addParameters({ options: { addonPanelInRight: false } })
|
||||
.add("base", () => {
|
||||
return (
|
||||
<Section>
|
||||
<ADSelectorExample
|
||||
isOpen={boolean("isOpen", true)}
|
||||
total={number("Users count", 10000)}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
# AdvancedSelector
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import AdvancedSelector from "@docspace/common/components/AdvancedSelector";
|
||||
```
|
||||
|
||||
#### Description
|
||||
|
||||
Required to select some advanced data.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
let options = [{ key: "self", label: "Me" }];
|
||||
|
||||
options = [
|
||||
...options,
|
||||
...[...Array(100).keys()].map((index) => {
|
||||
return {
|
||||
key: `user${index}`,
|
||||
label: `User ${index + 1} of ${optionsCount}`,
|
||||
};
|
||||
}),
|
||||
];
|
||||
|
||||
<AdvancedSelector
|
||||
placeholder="Search users"
|
||||
onSearchChanged={(e) => console.log(e.target.value)}
|
||||
options={options}
|
||||
isMultiSelect={false}
|
||||
buttonLabel="Add members"
|
||||
onSelect={(selectedOptions) => console.log("onSelect", selectedOptions)}
|
||||
/>;
|
||||
```
|
||||
|
||||
#### Properties
|
||||
|
||||
| Props | Type | Required | Values | Default | Description |
|
||||
| ----------------- | ------------------ | :------: | ------ | ------- | ----------- |
|
||||
| `placeholder` | `string` | - | | | |
|
||||
| `options` | `array of objects` | - | | | |
|
||||
| `isMultiSelect` | `bool` | - | - | | |
|
||||
| `buttonLabel` | `string` | - | - | | |
|
||||
| `onSearchChanged` | `func` | - | - | | |
|
||||
| `onSelect` | `func` | - | - | | |
|
@ -1,2 +0,0 @@
|
||||
import AdvancedSelector from "./AdvancedSelector";
|
||||
export default AdvancedSelector;
|
@ -1,50 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Button } from "@docspace/shared/components/button";
|
||||
import StyledFooter from "./StyledFooter";
|
||||
|
||||
const Footer = (props) => {
|
||||
const {
|
||||
selectButtonLabel,
|
||||
isDisabled,
|
||||
onClick,
|
||||
isVisible,
|
||||
className,
|
||||
embeddedComponent,
|
||||
selectedLength,
|
||||
showCounter,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<StyledFooter
|
||||
withEmbeddedComponent={embeddedComponent}
|
||||
isVisible={isVisible}
|
||||
className={className}
|
||||
>
|
||||
<Button
|
||||
className="add_members_btn"
|
||||
primary={true}
|
||||
size="normal"
|
||||
label={`${selectButtonLabel} ${
|
||||
selectedLength && showCounter ? `(${selectedLength})` : ""
|
||||
}`}
|
||||
scale={true}
|
||||
isDisabled={isDisabled}
|
||||
onClick={onClick}
|
||||
/>
|
||||
{embeddedComponent && embeddedComponent}
|
||||
</StyledFooter>
|
||||
);
|
||||
};
|
||||
|
||||
Footer.propTypes = {
|
||||
className: PropTypes.string,
|
||||
selectButtonLabel: PropTypes.string,
|
||||
isDisabled: PropTypes.bool,
|
||||
isVisible: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
comboBoxOptions: PropTypes.any,
|
||||
embeddedComponent: PropTypes.any,
|
||||
};
|
||||
|
||||
export default Footer;
|
@ -1,62 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { Avatar } from "@docspace/shared/components/avatar";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Checkbox } from "@docspace/shared/components/checkbox";
|
||||
|
||||
const Group = ({ data, style, index }) => {
|
||||
const { groupList, isMultiSelect, onGroupClick } = data;
|
||||
|
||||
const { label, avatarUrl, total, selectedCount } = groupList[index];
|
||||
|
||||
const isIndeterminate = selectedCount > 0 && selectedCount !== total;
|
||||
|
||||
const isChecked = total !== 0 && total === selectedCount;
|
||||
|
||||
let groupLabel = label;
|
||||
|
||||
if (isMultiSelect && selectedCount > 0) {
|
||||
groupLabel = `${label} (${selectedCount})`;
|
||||
}
|
||||
|
||||
const onGroupClickAction = React.useCallback(() => {
|
||||
onGroupClick && onGroupClick(index);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={style}
|
||||
className="row-option"
|
||||
name={`selector-row-option-${index}`}
|
||||
onClick={onGroupClickAction}
|
||||
>
|
||||
<div className="option-info">
|
||||
<Avatar
|
||||
className="option-avatar"
|
||||
role="user"
|
||||
size="min"
|
||||
source={avatarUrl}
|
||||
userName={label}
|
||||
/>
|
||||
<Text
|
||||
className="option-text option-text__group"
|
||||
truncate={true}
|
||||
noSelect={true}
|
||||
fontSize="14px"
|
||||
>
|
||||
{groupLabel}
|
||||
</Text>
|
||||
</div>
|
||||
{isMultiSelect && (
|
||||
<Checkbox
|
||||
value={`${index}`}
|
||||
isChecked={isChecked}
|
||||
isIndeterminate={isIndeterminate}
|
||||
className="option-checkbox"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Group);
|
@ -1,59 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { Avatar } from "@docspace/shared/components/avatar";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Checkbox } from "@docspace/shared/components/checkbox";
|
||||
const GroupHeader = ({
|
||||
avatarUrl,
|
||||
label,
|
||||
selectedCount,
|
||||
isMultiSelect,
|
||||
onSelectAll,
|
||||
isIndeterminate,
|
||||
isChecked,
|
||||
...rest
|
||||
}) => {
|
||||
const [groupLabel, setGroupLabel] = React.useState(label);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isMultiSelect) {
|
||||
selectedCount > 0
|
||||
? setGroupLabel(`${label} (${selectedCount})`)
|
||||
: setGroupLabel(`${label}`);
|
||||
}
|
||||
}, [selectedCount, isMultiSelect, label]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="row-option row-header">
|
||||
<div className="option-info">
|
||||
<Avatar
|
||||
className="option-avatar"
|
||||
role="user"
|
||||
size="min"
|
||||
source={avatarUrl}
|
||||
userName={label}
|
||||
/>
|
||||
<Text
|
||||
className="option-text option-text__header"
|
||||
truncate={true}
|
||||
noSelect={true}
|
||||
fontSize="14px"
|
||||
>
|
||||
{groupLabel}
|
||||
</Text>
|
||||
</div>
|
||||
{isMultiSelect && (
|
||||
<Checkbox
|
||||
isIndeterminate={isIndeterminate}
|
||||
isChecked={isChecked}
|
||||
onChange={onSelectAll}
|
||||
className="option-checkbox"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(GroupHeader);
|
@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { FixedSizeList as List } from "react-window";
|
||||
import AutoSizer from "react-virtualized-auto-sizer";
|
||||
import { CustomScrollbarsVirtualList } from "@docspace/shared/components/scrollbar";
|
||||
import Group from "./Group";
|
||||
|
||||
const GroupList = ({ groupList, onGroupClick, isMultiSelect }) => {
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<List
|
||||
className="options-list"
|
||||
height={height - 8}
|
||||
width={width + 8}
|
||||
itemCount={groupList.length}
|
||||
itemData={{ groupList, onGroupClick, isMultiSelect }}
|
||||
itemSize={48}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{Group}
|
||||
</List>
|
||||
)}
|
||||
</AutoSizer>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(GroupList);
|
@ -1,25 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { Heading } from "@docspace/shared/components/heading";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
|
||||
import ArrowPathReactSvgUrl from "PUBLIC_DIR/images/arrow.path.react.svg?url";
|
||||
|
||||
const Header = ({ headerLabel, onArrowClickAction }) => {
|
||||
return (
|
||||
<div className="header">
|
||||
<IconButton
|
||||
iconName={ArrowPathReactSvgUrl}
|
||||
size="17"
|
||||
isFill={true}
|
||||
className="arrow-button"
|
||||
onClick={onArrowClickAction}
|
||||
/>
|
||||
<Heading size="medium" truncate={true}>
|
||||
{headerLabel.replace("()", "")}
|
||||
</Heading>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Header);
|
@ -1,97 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { Avatar } from "@docspace/shared/components/avatar";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Checkbox } from "@docspace/shared/components/checkbox";
|
||||
import Loaders from "../../Loaders";
|
||||
|
||||
const Option = ({
|
||||
style,
|
||||
isMultiSelect,
|
||||
index,
|
||||
isChecked,
|
||||
avatarUrl,
|
||||
label,
|
||||
keyProp,
|
||||
onOptionChange,
|
||||
onLinkClick,
|
||||
isLoader,
|
||||
countLoaderRows,
|
||||
}) => {
|
||||
const onOptionChangeAction = React.useCallback(() => {
|
||||
onOptionChange && onOptionChange(index, isChecked);
|
||||
}, [onOptionChange, index, isChecked]);
|
||||
|
||||
const onLinkClickAction = React.useCallback(() => {
|
||||
onLinkClick && onLinkClick(index);
|
||||
}, [onLinkClick, index]);
|
||||
|
||||
return isLoader ? (
|
||||
<div style={style}>
|
||||
<div key="loader" className="option-loader">
|
||||
<Loaders.ListLoader withoutFirstRectangle count={countLoaderRows} />
|
||||
</div>
|
||||
</div>
|
||||
) : isMultiSelect ? (
|
||||
<div
|
||||
style={style}
|
||||
className="row-option"
|
||||
value={`${index}`}
|
||||
name={`selector-row-option-${index}`}
|
||||
onClick={onOptionChangeAction}
|
||||
>
|
||||
<div className="option-info">
|
||||
<Avatar
|
||||
className="option-avatar"
|
||||
role="user"
|
||||
size="min"
|
||||
source={avatarUrl}
|
||||
userName={label}
|
||||
/>
|
||||
<Text
|
||||
className="option-text"
|
||||
truncate={true}
|
||||
noSelect={true}
|
||||
fontSize="14px"
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</div>
|
||||
<Checkbox
|
||||
id={keyProp}
|
||||
value={`${index}`}
|
||||
isChecked={isChecked}
|
||||
className="option-checkbox"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
key={keyProp}
|
||||
style={style}
|
||||
className="row-option"
|
||||
data-index={index}
|
||||
name={`selector-row-option-${index}`}
|
||||
onClick={onLinkClickAction}
|
||||
>
|
||||
<div className="option-info">
|
||||
<Avatar
|
||||
className="option-avatar"
|
||||
role="user"
|
||||
size="min"
|
||||
source={avatarUrl}
|
||||
userName={label}
|
||||
/>
|
||||
<Text
|
||||
className="option-text"
|
||||
truncate={true}
|
||||
noSelect={true}
|
||||
fontSize="14px"
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Option);
|
@ -1,93 +0,0 @@
|
||||
import React from "react";
|
||||
import { FixedSizeList as List } from "react-window";
|
||||
import InfiniteLoader from "react-window-infinite-loader";
|
||||
import AutoSizer from "react-virtualized-auto-sizer";
|
||||
import { CustomScrollbarsVirtualList } from "@docspace/shared/components/scrollbar";
|
||||
|
||||
import Option from "./Option";
|
||||
|
||||
const OptionList = ({
|
||||
listOptionsRef,
|
||||
options,
|
||||
isOptionChecked,
|
||||
isMultiSelect,
|
||||
onOptionChange,
|
||||
onLinkClick,
|
||||
isItemLoaded,
|
||||
itemCount,
|
||||
loadMoreItems,
|
||||
isFirstLoad,
|
||||
}) => {
|
||||
const renderOption = React.useCallback(
|
||||
({ index, style }) => {
|
||||
const isLoaded = isItemLoaded(index);
|
||||
|
||||
if (!isLoaded) {
|
||||
if (!isFirstLoad) {
|
||||
return (
|
||||
<div style={style}>
|
||||
<Option isLoader={true} countLoaderRows={2} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <Option isLoader={true} />;
|
||||
}
|
||||
|
||||
const option = options[index];
|
||||
const isChecked = isOptionChecked(option);
|
||||
|
||||
return (
|
||||
<Option
|
||||
index={index}
|
||||
style={style}
|
||||
{...option}
|
||||
isChecked={isChecked}
|
||||
onOptionChange={onOptionChange}
|
||||
onLinkClick={onLinkClick}
|
||||
isMultiSelect={isMultiSelect}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[
|
||||
options,
|
||||
isMultiSelect,
|
||||
|
||||
isItemLoaded,
|
||||
isOptionChecked,
|
||||
|
||||
onOptionChange,
|
||||
onLinkClick,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<InfiniteLoader
|
||||
ref={listOptionsRef}
|
||||
isItemLoaded={isItemLoaded}
|
||||
itemCount={itemCount}
|
||||
loadMoreItems={loadMoreItems}
|
||||
>
|
||||
{({ onItemsRendered, ref }) => (
|
||||
<List
|
||||
className="options-list"
|
||||
height={height - 73}
|
||||
itemCount={itemCount}
|
||||
itemSize={48}
|
||||
onItemsRendered={onItemsRendered}
|
||||
ref={ref}
|
||||
width={width + 8}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{renderOption}
|
||||
</List>
|
||||
)}
|
||||
</InfiniteLoader>
|
||||
)}
|
||||
</AutoSizer>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(OptionList);
|
@ -1,29 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { SearchInput } from "@docspace/shared/components/search-input";
|
||||
|
||||
const Search = ({
|
||||
isDisabled,
|
||||
searchPlaceHolderLabel,
|
||||
searchValue,
|
||||
onSearchChange,
|
||||
onSearchReset,
|
||||
}) => {
|
||||
return (
|
||||
<div className="header-options">
|
||||
<SearchInput
|
||||
className="options_searcher"
|
||||
isDisabled={isDisabled}
|
||||
size="base"
|
||||
scale={true}
|
||||
isNeedFilter={false}
|
||||
placeholder={searchPlaceHolderLabel}
|
||||
value={searchValue}
|
||||
onChange={onSearchChange}
|
||||
onClearSearch={onSearchReset}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Search);
|
@ -1,447 +0,0 @@
|
||||
import React, { useRef, useState, useEffect, useCallback } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import Header from "./Header";
|
||||
import Search from "./Search";
|
||||
import GroupList from "./GroupList";
|
||||
import GroupHeader from "./GroupHeader";
|
||||
import OptionList from "./OptionList";
|
||||
import Option from "./Option";
|
||||
|
||||
import Footer from "./Footer";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Tooltip } from "@docspace/shared/components/tooltip";
|
||||
|
||||
import StyledSelector from "./StyledSelector";
|
||||
|
||||
const convertGroups = (items) => {
|
||||
if (!items) return [];
|
||||
|
||||
const wrappedGroups = items.map(convertGroup);
|
||||
|
||||
return wrappedGroups;
|
||||
};
|
||||
|
||||
const convertGroup = (group) => {
|
||||
return {
|
||||
key: group.key,
|
||||
label: `${group.label} (${group.total})`,
|
||||
total: group.total,
|
||||
selectedCount: 0,
|
||||
};
|
||||
};
|
||||
|
||||
const getCurrentGroup = (items) => {
|
||||
const currentGroup = items.length > 0 ? items[0] : {};
|
||||
return currentGroup;
|
||||
};
|
||||
|
||||
const Selector = (props) => {
|
||||
const {
|
||||
groups,
|
||||
isDisabled,
|
||||
isMultiSelect,
|
||||
hasNextPage,
|
||||
options,
|
||||
isNextPageLoading,
|
||||
loadNextPage,
|
||||
selectedOptions,
|
||||
selectedGroups,
|
||||
searchPlaceHolderLabel,
|
||||
emptySearchOptionsLabel,
|
||||
emptyOptionsLabel,
|
||||
loadingLabel,
|
||||
onSelect,
|
||||
getOptionTooltipContent,
|
||||
onSearchChanged,
|
||||
onGroupChanged,
|
||||
size,
|
||||
embeddedComponent,
|
||||
showCounter,
|
||||
onArrowClick,
|
||||
headerLabel,
|
||||
total,
|
||||
isFirstLoad,
|
||||
} = props;
|
||||
|
||||
const listOptionsRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
Object.keys(currentGroup).length === 0 &&
|
||||
setCurrentGroup(getCurrentGroup(convertGroups(groups)));
|
||||
resetCache();
|
||||
}, [searchValue, currentGroup, hasNextPage]);
|
||||
|
||||
const resetCache = useCallback(() => {
|
||||
if (listOptionsRef && listOptionsRef.current) {
|
||||
listOptionsRef.current.resetloadMoreItemsCache(true);
|
||||
}
|
||||
}, [listOptionsRef]);
|
||||
|
||||
const [selectedOptionList, setSelectedOptionList] = useState(
|
||||
selectedOptions || []
|
||||
);
|
||||
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
|
||||
const [groupList, setGroupList] = useState([]);
|
||||
|
||||
const [currentGroup, setCurrentGroup] = useState(
|
||||
getCurrentGroup(convertGroups(groups))
|
||||
);
|
||||
|
||||
const [groupHeader, setGroupHeader] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (groups.length === 0) return;
|
||||
|
||||
const newGroupList = [...groups];
|
||||
|
||||
if (
|
||||
groups.length === 1 &&
|
||||
selectedOptions &&
|
||||
selectedOptions.length === 0
|
||||
) {
|
||||
return setGroupHeader(newGroupList[0]);
|
||||
}
|
||||
|
||||
if (selectedOptions && selectedOptions.length === 0) {
|
||||
return setGroupList(newGroupList);
|
||||
}
|
||||
|
||||
if (selectedOptions) {
|
||||
newGroupList[0].selectedCount = selectedOptions.length;
|
||||
|
||||
if (groups.length === 1) return setGroupHeader(newGroupList[0]);
|
||||
selectedOptions.forEach((option) => {
|
||||
option?.groups?.forEach((group) => {
|
||||
const groupIndex = newGroupList.findIndex(
|
||||
(newGroup) => group === newGroup.id
|
||||
);
|
||||
|
||||
if (groupIndex > -1) {
|
||||
newGroupList[groupIndex].selectedCount =
|
||||
newGroupList[groupIndex].selectedCount + 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (groups.length === 1) return setGroupHeader(newGroupList[0]);
|
||||
setGroupList(newGroupList);
|
||||
}, [groups, selectedOptions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (total) {
|
||||
setGroupHeader({ ...groupHeader, total: total });
|
||||
|
||||
const newGroupList = groupList;
|
||||
|
||||
if (newGroupList.length > 0) {
|
||||
newGroupList.find((group) => group.key === groupHeader.key).total =
|
||||
total;
|
||||
}
|
||||
|
||||
setGroupList(newGroupList);
|
||||
}
|
||||
}, [total]);
|
||||
|
||||
const onSearchChange = useCallback(
|
||||
(value) => {
|
||||
setSearchValue(value);
|
||||
onSearchChanged && onSearchChanged(value);
|
||||
},
|
||||
[onSearchChanged]
|
||||
);
|
||||
|
||||
const onSearchReset = useCallback(() => {
|
||||
onSearchChanged && onSearchChange("");
|
||||
}, [onSearchChanged]);
|
||||
|
||||
// Every row is loaded except for our loading indicator row.
|
||||
const isItemLoaded = useCallback(
|
||||
(index) => {
|
||||
return !hasNextPage || index < options.length;
|
||||
},
|
||||
[hasNextPage, options]
|
||||
);
|
||||
|
||||
const onOptionChange = useCallback(
|
||||
(idx, isChecked) => {
|
||||
const indexList = Array.isArray(idx) ? idx : [idx];
|
||||
|
||||
let newSelected = selectedOptionList;
|
||||
let newGroupList = groupList;
|
||||
let newGroupHeader = { ...groupHeader };
|
||||
|
||||
indexList.forEach((index) => {
|
||||
newGroupHeader.selectedCount = isChecked
|
||||
? newGroupHeader.selectedCount - 1
|
||||
: newGroupHeader.selectedCount + 1;
|
||||
|
||||
const option = options[index];
|
||||
|
||||
newSelected = !isChecked
|
||||
? [option, ...newSelected]
|
||||
: newSelected.filter((el) => el.key !== option.key);
|
||||
|
||||
if (!option.groups) {
|
||||
setSelectedOptionList(newSelected);
|
||||
setGroupHeader(newGroupHeader);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newGroupList.length) {
|
||||
newGroupList[0].selectedCount = isChecked
|
||||
? newGroupList[0].selectedCount - 1
|
||||
: newGroupList[0].selectedCount + 1;
|
||||
|
||||
option.groups.forEach((group) => {
|
||||
const groupIndex = newGroupList.findIndex(
|
||||
(item) => item.key === group
|
||||
);
|
||||
|
||||
if (groupIndex > 0) {
|
||||
newGroupList[groupIndex].selectedCount = isChecked
|
||||
? newGroupList[groupIndex].selectedCount - 1
|
||||
: newGroupList[groupIndex].selectedCount + 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
setSelectedOptionList(newSelected);
|
||||
setGroupList(newGroupList);
|
||||
setGroupHeader(newGroupHeader);
|
||||
},
|
||||
[options, groupList, selectedOptionList, groupHeader]
|
||||
);
|
||||
|
||||
const isOptionChecked = useCallback(
|
||||
(option) => {
|
||||
const checked = selectedOptionList.find(
|
||||
(item) => item.key === option.key
|
||||
);
|
||||
|
||||
return !!checked;
|
||||
},
|
||||
[selectedOptionList]
|
||||
);
|
||||
|
||||
const onSelectOptions = (items) => {
|
||||
onSelect && onSelect(items);
|
||||
};
|
||||
|
||||
const onAddClick = useCallback(() => {
|
||||
onSelectOptions(selectedOptionList);
|
||||
}, [selectedOptionList]);
|
||||
|
||||
const onLinkClick = useCallback(
|
||||
(index) => {
|
||||
const option = options[index];
|
||||
|
||||
if (!option) return;
|
||||
|
||||
onSelectOptions([option]);
|
||||
},
|
||||
[options]
|
||||
);
|
||||
|
||||
// If there are more items to be loaded then add an extra row to hold a loading indicator.
|
||||
|
||||
// Only load 1 page of items at a time.
|
||||
// Pass an empty callback to InfiniteLoader in case it asks us to load more than once.
|
||||
const loadMoreItems = useCallback(
|
||||
(startIndex) => {
|
||||
if (isNextPageLoading) return;
|
||||
|
||||
const options = {
|
||||
startIndex: startIndex || 0,
|
||||
searchValue: searchValue,
|
||||
currentGroup: currentGroup ? currentGroup.key : null,
|
||||
};
|
||||
|
||||
loadNextPage && loadNextPage(options);
|
||||
},
|
||||
[isNextPageLoading, searchValue, currentGroup, options]
|
||||
);
|
||||
|
||||
const onSelectAll = useCallback(() => {
|
||||
const currentSelectedOption = [];
|
||||
selectedOptionList.forEach((selectedOption) => {
|
||||
options.forEach((option, idx) => {
|
||||
if (option.key === selectedOption.key) currentSelectedOption.push(idx);
|
||||
});
|
||||
});
|
||||
|
||||
if (currentSelectedOption.length > 0) {
|
||||
return onOptionChange(currentSelectedOption, true);
|
||||
}
|
||||
|
||||
onOptionChange(
|
||||
options.map((item, index) => index),
|
||||
false
|
||||
);
|
||||
}, [onOptionChange, selectedOptionList, options]);
|
||||
|
||||
const onGroupClick = useCallback(
|
||||
(index) => {
|
||||
const group = groupList[index];
|
||||
|
||||
setGroupHeader({ ...group });
|
||||
|
||||
onGroupChanged && onGroupChanged(group);
|
||||
setCurrentGroup(group);
|
||||
},
|
||||
[groupList, onGroupChanged]
|
||||
);
|
||||
|
||||
const onArrowClickAction = useCallback(() => {
|
||||
if (groupHeader && groups.length !== 1) {
|
||||
setGroupHeader(null);
|
||||
|
||||
onGroupChanged && onGroupChanged([]);
|
||||
setCurrentGroup([]);
|
||||
return;
|
||||
}
|
||||
|
||||
onArrowClick && onArrowClick();
|
||||
}, [groups, groupHeader && groupHeader.label, onArrowClick, onGroupChanged]);
|
||||
|
||||
const renderGroupsList = useCallback(() => {
|
||||
if (groupList.length === 0) {
|
||||
return <Option isLoader={true} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<GroupList
|
||||
groupList={groupList}
|
||||
isMultiSelect={isMultiSelect}
|
||||
onGroupClick={onGroupClick}
|
||||
/>
|
||||
);
|
||||
}, [isMultiSelect, groupList, onGroupClick]);
|
||||
|
||||
const itemCount = hasNextPage ? options.length + 1 : options.length;
|
||||
const hasSelected = selectedOptionList.length > 0;
|
||||
|
||||
return (
|
||||
<StyledSelector
|
||||
isMultiSelect={isMultiSelect}
|
||||
hasSelected={hasSelected}
|
||||
className="selector-wrapper"
|
||||
>
|
||||
<Header
|
||||
headerLabel={headerLabel}
|
||||
onArrowClickAction={onArrowClickAction}
|
||||
/>
|
||||
<div style={{ height: "100%" }} className="column-options" size={size}>
|
||||
<Search
|
||||
isDisabled={isDisabled}
|
||||
placeholder={searchPlaceHolderLabel}
|
||||
value={searchValue}
|
||||
onSearchChange={onSearchChange}
|
||||
onClearSearch={onSearchReset}
|
||||
/>
|
||||
<div style={{ width: "100%", height: "100%" }} className="body-options">
|
||||
{!groupHeader && !searchValue && groups ? (
|
||||
renderGroupsList()
|
||||
) : (
|
||||
<>
|
||||
{!searchValue && (
|
||||
<>
|
||||
<GroupHeader
|
||||
{...groupHeader}
|
||||
onSelectAll={onSelectAll}
|
||||
isMultiSelect={isMultiSelect}
|
||||
isIndeterminate={
|
||||
groupHeader.selectedCount > 0 &&
|
||||
groupHeader.selectedCount !== groupHeader.total
|
||||
}
|
||||
isChecked={
|
||||
groupHeader.total !== 0 &&
|
||||
groupHeader.total === groupHeader.selectedCount
|
||||
}
|
||||
/>
|
||||
<div className="option-separator"></div>
|
||||
</>
|
||||
)}
|
||||
{!hasNextPage && itemCount === 0 ? (
|
||||
<div className="row-option">
|
||||
<Text>
|
||||
{!searchValue ? emptyOptionsLabel : emptySearchOptionsLabel}
|
||||
</Text>
|
||||
</div>
|
||||
) : (
|
||||
<OptionList
|
||||
listOptionsRef={listOptionsRef}
|
||||
options={options}
|
||||
itemCount={itemCount}
|
||||
isMultiSelect={isMultiSelect}
|
||||
onOptionChange={onOptionChange}
|
||||
onLinkClick={onLinkClick}
|
||||
isItemLoaded={isItemLoaded}
|
||||
isOptionChecked={isOptionChecked}
|
||||
loadMoreItems={loadMoreItems}
|
||||
isFirstLoad={isFirstLoad}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{getOptionTooltipContent && (
|
||||
<Tooltip
|
||||
id="user"
|
||||
offsetRight={90}
|
||||
getContent={getOptionTooltipContent}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Footer
|
||||
className="footer"
|
||||
selectButtonLabel={headerLabel}
|
||||
showCounter={showCounter}
|
||||
isDisabled={isDisabled}
|
||||
isVisible={isMultiSelect && hasSelected}
|
||||
onClick={onAddClick}
|
||||
embeddedComponent={embeddedComponent}
|
||||
selectedLength={selectedOptionList.length}
|
||||
/>
|
||||
</StyledSelector>
|
||||
);
|
||||
};
|
||||
|
||||
Selector.propTypes = {
|
||||
options: PropTypes.array,
|
||||
groups: PropTypes.array,
|
||||
|
||||
hasNextPage: PropTypes.bool,
|
||||
isNextPageLoading: PropTypes.bool,
|
||||
loadNextPage: PropTypes.func,
|
||||
|
||||
isDisabled: PropTypes.bool,
|
||||
isMultiSelect: PropTypes.bool,
|
||||
allowGroupSelection: PropTypes.bool,
|
||||
isFirstLoad: PropTypes.bool,
|
||||
|
||||
selectButtonLabel: PropTypes.string,
|
||||
selectAllLabel: PropTypes.string,
|
||||
searchPlaceHolderLabel: PropTypes.string,
|
||||
groupsHeaderLabel: PropTypes.string,
|
||||
emptySearchOptionsLabel: PropTypes.string,
|
||||
emptyOptionsLabel: PropTypes.string,
|
||||
loadingLabel: PropTypes.string,
|
||||
|
||||
selectedOptions: PropTypes.array,
|
||||
selectedGroups: PropTypes.array,
|
||||
|
||||
onSelect: PropTypes.func,
|
||||
onSearchChanged: PropTypes.func,
|
||||
onGroupChanged: PropTypes.func,
|
||||
getOptionTooltipContent: PropTypes.func,
|
||||
|
||||
embeddedComponent: PropTypes.any,
|
||||
};
|
||||
|
||||
export default React.memo(Selector);
|
@ -1,38 +0,0 @@
|
||||
import styled, { css } from "styled-components";
|
||||
import Base from "../../../../components/themes/base";
|
||||
|
||||
const StyledFooter = styled.div`
|
||||
box-sizing: border-box;
|
||||
border-top: ${(props) => props.theme.advancedSelector.footerBorder};
|
||||
padding: 16px;
|
||||
height: 69px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
${(props) =>
|
||||
props.withEmbeddedComponent &&
|
||||
css`
|
||||
display: flex;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
!props.isVisible &&
|
||||
css`
|
||||
display: none;
|
||||
`}
|
||||
|
||||
button {
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.embedded_combo-box {
|
||||
.combo-button {
|
||||
min-height: 42px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
StyledFooter.defaultProps = { theme: Base };
|
||||
|
||||
export default StyledFooter;
|
@ -1,212 +0,0 @@
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import Base from "@docspace/shared/themes/base";
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
/* eslint-disable react/prop-types */
|
||||
|
||||
/* eslint-enable react/prop-types */
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
const StyledSelector = styled.div`
|
||||
display: grid;
|
||||
|
||||
height: 100%;
|
||||
grid-template-columns: 1fr;
|
||||
${(props) =>
|
||||
props.isMultiSelect && props.hasSelected
|
||||
? css`
|
||||
grid-template-rows: 53px 1fr 69px;
|
||||
grid-template-areas: "header" "column-options" "footer";
|
||||
`
|
||||
: css`
|
||||
grid-template-rows: 53px 1fr;
|
||||
grid-template-areas: "header" "column-options";
|
||||
`}
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
|
||||
height: 53px;
|
||||
min-height: 53px;
|
||||
|
||||
padding: 0 16px;
|
||||
margin: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
|
||||
.arrow-button {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `margin-left: 12px;`
|
||||
: `margin-right: 12px;`}
|
||||
}
|
||||
|
||||
svg {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.column-options {
|
||||
grid-area: column-options;
|
||||
box-sizing: border-box;
|
||||
|
||||
display: grid;
|
||||
|
||||
padding: 0;
|
||||
grid-row-gap: 2px;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 30px 1fr;
|
||||
grid-template-areas: "header-options" "body-options";
|
||||
|
||||
.header-options {
|
||||
grid-area: header-options;
|
||||
|
||||
padding: 0 16px;
|
||||
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `margin-left: 0px !important;`
|
||||
: `margin-right: 0px !important;`}
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 30px;
|
||||
|
||||
grid-template-areas: "options_searcher";
|
||||
|
||||
.options_searcher {
|
||||
grid-area: options_searcher;
|
||||
}
|
||||
|
||||
.options_searcher {
|
||||
div:first-child {
|
||||
:hover {
|
||||
border-color: ${(props) =>
|
||||
props.theme.advancedSelector.searcher.hoverBorderColor};
|
||||
}
|
||||
|
||||
:focus,
|
||||
:focus-within {
|
||||
border-color: ${(props) =>
|
||||
props.theme.advancedSelector.searcher.focusBorderColor};
|
||||
}
|
||||
|
||||
& > input::placeholder {
|
||||
color: ${(props) =>
|
||||
props.theme.advancedSelector.searcher.placeholderColor};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.body-options {
|
||||
grid-area: body-options;
|
||||
margin-top: 8px;
|
||||
|
||||
.options-list {
|
||||
div:nth-child(3) {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `left: 10px !important;`
|
||||
: `right: 10px !important;`}
|
||||
}
|
||||
}
|
||||
.option-loader {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.row-option {
|
||||
box-sizing: border-box;
|
||||
height: 48px;
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 0 16px;
|
||||
|
||||
&:hover {
|
||||
background-color: ${(props) =>
|
||||
props.theme.advancedSelector.hoverBackgroundColor};
|
||||
}
|
||||
|
||||
.option-info {
|
||||
width: calc(100% - 32px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.option-avatar {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `margin-left: 12px;`
|
||||
: `margin-right: 12px;`}
|
||||
min-width: 32px;
|
||||
max-width: 32px;
|
||||
}
|
||||
|
||||
.option-text {
|
||||
max-width: 100%;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.option-text__group {
|
||||
width: auto;
|
||||
border-bottom: ${(props) =>
|
||||
props.theme.toggleContent.hoverBorderBottom};
|
||||
}
|
||||
|
||||
.option-text__header {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.option-checkbox {
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
min-width: 16px;
|
||||
max-width: 16px;
|
||||
}
|
||||
}
|
||||
.option-separator {
|
||||
height: 1px;
|
||||
background: ${(props) =>
|
||||
props.theme.advancedSelector.selectedBackgroundColor};
|
||||
margin: 8px 16px;
|
||||
}
|
||||
|
||||
.row-header {
|
||||
cursor: auto;
|
||||
|
||||
.option-checkbox {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `margin-left: 0 !important;`
|
||||
: `margin-right: 0 !important;`}
|
||||
}
|
||||
|
||||
:hover {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
grid-area: footer;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledSelector.defaultProps = { theme: Base };
|
||||
|
||||
export default StyledSelector;
|
@ -1,31 +0,0 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Loader } from "@docspace/shared/components/loader";
|
||||
import Section from "../Section";
|
||||
|
||||
export class ExternalRedirect extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { to } = this.props;
|
||||
to && window.location.replace(to);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<Loader className="pageLoader" type="rombs" size="40px" />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ExternalRedirect.propTypes = {
|
||||
to: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ExternalRedirect;
|
@ -1 +0,0 @@
|
||||
export default from "./ExternalRedirect";
|
@ -1,50 +0,0 @@
|
||||
import React from "react";
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
import StyledDialogAsideLoader from "./StyledDialogAsideLoader";
|
||||
import { Aside } from "@docspace/shared/components/aside";
|
||||
import { Backdrop } from "@docspace/shared/components/backdrop";
|
||||
|
||||
const DialogAsideLoader = ({
|
||||
isPanel,
|
||||
withoutAside,
|
||||
withFooterBorder = false,
|
||||
}) => {
|
||||
const zIndex = 310;
|
||||
|
||||
const renderClearDialogAsideLoader = () => {
|
||||
return (
|
||||
<StyledDialogAsideLoader
|
||||
withFooterBorder={withFooterBorder}
|
||||
isPanel={isPanel}
|
||||
visible
|
||||
>
|
||||
<div className="dialog-loader-header">
|
||||
<RectangleSkeleton height="29px" />
|
||||
</div>
|
||||
<div className="dialog-loader-body">
|
||||
<RectangleSkeleton height="200px" />
|
||||
</div>
|
||||
|
||||
<div className="dialog-loader-footer">
|
||||
<RectangleSkeleton height="40px" />
|
||||
<RectangleSkeleton height="40px" />
|
||||
</div>
|
||||
</StyledDialogAsideLoader>
|
||||
);
|
||||
};
|
||||
|
||||
return withoutAside ? (
|
||||
renderClearDialogAsideLoader()
|
||||
) : (
|
||||
<>
|
||||
<Backdrop visible isAside zIndex={zIndex} />
|
||||
<StyledDialogAsideLoader visible isPanel={isPanel}>
|
||||
<Aside className="dialog-aside-loader" visible zIndex={zIndex}>
|
||||
{renderClearDialogAsideLoader()}
|
||||
</Aside>
|
||||
</StyledDialogAsideLoader>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DialogAsideLoader;
|
@ -1,63 +0,0 @@
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
const StyledDialogAsideLoader = styled.div`
|
||||
${(props) =>
|
||||
props.isPanel
|
||||
? css`
|
||||
.dialog-loader-header {
|
||||
padding: 12px 16px;
|
||||
|
||||
height: 53px;
|
||||
|
||||
border-bottom: ${(props) =>
|
||||
`1px solid ${props.theme.modalDialog.headerBorderColor}`};
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.dialog-loader-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.dialog-loader-footer {
|
||||
padding: 12px 16px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
|
||||
height: 71px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
border-top: ${(props) =>
|
||||
`1px solid ${props.theme.modalDialog.headerBorderColor}`};
|
||||
}
|
||||
`
|
||||
: css`
|
||||
.dialog-loader-header {
|
||||
border-bottom: ${(props) =>
|
||||
`1px solid ${props.theme.modalDialog.headerBorderColor}`};
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.dialog-loader-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.dialog-loader-footer {
|
||||
${(props) =>
|
||||
props.withFooterBorder &&
|
||||
`border-top: 1px solid ${props.theme.modalDialog.headerBorderColor}`};
|
||||
padding: 16px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
export default StyledDialogAsideLoader;
|
@ -1 +0,0 @@
|
||||
export default from "./DialogAsideLoader";
|
@ -1,22 +0,0 @@
|
||||
import React from "react";
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
import StyledDialogLoader from "./StyledDialogLoader";
|
||||
|
||||
const DialogLoader = ({ isLarge, withFooterBorder }) => {
|
||||
return (
|
||||
<StyledDialogLoader withFooterBorder={withFooterBorder} isLarge={isLarge}>
|
||||
<div className="dialog-loader-header">
|
||||
<RectangleSkeleton height="29px" />
|
||||
</div>
|
||||
<div className="dialog-loader-body">
|
||||
<RectangleSkeleton height={isLarge ? "175px" : "73px"} />
|
||||
</div>
|
||||
<div className="dialog-loader-footer">
|
||||
<RectangleSkeleton height="40px" />
|
||||
<RectangleSkeleton height="40px" />
|
||||
</div>
|
||||
</StyledDialogLoader>
|
||||
);
|
||||
};
|
||||
|
||||
export default DialogLoader;
|
@ -1,34 +0,0 @@
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
import styled from "styled-components";
|
||||
import { mobile } from "@docspace/shared/utils";
|
||||
|
||||
const StyledDialogLoader = styled.div`
|
||||
height: auto;
|
||||
width: ${(props) => (props.isLarge ? "520px" : "400px")};
|
||||
@media ${mobile} {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dialog-loader-header {
|
||||
border-bottom: ${(props) =>
|
||||
`1px solid ${props.theme.modalDialog.headerBorderColor}`};
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.dialog-loader-body {
|
||||
padding: 12px 16px 8px;
|
||||
}
|
||||
|
||||
.dialog-loader-footer {
|
||||
${(props) =>
|
||||
props.withFooterBorder &&
|
||||
`border-top: 1px solid ${props.theme.modalDialog.headerBorderColor}`};
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
padding: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledDialogLoader.defaultProps = { theme: Base };
|
||||
|
||||
export default StyledDialogLoader;
|
@ -1 +0,0 @@
|
||||
export default from "./DialogLoader";
|
@ -1,47 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { RowsSkeleton } from "@docspace/shared/skeletons";
|
||||
import { TilesSkeleton } from "@docspace/shared/skeletons/tiles";
|
||||
|
||||
import { isMobile, isTablet } from "@docspace/shared/utils";
|
||||
|
||||
const EmptyContainerLoader = ({ viewAs, style, ...rest }) => {
|
||||
const [viewMobile, setViewMobile] = useState(false);
|
||||
const [viewTablet, setViewTablet] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
onCheckView();
|
||||
window.addEventListener("resize", onCheckView);
|
||||
|
||||
return () => window.removeEventListener("resize", onCheckView);
|
||||
}, []);
|
||||
|
||||
const onCheckView = () => {
|
||||
if (isMobile()) {
|
||||
setViewMobile(true);
|
||||
} else {
|
||||
setViewMobile(false);
|
||||
}
|
||||
|
||||
if (isTablet()) {
|
||||
setViewTablet(true);
|
||||
} else {
|
||||
setViewTablet(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div {...rest} style={{ display: "contents", style }}>
|
||||
{viewAs === "tile" ? (
|
||||
!viewMobile && !viewTablet ? (
|
||||
<TilesSkeleton filesCount={7} />
|
||||
) : (
|
||||
<TilesSkeleton />
|
||||
)
|
||||
) : (
|
||||
<RowsSkeleton count={(viewMobile && 8) || (viewTablet && 12) || 9} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptyContainerLoader;
|
@ -1 +0,0 @@
|
||||
export default from "./EmptyContainerLoader";
|
@ -1,93 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { StyledGroup, StyledLastRow, StyledSpacer } from "./StyledGroupLoader";
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
|
||||
const GroupLoader = ({ id, className, style, ...rest }) => {
|
||||
const {
|
||||
title,
|
||||
borderRadius,
|
||||
backgroundColor,
|
||||
foregroundColor,
|
||||
backgroundOpacity,
|
||||
foregroundOpacity,
|
||||
speed,
|
||||
animate,
|
||||
} = rest;
|
||||
|
||||
return (
|
||||
<StyledGroup id={id} className={className} style={style}>
|
||||
<RectangleSkeleton
|
||||
title={title}
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
<RectangleSkeleton
|
||||
title={title}
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
<RectangleSkeleton
|
||||
title={title}
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
<StyledSpacer />
|
||||
<StyledLastRow>
|
||||
<RectangleSkeleton
|
||||
title={title}
|
||||
width="100"
|
||||
height="36"
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
<RectangleSkeleton
|
||||
title={title}
|
||||
width="100"
|
||||
height="36"
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
</StyledLastRow>
|
||||
</StyledGroup>
|
||||
);
|
||||
};
|
||||
|
||||
GroupLoader.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
GroupLoader.defaultProps = {
|
||||
id: undefined,
|
||||
className: undefined,
|
||||
style: undefined,
|
||||
};
|
||||
|
||||
export default GroupLoader;
|
@ -1,40 +0,0 @@
|
||||
import React from "react";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import {
|
||||
withKnobs,
|
||||
boolean,
|
||||
text,
|
||||
color,
|
||||
number,
|
||||
} from "@storybook/addon-knobs/react";
|
||||
import Section from "../../../../.storybook/decorators/section";
|
||||
|
||||
import Loaders from "..";
|
||||
import { LOADER_STYLE } from "@docspace/shared/constants";
|
||||
import withReadme from "storybook-readme/with-readme";
|
||||
import Readme from "./README.md";
|
||||
|
||||
storiesOf("Components|Loaders", module)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add("group loader", () => (
|
||||
<Section>
|
||||
<h1>Group Loader</h1>
|
||||
<Loaders.Group
|
||||
title={text("title", LOADER_STYLE.title)}
|
||||
borderRadius={text("borderRadius", "3")}
|
||||
backgroundColor={color("backgroundColor", LOADER_STYLE.backgroundColor)}
|
||||
foregroundColor={color("foregroundColor", LOADER_STYLE.foregroundColor)}
|
||||
backgroundOpacity={number(
|
||||
"backgroundOpacity",
|
||||
LOADER_STYLE.backgroundOpacity
|
||||
)}
|
||||
foregroundOpacity={number(
|
||||
"foregroundOpacity",
|
||||
LOADER_STYLE.foregroundOpacity
|
||||
)}
|
||||
speed={number("speed", LOADER_STYLE.speed)}
|
||||
animate={boolean("animate", LOADER_STYLE.animate)}
|
||||
/>
|
||||
</Section>
|
||||
));
|
@ -1,26 +0,0 @@
|
||||
# Group Loader
|
||||
|
||||
Component that displays group loader
|
||||
|
||||
### Usage
|
||||
|
||||
```js
|
||||
import Loaders from "@docspace/common/components/Loaders";
|
||||
```
|
||||
|
||||
```jsx
|
||||
<Loaders.Group />
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Props | Type | Required | Values | Default | Description |
|
||||
| ------------------- | :------: | :------: | :----: | :-------: | ------------------------------------------------ |
|
||||
| `title` | `string` | - | - | `` | It's used to describe what element it is. |
|
||||
| `borderRadius` | `string` | - | - | `3` | Sets the corners rounding |
|
||||
| `backgroundColor` | `string` | - | - | `#000000` | Used as background of animation |
|
||||
| `foregroundColor` | `string` | - | - | `#000000` | Used as the foreground of animation |
|
||||
| `backgroundOpacity` | `number` | - | - | 0.2 | Background opacity (0 = transparent, 1 = opaque) |
|
||||
| `foregroundOpacity` | `number` | - | - | 0.15 | Animation opacity (0 = transparent, 1 = opaque) |
|
||||
| `speed` | `number` | - | - | 2 | Animation speed in seconds |
|
||||
| `animate` | `bool` | - | - | true | Opt-out of animations |
|
@ -1,27 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
import { mobile } from "@docspace/shared/utils";
|
||||
|
||||
const StyledGroup = styled.div`
|
||||
width: 400px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr 1fr 1fr 1fr;
|
||||
grid-row-gap: 14px;
|
||||
|
||||
@media ${mobile} {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledLastRow = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: 100px 100px;
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 8px;
|
||||
`;
|
||||
|
||||
const StyledSpacer = styled.div`
|
||||
margin-top: 32px;
|
||||
`;
|
||||
|
||||
export { StyledGroup, StyledLastRow, StyledSpacer };
|
@ -1 +0,0 @@
|
||||
export default from "./GroupLoader";
|
@ -1,31 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
import { desktop } from "@docspace/shared/utils";
|
||||
|
||||
const StyledTreeFolder = styled.div`
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `padding-left: 16px;`
|
||||
: `padding-right: 16px;`}
|
||||
`;
|
||||
|
||||
const StyledLoader = styled.div`
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 8px 16px 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 6px;
|
||||
margin-bottom: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.tree-node-loader_additional-rectangle {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.paddingLeft &&
|
||||
(props.theme.interfaceDirection === "rtl"
|
||||
? `padding-right: ${props.paddingLeft}`
|
||||
: `padding-left: ${props.paddingLeft}`)};
|
||||
`;
|
||||
|
||||
export { StyledLoader, StyledTreeFolder };
|
@ -1,51 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { StyledTreeFolder, StyledLoader } from "./StyledTreeFolder";
|
||||
import TreeNodeLoader from "../TreeNodeLoader";
|
||||
|
||||
const NewTreeFolderLoader = ({ id, className, style, ...rest }) => {
|
||||
return (
|
||||
<StyledTreeFolder id={id} className={className} style={style}>
|
||||
<StyledLoader>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"16px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
|
||||
<StyledLoader paddingLeft={"32px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"32px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"32px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
|
||||
<StyledLoader>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"16px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"16px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
</StyledTreeFolder>
|
||||
);
|
||||
};
|
||||
|
||||
NewTreeFolderLoader.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
NewTreeFolderLoader.defaultProps = {
|
||||
id: undefined,
|
||||
className: undefined,
|
||||
style: undefined,
|
||||
};
|
||||
|
||||
export default NewTreeFolderLoader;
|
@ -1,159 +0,0 @@
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const StyledHeader = styled.div`
|
||||
width: 100%;
|
||||
padding: ${(props) => (props.isPersonal ? "0px 16px 12px" : "12px 16px")};
|
||||
${(props) =>
|
||||
props.isPersonal &&
|
||||
(props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: -12px;
|
||||
margin-left: 12px;
|
||||
`
|
||||
: css`
|
||||
margin-left: -12px;
|
||||
margin-right: 12px;
|
||||
`)}
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
border-bottom: ${(props) => props.theme.filesPanels.sharing.borderBottom};
|
||||
`;
|
||||
|
||||
StyledHeader.defaultProps = { theme: Base };
|
||||
|
||||
const StyledExternalLink = styled.div`
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
padding: ${(props) => (props.isPersonal ? "20px 4px" : "20px 16px")};
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
border-bottom: ${(props) =>
|
||||
props.isPersonal ? "none" : props.theme.filesPanels.sharing.borderBottom};
|
||||
|
||||
.rectangle-loader {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledExternalLink.defaultProps = { theme: Base };
|
||||
|
||||
const StyledInternalLink = styled.div`
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 20px 16px;
|
||||
|
||||
box-sizing: border-box;
|
||||
`;
|
||||
|
||||
const StyledOwner = styled.div`
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 8px 16px;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
margin-bottom: 16px;
|
||||
|
||||
.owner-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
svg:first-child {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `margin-left: 12px;`
|
||||
: `margin-right: 12px;`}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledBody = styled.div`
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
div:nth-child(3) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledItem = styled.div`
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
padding: 8px 16px;
|
||||
|
||||
.item-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
svg:first-child {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `margin-left: 12px;`
|
||||
: `margin-right: 12px;`}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledButtons = styled.div`
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
padding: 4px;
|
||||
|
||||
svg:first-child {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `margin-left: 8px;`
|
||||
: `margin-right: 8px;`}
|
||||
}
|
||||
`;
|
||||
|
||||
export {
|
||||
StyledContainer,
|
||||
StyledHeader,
|
||||
StyledExternalLink,
|
||||
StyledInternalLink,
|
||||
StyledOwner,
|
||||
StyledBody,
|
||||
StyledItem,
|
||||
StyledButtons,
|
||||
};
|
@ -1,138 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import {
|
||||
StyledContainer,
|
||||
StyledHeader,
|
||||
StyledExternalLink,
|
||||
StyledInternalLink,
|
||||
StyledOwner,
|
||||
StyledBody,
|
||||
StyledItem,
|
||||
} from "./StyledSharingPanel";
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
|
||||
const SharingPanelLoader = ({ id, className, style, ...rest }) => {
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledHeader>
|
||||
<RectangleSkeleton width={"283px"} height={"29px"} />
|
||||
<RectangleSkeleton width={"48px"} height={"29px"} />
|
||||
</StyledHeader>
|
||||
|
||||
<StyledExternalLink>
|
||||
<RectangleSkeleton
|
||||
className="rectangle-loader"
|
||||
width={"146px"}
|
||||
height={"22px"}
|
||||
/>
|
||||
<RectangleSkeleton
|
||||
className="rectangle-loader"
|
||||
width={"448px"}
|
||||
height={"32px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"184px"} height={"20px"} />
|
||||
</StyledExternalLink>
|
||||
|
||||
<StyledInternalLink>
|
||||
<RectangleSkeleton width={"99px"} height={"22px"} />
|
||||
<RectangleSkeleton width={"30px"} height={"22px"} />
|
||||
</StyledInternalLink>
|
||||
|
||||
<StyledOwner>
|
||||
<div className="owner-info">
|
||||
<RectangleSkeleton
|
||||
width={"32px"}
|
||||
height={"32px"}
|
||||
borderRadius={"1000px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"91px"} height={"16px"} />
|
||||
</div>
|
||||
<RectangleSkeleton width={"91px"} height={"16px"} />
|
||||
</StyledOwner>
|
||||
|
||||
<StyledBody>
|
||||
<StyledItem>
|
||||
<div className="item-info">
|
||||
<RectangleSkeleton
|
||||
width={"32px"}
|
||||
height={"32px"}
|
||||
borderRadius={"1000px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"91px"} height={"16px"} />
|
||||
</div>
|
||||
<RectangleSkeleton width={"45px"} height={"32px"} />
|
||||
</StyledItem>
|
||||
<StyledItem>
|
||||
<div className="item-info">
|
||||
<RectangleSkeleton
|
||||
width={"32px"}
|
||||
height={"32px"}
|
||||
borderRadius={"1000px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"91px"} height={"16px"} />
|
||||
</div>
|
||||
<RectangleSkeleton width={"45px"} height={"32px"} />
|
||||
</StyledItem>
|
||||
<StyledItem>
|
||||
<div className="item-info">
|
||||
<RectangleSkeleton
|
||||
width={"32px"}
|
||||
height={"32px"}
|
||||
borderRadius={"1000px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"91px"} height={"16px"} />
|
||||
</div>
|
||||
<RectangleSkeleton width={"45px"} height={"32px"} />
|
||||
</StyledItem>
|
||||
<StyledItem>
|
||||
<div className="item-info">
|
||||
<RectangleSkeleton
|
||||
width={"32px"}
|
||||
height={"32px"}
|
||||
borderRadius={"1000px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"91px"} height={"16px"} />
|
||||
</div>
|
||||
<RectangleSkeleton width={"45px"} height={"32px"} />
|
||||
</StyledItem>
|
||||
<StyledItem>
|
||||
<div className="item-info">
|
||||
<RectangleSkeleton
|
||||
width={"32px"}
|
||||
height={"32px"}
|
||||
borderRadius={"1000px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"91px"} height={"16px"} />
|
||||
</div>
|
||||
<RectangleSkeleton width={"45px"} height={"32px"} />
|
||||
</StyledItem>
|
||||
<StyledItem>
|
||||
<div className="item-info">
|
||||
<RectangleSkeleton
|
||||
width={"32px"}
|
||||
height={"32px"}
|
||||
borderRadius={"1000px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"91px"} height={"16px"} />
|
||||
</div>
|
||||
<RectangleSkeleton width={"45px"} height={"32px"} />
|
||||
</StyledItem>
|
||||
</StyledBody>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
SharingPanelLoader.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
SharingPanelLoader.defaultProps = {
|
||||
id: undefined,
|
||||
className: undefined,
|
||||
style: undefined,
|
||||
};
|
||||
|
||||
export default SharingPanelLoader;
|
@ -1,66 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import {
|
||||
StyledContainer,
|
||||
StyledHeader,
|
||||
StyledExternalLink,
|
||||
StyledInternalLink,
|
||||
StyledOwner,
|
||||
StyledBody,
|
||||
StyledItem,
|
||||
StyledButtons,
|
||||
} from "./StyledSharingPanel";
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
|
||||
const SharingPanelLoaderModal = ({
|
||||
id,
|
||||
className,
|
||||
style,
|
||||
isShared,
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledHeader isPersonal={true}>
|
||||
<RectangleSkeleton width={"283px"} height={"16px"} />
|
||||
</StyledHeader>
|
||||
|
||||
<StyledExternalLink isPersonal={true}>
|
||||
<RectangleSkeleton
|
||||
className="rectangle-loader"
|
||||
width={"146px"}
|
||||
height={"22px"}
|
||||
/>
|
||||
{isShared && (
|
||||
<>
|
||||
<RectangleSkeleton
|
||||
className="rectangle-loader"
|
||||
width={"368px"}
|
||||
height={"32px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"184px"} height={"20px"} />
|
||||
</>
|
||||
)}
|
||||
</StyledExternalLink>
|
||||
<StyledButtons>
|
||||
<RectangleSkeleton width={"100%"} height={"40px"} />
|
||||
<RectangleSkeleton width={"100%"} height={"40px"} />
|
||||
</StyledButtons>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
SharingPanelLoaderModal.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
SharingPanelLoaderModal.defaultProps = {
|
||||
id: undefined,
|
||||
className: undefined,
|
||||
style: undefined,
|
||||
};
|
||||
|
||||
export default SharingPanelLoaderModal;
|
@ -1,21 +0,0 @@
|
||||
import React from "react";
|
||||
import ContentLoader from "react-content-loader";
|
||||
import { LOADER_STYLE } from "@docspace/shared/constants";
|
||||
|
||||
const TextLoader = (props) => (
|
||||
<ContentLoader
|
||||
speed={2}
|
||||
width={174}
|
||||
height={23}
|
||||
viewBox="0 0 174 23"
|
||||
backgroundColor={LOADER_STYLE.backgroundColor}
|
||||
foregroundColor={LOADER_STYLE.foregroundColor}
|
||||
backgroundOpacity={LOADER_STYLE.backgroundOpacity}
|
||||
foregroundOpacity={LOADER_STYLE.foregroundOpacity}
|
||||
{...props}
|
||||
>
|
||||
<rect x="0" y="0" rx="0" ry="0" width="174" height="23" />
|
||||
</ContentLoader>
|
||||
);
|
||||
|
||||
export default TextLoader;
|
@ -1,26 +0,0 @@
|
||||
# Tree Folder Loader
|
||||
|
||||
Component that displays tree folder loader
|
||||
|
||||
### Usage
|
||||
|
||||
```js
|
||||
import Loaders from "@docspace/common/components/Loaders";
|
||||
```
|
||||
|
||||
```jsx
|
||||
<Loaders.TreeFolders />
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Props | Type | Required | Values | Default | Description |
|
||||
| ------------------- | :------: | :------: | :----: | :-------: | ------------------------------------------------ |
|
||||
| `title` | `string` | - | - | `` | It's used to describe what element it is. |
|
||||
| `borderRadius` | `string` | - | - | `3` | Sets the corners rounding |
|
||||
| `backgroundColor` | `string` | - | - | `#000000` | Used as background of animation |
|
||||
| `foregroundColor` | `string` | - | - | `#000000` | Used as the foreground of animation |
|
||||
| `backgroundOpacity` | `number` | - | - | 0.2 | Background opacity (0 = transparent, 1 = opaque) |
|
||||
| `foregroundOpacity` | `number` | - | - | 0.15 | Animation opacity (0 = transparent, 1 = opaque) |
|
||||
| `speed` | `number` | - | - | 2 | Animation speed in seconds |
|
||||
| `animate` | `bool` | - | - | true | Opt-out of animations |
|
@ -1,27 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
import { desktop } from "@docspace/shared/utils";
|
||||
|
||||
const StyledTreeFolder = styled.div`
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 8px 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 6px;
|
||||
margin-bottom: 24px;
|
||||
`;
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
margin-top: 48px;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledBox = styled.div`
|
||||
@media ${desktop} {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `margin-left: 8px;`
|
||||
: `margin-right: 8px;`}
|
||||
}
|
||||
`;
|
||||
|
||||
export { StyledTreeFolder, StyledContainer, StyledBox };
|
@ -1,71 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import {
|
||||
StyledTreeFolder,
|
||||
StyledContainer,
|
||||
StyledBox,
|
||||
} from "./StyledTreeFolderLoader";
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
import TreeNodeLoader from "../TreeNodeLoader";
|
||||
|
||||
const TreeFolderLoader = ({ id, className, style, ...rest }) => {
|
||||
const {
|
||||
title,
|
||||
borderRadius,
|
||||
backgroundColor,
|
||||
foregroundColor,
|
||||
backgroundOpacity,
|
||||
foregroundOpacity,
|
||||
speed,
|
||||
animate,
|
||||
} = rest;
|
||||
|
||||
return (
|
||||
<StyledBox id={id} className={className} style={style}>
|
||||
<StyledTreeFolder>
|
||||
<TreeNodeLoader {...rest} />
|
||||
<TreeNodeLoader {...rest} />
|
||||
<TreeNodeLoader {...rest} />
|
||||
</StyledTreeFolder>
|
||||
|
||||
<StyledTreeFolder>
|
||||
<TreeNodeLoader {...rest} />
|
||||
<TreeNodeLoader {...rest} />
|
||||
<TreeNodeLoader {...rest} />
|
||||
</StyledTreeFolder>
|
||||
|
||||
<StyledTreeFolder>
|
||||
<TreeNodeLoader {...rest} />
|
||||
</StyledTreeFolder>
|
||||
|
||||
<StyledContainer>
|
||||
<RectangleSkeleton
|
||||
title={title}
|
||||
width="100%"
|
||||
height="48"
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
</StyledContainer>
|
||||
</StyledBox>
|
||||
);
|
||||
};
|
||||
|
||||
TreeFolderLoader.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
TreeFolderLoader.defaultProps = {
|
||||
id: undefined,
|
||||
className: undefined,
|
||||
style: undefined,
|
||||
};
|
||||
|
||||
export default TreeFolderLoader;
|
@ -1,40 +0,0 @@
|
||||
import React from "react";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import {
|
||||
withKnobs,
|
||||
text,
|
||||
boolean,
|
||||
color,
|
||||
number,
|
||||
} from "@storybook/addon-knobs/react";
|
||||
import Section from "../../../../.storybook/decorators/section";
|
||||
|
||||
import Loaders from "..";
|
||||
import { LOADER_STYLE } from "@docspace/shared/constants";
|
||||
import withReadme from "storybook-readme/with-readme";
|
||||
import Readme from "./README.md";
|
||||
|
||||
storiesOf("Components|Loaders", module)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add("tree folder loader", () => (
|
||||
<Section>
|
||||
<h1>Tree Folder Loader</h1>
|
||||
<Loaders.TreeFolders
|
||||
title={text("title", LOADER_STYLE.title)}
|
||||
borderRadius={text("borderRadius", "3")}
|
||||
backgroundColor={color("backgroundColor", LOADER_STYLE.backgroundColor)}
|
||||
foregroundColor={color("foregroundColor", LOADER_STYLE.foregroundColor)}
|
||||
backgroundOpacity={number(
|
||||
"backgroundOpacity",
|
||||
LOADER_STYLE.backgroundOpacity
|
||||
)}
|
||||
foregroundOpacity={number(
|
||||
"foregroundOpacity",
|
||||
LOADER_STYLE.foregroundOpacity
|
||||
)}
|
||||
speed={number("speed", LOADER_STYLE.speed)}
|
||||
animate={boolean("animate", LOADER_STYLE.animate)}
|
||||
/>
|
||||
</Section>
|
||||
));
|
@ -1 +0,0 @@
|
||||
export default from "./TreeFolderLoader";
|
@ -1,62 +0,0 @@
|
||||
import React from "react";
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
import { CircleSkeleton } from "@docspace/shared/skeletons";
|
||||
|
||||
const TreeNodeLoader = ({
|
||||
title,
|
||||
borderRadius,
|
||||
backgroundColor,
|
||||
foregroundColor,
|
||||
backgroundOpacity,
|
||||
foregroundOpacity,
|
||||
speed,
|
||||
animate,
|
||||
withRectangle = false,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<CircleSkeleton
|
||||
title={title}
|
||||
height="32"
|
||||
radius="3"
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
|
||||
{withRectangle && (
|
||||
<RectangleSkeleton
|
||||
title={title}
|
||||
width="16"
|
||||
height="16"
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
className="tree-node-loader_additional-rectangle"
|
||||
/>
|
||||
)}
|
||||
|
||||
<RectangleSkeleton
|
||||
title={title}
|
||||
width="100%"
|
||||
height="24"
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TreeNodeLoader;
|
@ -1 +0,0 @@
|
||||
export default from "./TreeNodeLoader";
|
@ -1,12 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledTreeSettingsLoader = styled.div`
|
||||
width: 90%;
|
||||
display: grid;
|
||||
grid-template-columns: 8px 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 6px;
|
||||
margin: 24px 0;
|
||||
`;
|
||||
|
||||
export default StyledTreeSettingsLoader;
|
@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import StyledTreeSettingsLoader from "./StyledTreeSettingsLoader";
|
||||
import TreeNodeLoader from "../TreeNodeLoader";
|
||||
|
||||
const TreeSettingsLoader = ({ id, className, style, ...rest }) => {
|
||||
return (
|
||||
<div id={id} className={className} style={style}>
|
||||
<StyledTreeSettingsLoader>
|
||||
<TreeNodeLoader {...rest} />
|
||||
</StyledTreeSettingsLoader>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
TreeSettingsLoader.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
TreeSettingsLoader.defaultProps = {
|
||||
id: undefined,
|
||||
className: undefined,
|
||||
style: undefined,
|
||||
};
|
||||
|
||||
export default TreeSettingsLoader;
|
@ -1 +0,0 @@
|
||||
export default from "./TreeSettingsLoader";
|
@ -1,31 +0,0 @@
|
||||
import TreeFolders from "./TreeFolderLoader";
|
||||
import NewTreeFolders from "./NewTreeFolderLoader";
|
||||
import TreeSettingsLoader from "./TreeSettingsLoader";
|
||||
|
||||
import Text from "./TextLoader";
|
||||
|
||||
import Group from "./GroupLoader";
|
||||
|
||||
import DialogLoader from "./DialogLoader";
|
||||
import DialogAsideLoader from "./DialogAsideLoader";
|
||||
import SharingPanelLoader from "./SharingPanelLoader";
|
||||
import SharingPanelLoaderModal from "./SharingPanelLoader/modal";
|
||||
|
||||
import EmptyContainerLoader from "./EmptyContainerLoader/EmptyContainerLoader";
|
||||
|
||||
export default {
|
||||
TreeFolders,
|
||||
TreeSettingsLoader,
|
||||
|
||||
Text,
|
||||
|
||||
Group,
|
||||
|
||||
DialogLoader,
|
||||
DialogAsideLoader,
|
||||
NewTreeFolders,
|
||||
SharingPanelLoader,
|
||||
SharingPanelLoaderModal,
|
||||
|
||||
EmptyContainerLoader,
|
||||
};
|
@ -1,6 +0,0 @@
|
||||
export { default as PublicRoute } from "./PublicRoute";
|
||||
export { default as ExternalRedirect } from "./ExternalRedirect";
|
||||
export { default as AdvancedSelector } from "./AdvancedSelector";
|
||||
export { default as Section } from "./Section";
|
||||
export { default as FilterInput } from "./FilterInput";
|
||||
export { default as SystemThemeDetector } from "./SystemThemeDetector";
|
20
packages/common/index.d.ts
vendored
20
packages/common/index.d.ts
vendored
@ -1,20 +0,0 @@
|
||||
type TFuncType = (key: string) => string;
|
||||
|
||||
type HTMLElementEvent<T extends HTMLElement> = Event & {
|
||||
target: T;
|
||||
};
|
||||
|
||||
interface IProvider {
|
||||
linked: boolean;
|
||||
provider: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
type ProvidersType = IProvider[];
|
||||
|
||||
interface Window {
|
||||
zESettings?: any;
|
||||
zE?: {
|
||||
apply: Function;
|
||||
};
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
export { default as api } from "./api";
|
||||
export { default as store } from "./store";
|
||||
export { default as history } from "./history";
|
||||
export * from "./components";
|
||||
export * as constants from "./constants";
|
||||
export * as utils from "./utils";
|
||||
export * from "./desktop";
|
@ -1,50 +0,0 @@
|
||||
{
|
||||
"name": "@docspace/common",
|
||||
"version": "2.0.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "echo 'skip it'",
|
||||
"clean": "echo 'skip it'",
|
||||
"deploy": "echo 'skip it'",
|
||||
"start": "echo 'skip it'",
|
||||
"start-prod": "echo 'skip it'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@loadable/component": "^5.15.3",
|
||||
"axios": "^0.22.0",
|
||||
"cross-fetch": "3.1.5",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"global": "^4.4.0",
|
||||
"i18next": "^20.6.1",
|
||||
"mobx": "^6.8.0",
|
||||
"mobx-react": "^7.6.0",
|
||||
"moment": "^2.29.4",
|
||||
"moment-timezone": "^0.5.43",
|
||||
"prop-types": "^15.8.1",
|
||||
"query-string": "7.1.3",
|
||||
"re-resizable": "^6.9.9",
|
||||
"react": "^18.2.0",
|
||||
"react-autosize-textarea": "^7.1.0",
|
||||
"react-content-loader": "^5.1.4",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hammerjs": "^1.0.1",
|
||||
"react-i18next": "^13.2.1",
|
||||
"react-player": "^1.15.3",
|
||||
"react-router": "^6.10.0",
|
||||
"react-router-dom": "^6.10.0",
|
||||
"react-tooltip": "^5.23.0",
|
||||
"react-viewer": "^3.2.2",
|
||||
"react-virtualized-auto-sizer": "^1.0.7",
|
||||
"react-window": "^1.8.8",
|
||||
"react-window-infinite-loader": "^1.0.8",
|
||||
"screenfull": "^5.2.0",
|
||||
"sjcl": "^1.0.8",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"styled-components": "^5.3.9",
|
||||
"workbox-window": "^6.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@welldone-software/why-did-you-render": "^6.2.3"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user