Skip to content

Commit

Permalink
[FRNT- 450] Rewrite menulist (#85)
Browse files Browse the repository at this point in the history
* fix: rewrite menulist

* fix: add new styles

* fix: add examples, fix styles

* fix: fix list styles

* fix styles

* rewrite list styles
  • Loading branch information
Irinaristova committed Apr 30, 2021
1 parent 2b74b94 commit 81b6fce
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 92 deletions.
1 change: 1 addition & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { positionRelativeGet } from './position-relative';
export { keyboardEventHandle } from './keyboard-event';
export { keyHandlerGet } from './select-handlers';
export { keyHandlerList } from './listHandlers';
export { Variant } from './types';
33 changes: 33 additions & 0 deletions src/lib/listHandlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const LI_TAG = 'LI';

export const onKeyDown = (listNode: HTMLElement) => () => {
if (document.activeElement?.tagName === LI_TAG) {
(document.activeElement?.nextElementSibling as HTMLElement)?.focus();
} else {
(listNode?.firstChild as HTMLElement)?.focus();
}
};

export const onKeyUp = (listNode: HTMLElement) => () => {
if (document.activeElement?.tagName === LI_TAG) {
(document?.activeElement?.previousElementSibling as HTMLElement)?.focus();
} else {
(listNode.lastChild as HTMLElement)?.focus();
}
};

const onItemEnter = (listNode: HTMLElement) => () => {
if (document.activeElement?.tagName === LI_TAG) {
(document?.activeElement as HTMLElement).click();
} else {
(listNode?.lastChild as HTMLElement).focus();
}
};

export const keyHandlerList = ({
listNode,
}: any) => ({
arrowDown: onKeyDown(listNode),
arrowUp: onKeyUp(listNode),
enter: onItemEnter(listNode),
});
6 changes: 3 additions & 3 deletions src/lib/select-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ const LI_TAG = 'LI';

const onArrowDown = (dropdownNode: HTMLElement) => () => {
if (document.activeElement?.tagName === LI_TAG) {
(document.activeElement.nextElementSibling as HTMLElement).focus();
(document.activeElement?.nextElementSibling as HTMLElement).focus();
} else {
(dropdownNode.firstChild as HTMLElement).focus();
(dropdownNode?.firstChild as HTMLElement).focus();
}
};

const onArrowUp = (dropdownNode: HTMLElement) => () => {
if (document.activeElement?.tagName === LI_TAG) {
(document.activeElement.previousElementSibling as HTMLElement).focus();
(document?.activeElement?.previousElementSibling as HTMLElement).focus();
} else {
(dropdownNode.lastChild as HTMLElement).focus();
}
Expand Down
6 changes: 3 additions & 3 deletions src/ui/atoms/button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ export const Button = styled(ButtonBase)`
&[data-outlined='true'] {
background-color: transparent;
color: var(--local-shape-color);
svg > path {
fill: var(--local-shape-color);
}
svg > path {
fill: var(--local-shape-color);
}
}
[data-icon] {
Expand Down
206 changes: 143 additions & 63 deletions src/ui/atoms/list/index.tsx
Original file line number Diff line number Diff line change
@@ -1,116 +1,196 @@
import * as React from 'react';
import styled, { StyledComponent } from 'styled-components';
import { Variant } from 'lib/types';

/**
* --woly-list-padding
* --woly-list-color
* --woly-list-background
* --woly-rounding
* --woly-shadow
* --woly-canvas
* --woly-background-hover
* --woly-color
* --woly-color-hover
* --woly-line-height
*/

import { keyHandlerList, keyboardEventHandle } from 'lib';
interface List {
className?: string;
disabled?: boolean;
list: Array<{
left?: React.ReactNode;
right?: React.ReactNode;
text: React.ReactNode;
id: string;
disabled?: boolean;
onClick?: React.MouseEventHandler<HTMLLIElement>;
onClick?: React.EventHandler<React.SyntheticEvent>;
}>;
}

const ListBase: React.FC<List & Variant> = ({ className, list, variant = 'default' }) => (
<ul className={className} data-variant={variant}>
{list.map(({ left, right, text, id, disabled, onClick }) => (
<li key={id} data-type="list-item" data-disabled={disabled} onClick={onClick}>
{left && <span data-icon="left">{left}</span>}
<span data-block="content">{text}</span>
{right && <span data-icon="right">{right}</span>}
</li>
))}
</ul>
);
const ListBase: React.FC<List & Variant> = ({
className,
list,
variant = 'default',
disabled = false,
}) => {
const tabIndex = disabled ? -1 : 0;
const itemListRef = React.useRef(null);

const onKeyDown = React.useCallback(
(event: React.KeyboardEvent) => {
const listNode = itemListRef.current;

if (!document || !listNode || event.key === 'Tab') {
return;
}

event.preventDefault();

const handlerList = keyHandlerList({
listNode,
});

keyboardEventHandle({
event,
keyHandler: handlerList,
});
},
[itemListRef],
);
return (
<ul
className={className}
data-disabled={disabled}
data-variant={variant}
onKeyDown={onKeyDown}
ref={itemListRef}
role="listbox"
tabIndex={tabIndex}
>
{list.map(({ left, right, text, id, onClick, disabled }) => (
<li
data-disabled={disabled}
data-type="list-item"
key={id}
onClick={onClick}
tabIndex={-1}
>
{left && <span data-icon="left">{left}</span>}
<span data-text="text">{text}</span>
{right && <span data-icon="right">{right}</span>}
</li>
))}
</ul>
);
}


export const List = styled(ListBase)`
--woly-vertical: calc(1px * var(--woly-component-level) * var(--woly-main-level));
--woly-horizontal: calc(
var(--woly-const-m) + (1px * var(--woly-main-level)) + var(--woly-vertical)
--local-vertical: calc(1px * var(--woly-component-level) * var(--woly-main-level));
--local-horizontal: calc(
var(--woly-const-m) + (1px * var(--woly-main-level)) + var(--local-vertical)
);
--woly-width: 100%;
--local-gap: var(--local-vertical);
--local-compensate: var(--woly-const-m);
--local-margin: var(--woly-border-width);
--local-color: var(--woly-canvas-text-default);
--local-background: var(--woly-shape-text-default);
--local-item-background: var(--woly-canvas-default);
--local-border: var(--woly-canvas-default);
box-sizing: border-box;
width: var(--woly-width);
width: 100%;
outline: none;
padding: 0;
margin: 0;
color: var(--woly-color, #000000);
border: var(--woly-border-width) solid var(--local-border);
list-style-type: none;
background-color: var(--woly-canvas, #ffffff);
border-radius: var(--woly-rounding, 3px);
box-shadow: var(--woly-shadow, 3px 3px 8px rgba(11, 31, 53, 0.04));
[data-icon] {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: var(--woly-line-height, 24px);
height: var(--woly-line-height, 24px);
padding-right: 6px;
svg > path {
fill: var(--woly-color-disabled, #000000);
}
}
li[data-type='list-item'] {
display: flex;
flex: 1;
align-items: center;
padding: var(--woly-vertical, 12px) var(--woly-horizontal, 18px 12px);
padding: var(--local-vertical) 0;
margin-bottom: var(--local-margin);
font-size: var(--woly-font-size, 15px);
line-height: var(--woly-line-height, 24px);
color: var(--local-color);
background: var(--local-item-background);
cursor: pointer;
outline: none;
[data-block='content'] {
[data-text] {
display: flex;
flex: 1;
padding: 0 var(--local-horizontal);
}
&:hover {
background-color: var(--woly-background-hover, #f5f5f5);
& > [data-text]:not(:only-child, :last-child ){
padding-right: 0;
}
&:focus,
[data-icon] {
--local-icon-size: var(--woly-line-height);
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: var(--local-icon-size);
height: var(--local-icon-size);
svg > path {
fill: var(--local-color);
}
}
[data-icon='left'] {
padding: 0 0 0 calc(var(--local-horizontal) - var(--local-compensate));
}
[data-icon='right'] {
padding: 0 calc(var(--local-horizontal) - var(--local-compensate)) 0 0;
}
[data-icon='left'] ~ [data-text],
[data-text] ~ [data-icon='right'] {
padding-left: var(--local-gap);
}
&:hover {
--local-item-background: var(--woly-canvas-disabled);
}
&:focus {
box-shadow: 0 0 0 var(--woly-border-width) var(--woly-focus);
}
&:active {
border-color: var(--woly-border-focus, #1f68f5);
border-style: solid;
border-width: var(--woly-border-width, 1.5px);
--local-item-background: var(--woly-focus);
--local-color: var(--woly-shape-text-active);
}
&[data-disabled='true'] {
color: var(--woly-color-disabled, #c4c4c4);
--local-color: var(--woly-canvas-text-disabled);
--local-item-background: var(--woly-canvas-disabled);
pointer-events: none;
[data-icon] {
svg > path {
fill: var(--woly-canvas, #c4c4c4);
}
--local-color: var(--woly-canvas-text-disabled);
}
}
}
&:focus {
box-shadow: 0 0 0 var(--woly-border-width) var(--woly-focus);
}
&[data-disabled='true'] {
pointer-events: none;
li[data-type='list-item'] {
--local-color: var(--woly-canvas-text-disabled);
--local-item-background: var(--woly-canvas-disabled);
}
[data-icon] {
--local-color: var(--woly-canvas-text-disabled);
}
}
` as StyledComponent<'ul', Record<string, unknown>, List & Variant>;
Loading

0 comments on commit 81b6fce

Please sign in to comment.