Skip to content

Commit

Permalink
Merge pull request #372 from dhis2/feat/list-context-menu
Browse files Browse the repository at this point in the history
feat(list): context menu
  • Loading branch information
Birkbjo authored Mar 5, 2024
2 parents 849de93 + c19814f commit f5aa068
Show file tree
Hide file tree
Showing 8 changed files with 502 additions and 35 deletions.
7 changes: 5 additions & 2 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2024-03-01T17:52:14.520Z\n"
"PO-Revision-Date: 2024-03-01T17:52:14.520Z\n"
"POT-Creation-Date: 2024-03-05T18:46:53.934Z\n"
"PO-Revision-Date: 2024-03-05T18:46:53.934Z\n"

msgid "schemas"
msgstr "schemas"
Expand Down Expand Up @@ -177,6 +177,9 @@ msgstr "Search by name, code or ID"
msgid "Public access"
msgstr "Public access"

msgid "Show details"
msgstr "Show details"

msgid "At least one column must be selected"
msgstr "At least one column must be selected"

Expand Down
288 changes: 288 additions & 0 deletions src/components/LinkButton/LinkButton.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
.linkButton {
display: inline-flex;
position: relative;
align-items: center;
justify-content: center;
border-radius: 4px;
font-weight: 400;
letter-spacing: 0.5px;
text-decoration: none;
cursor: pointer;
user-select: none;
color: var(--colors-grey900);

/*medium*/
height: 36px;
padding: 0 var(--spacers-dp12);
font-size: 14px;
line-height: 16px;

/*basic*/
border: 1px solid var(--colors-grey500);
background-color: #f9fafb;
}

.linkButton:disabled {
cursor: not-allowed;
}

.linkButton:focus {
outline: 3px solid blue;
outline-offset: -3px;
text-decoration: underline;
}

/* Prevent focus styles when mouse clicking */
.linkButton:focus:not(:focus-visible) {
outline: none;
text-decoration: none;
}

/* Prevent focus styles on active and disabled buttons */
.linkButton:active:focus,
.linkButton:disabled:focus {
outline: none;
text-decoration: none;
}

.linkButton:hover {
border-color: var(--colors-grey500);
background-color: var(--colors-grey200);
}

.linkButton:active,
.linkButton:active:focus {
border-color: var(--colors-grey500);
background-color: var(--colors-grey200);
box-shadow: 0 0 0 1px rgb(0, 0, 0, 0.1) inset;
}

.linkButton:focus {
background-color: #f9fafb;
}

.linkButton:disabled {
border-color: var(--colors-grey400);
background-color: #f9fafb;
box-shadow: none;
color: var(--theme-disabled);
fill: var(--theme-disabled);
}

.small {
height: 28px;
padding: 0 6px;
font-size: 14px;
line-height: 16px;
}

.large {
height: 43px;
padding: 0 var(--spacers-dp24);
font-size: 16px;
letter-spacing: 0.57px;
line-height: 19px;
}

.primary {
border-color: var(--theme-primary800);
background: linear-gradient(180deg, #1565c0 0%, #0650a3 100%);
background-color: #2b61b3;
color: var(--colors-white);
fill: var(--colors-white);
font-weight: 500;
}

.primary:hover {
border-color: var(--theme-primary800);
background: linear-gradient(180deg, #054fa3 0%, #034793 100%);
background-color: #21539f;
}

.primary:active,
.primary:active:focus {
background: linear-gradient(180deg, #054fa3 0%, #034793 100%);
background-color: #1c4a90;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18) inset;
}

.primary:focus {
background: var(--colors-blue800);
border-color: var(--colors-blue900);
outline-offset: -5px;
}

.primary:disabled {
border-color: #93a6bd;
background: #b3c6de;
box-shadow: none;
color: var(--colors-white);
fill: var(--colors-white);
}

.secondary {
border-color: rgba(74, 87, 104, 0.25);
background-color: transparent;
}

.secondary:hover {
border-color: rgba(74, 87, 104, 0.5);
background-color: rgba(160, 173, 186, 0.05);
}

.secondary:active,
.secondary:active:focus {
background-color: rgba(160, 173, 186, 0.2);
box-shadow: none;
}

.secondary:focus {
background-color: transparent;
}

.secondary:disabled {
border-color: rgba(74, 87, 104, 0.25);
background-color: transparent;
box-shadow: none;
color: var(--theme-disabled);
fill: var(--theme-disabled);
}

.destructive {
border-color: #a10b0b;
background: linear-gradient(180deg, #d32f2f 0%, #b71c1c 100%);
background-color: #b9242b;
color: var(--colors-white);
fill: var(--colors-white);
font-weight: 500;
}

.destructive:hover {
border-color: #a10b0b;
background: linear-gradient(180deg, #b81c1c 0%, #b80c0b 100%);
background-color: #ac0f1a;
}

.destructive:active,
.destructive:active:focus {
background: linear-gradient(180deg, #b81c1c 0%, #b80c0b 100%);
background-color: #ac101b;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18) inset;
}

.destructive:focus {
background: linear-gradient(180deg, #d32f2f 0%, #b71c1c 100%);
background-color: #b72229;
}

.destructive:disabled {
border-color: #c59898;
background: #d6a8a8;
box-shadow: none;
color: var(--colors-white);
fill: var(--colors-white);
}

.destructive.secondary {
border-color: rgba(74, 87, 104, 0.25);
background: transparent;
color: var(--colors-red700);
fill: var(--colors-red700);
font-weight: 400;
}

.destructive.secondary:hover {
border-color: var(--colors-red600);
background: var(--colors-red050);
color: var(--colors-red800);
fill: var(--colors-red800);
}

.destructive.secondary:active,
.destructive.secondary:active:focus {
background: var(--colors-red100);
border-color: var(--colors-red700);
box-shadow: none;
}

.destructive.secondary:disabled {
background: transparent;
border-color: rgba(74, 87, 104, 0.25);
color: rgba(183, 28, 28, 0.6);
fill: rgba(183, 28, 28, 0.6);
}

.icon-only {
padding: 0 0 0 5px;
}

.button-icon {
margin-right: 6px;
color: inherit;
fill: inherit;
font-size: 26px;
vertical-align: middle;
pointer-events: none;
}

.icon-only .button-icon {
margin-right: 5px;
}

.small.icon-only {
padding: 0 4px 0 5px;
}

.small .button-icon {
margin-right: 2px;
}

.small.icon-only .button-icon {
margin-right: 1px;
}

.toggled {
background: var(--colors-grey700);
border: 1px solid var(--colors-grey900);
color: var(--colors-grey050);
fill: var(--colors-grey050);
}

.toggled:focus {
background: var(--colors-grey800);
}

.toggled:hover {
background: var(--colors-grey800);
border-color: var(--colors-grey900);
}

.toggled:active,
.toggled:active:focus {
background: var(--colors-grey900);
border-color: var(--colors-grey900);
}

.toggled:disabled {
background: var(--colors-grey500);
border-color: var(--colors-grey600);
color: var(--colors-grey050);
fill: var(--colors-grey050);
}

.loader {
width: 16px;
height: 16px;
margin-right: 8px;
}

.loader + .button-icon {
display: none;
}

.icon-only .loader {
margin: 0 8px 0 4px;
}
.small.icon-only .loader {
margin: 0 4px;
}
87 changes: 87 additions & 0 deletions src/components/LinkButton/LinkButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { ButtonProps } from '@dhis2/ui'
import cx from 'classnames'
import React, { AnchorHTMLAttributes } from 'react'
import { useLinkClickHandler, useHref } from 'react-router-dom'
import css from './LinkButton.module.css'

type UseLinkClickHandlerParameters = Parameters<typeof useLinkClickHandler>

type LinkClickHandlerOptions = UseLinkClickHandlerParameters[1]

type RelevantButtonProps = Pick<
ButtonProps,
| 'disabled'
| 'className'
| 'primary'
| 'secondary'
| 'small'
| 'toggled'
| 'large'
| 'destructive'
>

type LinkButtonProps = AnchorHTMLAttributes<HTMLAnchorElement> &
LinkClickHandlerOptions &
RelevantButtonProps & {
to: Parameters<typeof useLinkClickHandler>[0]
}

/* Wrapping button with anchor-tags are not valid, style anchor as a UI-button */
export const LinkButton = ({
onClick,
disabled,
className,
primary,
secondary,
small,
toggled,
large,
destructive,
target,
replace,
state,
preventScrollReset,
relative,
to,
href,
...anchorProps
}: LinkButtonProps) => {
const resolvedHref = useHref(to, { relative })
const handleClickInternal = useLinkClickHandler(to, {
replace,
state,
preventScrollReset,
relative,
target,
})

const handleClick = (
event: React.MouseEvent<HTMLAnchorElement, MouseEvent>
) => {
if (onClick) {
onClick(event)
}
if (!event.defaultPrevented) {
handleClickInternal(event)
}
}

const resolvedClassname = cx(css.linkButton, className, {
[css.disabled]: disabled,
[css.primary]: primary,
[css.secondary]: secondary,
[css.destructive]: destructive,
[css.toggled]: toggled,
[css.large]: large,
[css.small]: small,
})
return (
<a
{...anchorProps}
className={resolvedClassname}
href={href || resolvedHref}
onClick={href ? onClick : handleClick}
target={target}
/>
)
}
1 change: 1 addition & 0 deletions src/components/LinkButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './LinkButton'
Loading

0 comments on commit f5aa068

Please sign in to comment.