mui menu, select input inprogress

This commit is contained in:
Sebastian 2022-06-24 11:42:21 -03:00
parent b06ae62de0
commit 50379a1d5b
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
6 changed files with 376 additions and 12 deletions

View File

@ -16,11 +16,11 @@
import { ComponentChildren, h, VNode, JSX } from "preact"; import { ComponentChildren, h, VNode, JSX } from "preact";
import { css } from "@linaria/core"; import { css } from "@linaria/core";
// eslint-disable-next-line import/extensions // eslint-disable-next-line import/extensions
import { theme, ripple, Colors, rippleOutlined } from "./style"; import { theme, Colors, rippleEnabled, rippleEnabledOutlined } from "./style";
// eslint-disable-next-line import/extensions // eslint-disable-next-line import/extensions
import { alpha } from "./colors/manipulation"; import { alpha } from "./colors/manipulation";
const buttonBaseStyle = css` export const buttonBaseStyle = css`
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -318,6 +318,7 @@ interface BaseProps extends JSX.HTMLAttributes<HTMLButtonElement> {
onClick?: () => Promise<void>; onClick?: () => Promise<void>;
containedRipple?: boolean; containedRipple?: boolean;
children?: ComponentChildren; children?: ComponentChildren;
svg?: any;
} }
function ButtonBase({ function ButtonBase({
@ -325,7 +326,7 @@ function ButtonBase({
children, children,
containedRipple, containedRipple,
onClick, onClick,
dangerouslySetInnerHTML, svg,
...rest ...rest
}: BaseProps): VNode { }: BaseProps): VNode {
function doClick(): void { function doClick(): void {
@ -334,14 +335,14 @@ function ButtonBase({
const classNames = [ const classNames = [
buttonBaseStyle, buttonBaseStyle,
_class, _class,
containedRipple ? ripple : rippleOutlined, containedRipple ? rippleEnabled : rippleEnabledOutlined,
].join(" "); ].join(" ");
if (dangerouslySetInnerHTML) { if (svg) {
return ( return (
<button <button
onClick={doClick} onClick={doClick}
class={classNames} class={classNames}
dangerouslySetInnerHTML={dangerouslySetInnerHTML} dangerouslySetInnerHTML={{ __html: svg }}
{...rest} {...rest}
/> />
); );
@ -375,7 +376,7 @@ export function IconButton({
fill: currentColor; fill: currentColor;
`, `,
].join(" ")} ].join(" ")}
dangerouslySetInnerHTML={{ __html: svg }} svg={svg}
/> />
); );
} }

View File

@ -0,0 +1,172 @@
/*
This file is part of GNU Taler
(C) 2022 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
*
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { Menu, MenuItem } from "./Menu.jsx";
import { Paper } from "./Paper.js";
export default {
title: "mui/menu",
component: Menu,
};
export const BasicExample = (): VNode => {
const [open, setOpen] = useState(false);
async function handleClose(): Promise<void> {
setOpen(false);
}
async function handleClick(): Promise<void> {
setOpen(true);
}
return (
<Menu open={open} onClose={handleClose} onClick={handleClick}>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
);
};
import { styled } from "@linaria/react";
// eslint-disable-next-line import/extensions
import { theme } from "./style";
import { Typography } from "./Typography.js";
import { Divider } from "./Divider.js";
const ListItemIcon = styled.div`
min-width: 36px;
color: ${theme.palette.action.active};
flex-shrink: 0;
display: inline-flex;
`;
const IconCut = (): VNode => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
aria-hidden="true"
focusable="false"
style={{
width: "1em",
height: "1em",
}}
>
<path d="M9.64 7.64c.23-.5.36-1.05.36-1.64 0-2.21-1.79-4-4-4S2 3.79 2 6s1.79 4 4 4c.59 0 1.14-.13 1.64-.36L10 12l-2.36 2.36C7.14 14.13 6.59 14 6 14c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4c0-.59-.13-1.14-.36-1.64L12 14l7 7h3v-1L9.64 7.64zM6 8c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm0 12c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm6-7.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5.22.5.5-.22.5-.5.5zM19 3l-6 6 2 2 7-7V3z" />
</svg>
);
const IconCopy = (): VNode => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
aria-hidden="true"
focusable="false"
style={{
width: "1em",
height: "1em",
}}
>
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
);
const IconPaste = (): VNode => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
aria-hidden="true"
focusable="false"
style={{
width: "1em",
height: "1em",
}}
>
<path d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z" />
</svg>
);
const IconCloud = (): VNode => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
aria-hidden="true"
focusable="false"
style={{
width: "1em",
height: "1em",
}}
>
<path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z" />
</svg>
);
const ListItemText = styled.div`
flex: 1 1 auto;
min-width: 0px;
margin-top: 4px;
margin-bottom: 4px;
`;
export function IconMenu(): VNode {
return (
<div style={{ width: 320 }}>
<Paper>
<ul>
<MenuItem>
<ListItemIcon>
<IconCut />
</ListItemIcon>
<ListItemText>Cut</ListItemText>
<Typography variant="body2" /* color="text.secondary" */>
X
</Typography>
</MenuItem>
<MenuItem>
<ListItemIcon>
<IconCopy />
</ListItemIcon>
<ListItemText>Copy</ListItemText>
<Typography variant="body2" /* color="text.secondary" */>
C
</Typography>
</MenuItem>
<MenuItem>
<ListItemIcon>
<IconPaste />
</ListItemIcon>
<ListItemText>Paste</ListItemText>
<Typography variant="body2" /* color="text.secondary" */>
V
</Typography>
</MenuItem>
<Divider />
<MenuItem>
<ListItemIcon>
<IconCloud />
</ListItemIcon>
<ListItemText>Web Clipboard</ListItemText>
</MenuItem>
</ul>
</Paper>
</div>
);
}

View File

@ -0,0 +1,135 @@
/*
This file is part of GNU Taler
(C) 2022 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { css } from "@linaria/core";
import { h, VNode, Fragment, ComponentChildren } from "preact";
import { buttonBaseStyle } from "./Button.js";
import { alpha } from "./colors/manipulation.js";
import { Paper } from "./Paper.js";
// eslint-disable-next-line import/extensions
import { Colors, ripple, theme } from "./style";
interface Props {
children: ComponentChildren;
onClose: () => Promise<void>;
onClick: () => Promise<void>;
open?: boolean;
}
const menuPaper = css`
max-height: calc(100% - 96px);
-webkit-overflow-scrolling: touch;
`;
const menuList = css`
outline: 0px;
`;
export function Menu({ children, onClose, onClick, open }: Props): VNode {
return (
<Popover class={menuPaper}>
<ul class={menuList}>{children}</ul>
</Popover>
);
}
const popoverRoot = css``;
const popoverPaper = css`
position: absolute;
overflow-y: auto;
overflow-x: hidden;
min-width: 16px;
min-height: 16px;
max-width: calc(100% - 32px);
max-height: calc(100% - 32px);
outline: 0;
`;
function Popover({ children }: any): VNode {
return (
<div class={popoverRoot}>
<Paper class={popoverPaper}>{children}</Paper>
</div>
);
}
const root = css`
display: flex;
justify-content: flex-start;
align-items: center;
position: relative;
text-decoration: none;
min-height: 48px;
padding-top: 6px;
padding-bottom: 6px;
box-sizing: border-box;
white-space: nowrap;
appearance: none;
&:not([data-disableGutters]) {
padding-left: 16px;
padding-right: 16px;
}
[data-dividers] {
border-bottom: 1px solid ${theme.palette.divider};
background-clip: padding-box;
}
&:hover {
text-decoration: none;
background-color: var(--color-main-alpha-half);
@media (hover: none) {
background-color: transparent;
}
}
`;
export function MenuItem({
children,
onClick,
color = "primary",
}: {
children: ComponentChildren;
onClick?: () => Promise<void>;
color?: Colors;
}): VNode {
function doClick(): void {
// if (onClick) onClick();
return;
}
return (
<li
onClick={doClick}
disabled={false}
role="menuitem"
class={[buttonBaseStyle, root, ripple].join(" ")}
style={{
"--color-main": theme.palette[color].main,
"--color-dark": theme.palette[color].dark,
"--color-grey-or-dark": !color
? theme.palette.grey.A100
: theme.palette[color].dark,
"--color-main-alpha-half": alpha(theme.palette[color].main, 0.7),
"--color-main-alpha-opacity": alpha(
theme.palette[color].main,
theme.palette.action.hoverOpacity,
),
}}
>
{children}
</li>
);
}

View File

@ -24,5 +24,6 @@ import * as a3 from "./Grid.stories.js";
import * as a4 from "./Paper.stories.js"; import * as a4 from "./Paper.stories.js";
import * as a5 from "./TextField.stories.js"; import * as a5 from "./TextField.stories.js";
import * as a6 from "./Alert.stories.js"; import * as a6 from "./Alert.stories.js";
import * as a7 from "./Menu.stories.js";
export default [a1, a3, a4, a5, a6]; export default [a1, a3, a4, a5, a6, a7];

View File

@ -13,8 +13,46 @@
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
import { h, VNode } from "preact"; import { css } from "@linaria/core";
import { h, VNode, Fragment } from "preact";
export function SelectStandard(): VNode { const SelectSelect = css`
return <div />; height: "auto";
min-height: "1.4374em";
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
`;
const SelectIcon = css``;
const SelectNativeInput = css`
bottom: 0px;
left: 0px;
position: "absolute";
opacity: 0px;
pointer-events: "none";
width: 100%;
box-sizing: border-box;
`;
export function SelectStandard({ value }: any): VNode {
return (
<Fragment>
<div class={SelectSelect} role="button">
{!value ? (
// notranslate needed while Google Translate will not fix zero-width space issue
<span className="notranslate">&#8203;</span>
) : (
value
)}
<input
class={SelectNativeInput}
aria-hidden
tabIndex={-1}
value={Array.isArray(value) ? value.join(",") : value}
/>
</div>
</Fragment>
);
} }

View File

@ -63,6 +63,23 @@ export const ripple = css`
transition: background 0.2s; transition: background 0.2s;
&:hover {
background: var(--color-main)
radial-gradient(circle, transparent 1%, var(--color-dark) 1%)
center/15000%;
}
&:active {
background-color: var(--color-main);
background-size: 100%;
transition: background 0s;
}
`;
export const rippleEnabled = css`
background-position: center;
transition: background 0.2s;
&:hover:enabled { &:hover:enabled {
background: var(--color-main) background: var(--color-main)
radial-gradient(circle, transparent 1%, var(--color-dark) 1%) radial-gradient(circle, transparent 1%, var(--color-dark) 1%)
@ -75,7 +92,7 @@ export const ripple = css`
} }
`; `;
export const rippleOutlined = css` export const rippleEnabledOutlined = css`
background-position: center; background-position: center;
transition: background 0.2s; transition: background 0.2s;