mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-12 10:10:29 +03:00
initial commit
This commit is contained in:
commit
026f835a87
176 changed files with 10613 additions and 0 deletions
103
src/app/atoms/context-menu/ContextMenu.jsx
Normal file
103
src/app/atoms/context-menu/ContextMenu.jsx
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import './ContextMenu.scss';
|
||||
|
||||
import Tippy from '@tippyjs/react';
|
||||
import 'tippy.js/animations/scale-extreme.css';
|
||||
|
||||
import Text from '../text/Text';
|
||||
import Button from '../button/Button';
|
||||
import ScrollView from '../scroll/ScrollView';
|
||||
|
||||
function ContextMenu({
|
||||
content, placement, maxWidth, render,
|
||||
}) {
|
||||
const [isVisible, setVisibility] = useState(false);
|
||||
const showMenu = () => setVisibility(true);
|
||||
const hideMenu = () => setVisibility(false);
|
||||
|
||||
return (
|
||||
<Tippy
|
||||
animation="scale-extreme"
|
||||
className="context-menu"
|
||||
visible={isVisible}
|
||||
onClickOutside={hideMenu}
|
||||
content={<ScrollView invisible>{typeof content === 'function' ? content(hideMenu) : content}</ScrollView>}
|
||||
placement={placement}
|
||||
interactive
|
||||
arrow={false}
|
||||
maxWidth={maxWidth}
|
||||
>
|
||||
{render(isVisible ? hideMenu : showMenu)}
|
||||
</Tippy>
|
||||
);
|
||||
}
|
||||
|
||||
ContextMenu.defaultProps = {
|
||||
maxWidth: 'unset',
|
||||
placement: 'right',
|
||||
};
|
||||
|
||||
ContextMenu.propTypes = {
|
||||
content: PropTypes.oneOfType([
|
||||
PropTypes.node,
|
||||
PropTypes.func,
|
||||
]).isRequired,
|
||||
placement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
|
||||
maxWidth: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]),
|
||||
render: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
function MenuHeader({ children }) {
|
||||
return (
|
||||
<div className="context-menu__header">
|
||||
<Text variant="b3">{ children }</Text>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
MenuHeader.propTypes = {
|
||||
children: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
function MenuItem({
|
||||
variant, iconSrc, type, onClick, children,
|
||||
}) {
|
||||
return (
|
||||
<div className="context-menu__item">
|
||||
<Button
|
||||
variant={variant}
|
||||
iconSrc={iconSrc}
|
||||
type={type}
|
||||
onClick={onClick}
|
||||
>
|
||||
{ children }
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
MenuItem.defaultProps = {
|
||||
variant: 'surface',
|
||||
iconSrc: 'none',
|
||||
type: 'button',
|
||||
};
|
||||
|
||||
MenuItem.propTypes = {
|
||||
variant: PropTypes.oneOf(['surface', 'caution', 'danger']),
|
||||
iconSrc: PropTypes.string,
|
||||
type: PropTypes.oneOf(['button', 'submit']),
|
||||
onClick: PropTypes.func.isRequired,
|
||||
children: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
function MenuBorder() {
|
||||
return <div style={{ borderBottom: '1px solid var(--bg-surface-border)' }}> </div>;
|
||||
}
|
||||
|
||||
export {
|
||||
ContextMenu as default, MenuHeader, MenuItem, MenuBorder,
|
||||
};
|
||||
71
src/app/atoms/context-menu/ContextMenu.scss
Normal file
71
src/app/atoms/context-menu/ContextMenu.scss
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
.context-menu {
|
||||
background-color: var(--bg-surface);
|
||||
box-shadow: var(--bs-popup);
|
||||
border-radius: var(--bo-radius);
|
||||
overflow: hidden;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
& .tippy-content > div > .scrollbar {
|
||||
max-height: 90vh;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu__click-wrapper {
|
||||
display: inline-flex;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu__header {
|
||||
height: 34px;
|
||||
padding: 0 var(--sp-tight);
|
||||
margin-bottom: var(--sp-ultra-tight);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--bg-surface-border);
|
||||
|
||||
.text {
|
||||
color: var(--tc-surface-low);
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: var(--sp-normal);
|
||||
border-top: 1px solid var(--bg-surface-border);
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu__item {
|
||||
button[class^="btn"] {
|
||||
width: 100%;
|
||||
justify-content: start;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
|
||||
.text:first-child {
|
||||
margin: {
|
||||
left: calc(var(--ic-small) + var(--sp-ultra-tight));
|
||||
right: var(--sp-extra-tight);
|
||||
}
|
||||
|
||||
[dir=rtl] & {
|
||||
margin: {
|
||||
left: var(--sp-extra-tight);
|
||||
right: calc(var(--ic-small) + var(--sp-ultra-tight));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn-surface:focus {
|
||||
background-color: var(--bg-surface-hover);
|
||||
}
|
||||
.btn-caution:focus {
|
||||
background-color: var(--bg-caution-hover);
|
||||
}
|
||||
.btn-danger:focus {
|
||||
background-color: var(--bg-danger-hover);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue