Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new component - alert #426

Merged
merged 20 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .jscpd.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
"**/angular.json",
"**/tsconfig.json",
"**/angular-*/**/main.ts",
"**/README.md"
"**/README.md",
"packages/components/src/components/alert/alert.lite.tsx",
"showcases/react-showcase/src/components/alert/index.tsx"
nmerget marked this conversation as resolved.
Show resolved Hide resolved
],
"absolute": true
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/components/_templates/mitosis/new/tsx.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function DB<%= h.changeCase.pascal(name) %>(props: DB<%= h.change
});

return (
<div className={'db-<%= name %>' + (props.className ? ' ' + props.className : '')}>
<div class={'db-<%= name %>' + (props.className ? ' ' + props.className : '')}>
mfranzke marked this conversation as resolved.
Show resolved Hide resolved
<Show when={state.stylePath}>
<link rel="stylesheet" href={state.stylePath} />
</Show>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DBAlert, DBAlertModule } from './alert';
20 changes: 20 additions & 0 deletions packages/components/scripts/post-build/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,26 @@
* }]}
*/
const getComponents = () => [
{
name: 'alert',
defaultStylePath: 'components/alert/alert.css',
overwrites: {
global: [
{ from: 'handleClick(event)', to: 'handleClick(event:any)' },
{
from: 'getIcon(icon, variant) {',
to: 'getIcon(icon:any, variant:any) {'
}
],
vue: [
{
from: 'import { DBAlertState, DBAlertProps } from "./model";',
to: ''
}
]
}
},

{
name: 'infotext',
defaultStylePath: 'components/infotext/infotext.css',
Expand Down
111 changes: 111 additions & 0 deletions packages/components/src/components/alert/alert.lite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
onMount,
Show,
Slot,
useMetadata,
useStore
} from '@builder.io/mitosis';
import { DBAlertState, DBAlertProps } from './model';
import { DBIcon } from '../icon';
import { DefaultVariantsIcon } from '../../shared/model';
import { DBButton } from '../button';
import { DBLink } from '../link';

useMetadata({
isAttachedToShadowDom: true,
component: {
includeIcon: false,
properties: []
}
});

const DEFAULT_VALUES = {
closeButton: 'Close Button'
};

export default function DBAlert(props: DBAlertProps) {
const state = useStore<DBAlertState>({
handleClick: (event) => {
if (props.onClick) {
props.onClick(event);
}
},
getIcon: (icon?: string, variant?: string) => {
return icon || DefaultVariantsIcon[variant] || 'info';
}
});

onMount(() => {
if (props.stylePath) {
state.stylePath = props.stylePath;
}
});

return (
<div
class={'db-alert' + (props.className ? ' ' + props.className : '')}
data-variant={props.variant}
data-type={props.type}>
<Show when={state.stylePath}>
<link rel="stylesheet" href={state.stylePath} />
</Show>
<div class="db-alert-icon-container">
<DBIcon icon={state.getIcon(props.icon, props.variant)} />
</div>
nmerget marked this conversation as resolved.
Show resolved Hide resolved
<div class="db-alert-content-container">
<div class="db-alert-headline-container">
<Show
when={props.headline}
else={<span>{props.children}</span>}>
<strong>{props.headline}</strong>
</Show>
<div class="db-alert-close-container">
<Show when={props.type !== 'inline'}>
<DBLink
className="db-alert-headline-link"
variant="inline"
href={props.link?.href}
target={props.link?.target}
rel={props.link?.rel}
role={props.link?.role}
disabled={props.link?.disabled}
selected={props.link?.selected}
label={props.link?.label}
hreflang={props.link?.hreflang}
current={props.link?.current}>
<Slot name="link" />
</DBLink>
</Show>
<DBButton
icon="close"
variant="ghost"
size="small"
onClick={(event) => state.handleClick(event)}>
{props.closeButtonText ??
DEFAULT_VALUES.closeButton}
</DBButton>
</div>
</div>

<Show when={props.headline}>
<span>{props.children}</span>
</Show>

<DBLink
className="db-alert-content-link"
variant="inline"
href={props.link?.href}
target={props.link?.target}
rel={props.link?.rel}
role={props.link?.role}
disabled={props.link?.disabled}
selected={props.link?.selected}
label={props.link?.label}
hreflang={props.link?.hreflang}
current={props.link?.current}>
<Slot name="link" />
</DBLink>
</div>
</div>
);
}
96 changes: 96 additions & 0 deletions packages/components/src/components/alert/alert.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
@use "@db-ui/foundations/build/scss/variables" as *;
@use "@db-ui/foundations/build/scss/variables.global" as *;
@use "@db-ui/foundations/build/scss/helpers/shadow-dom" as *;
@use "@db-ui/foundations/build/scss/color-placeholder" as *;

$variants: (
"critical": $db-colors-critical-element-enabled,
"information": $db-colors-information-element-enabled,
"warning": $db-colors-warning-element-enabled,
"success": $db-colors-success-element-enabled
);

@mixin handle-links($show-headline) {
.db-alert-headline-link {
@if ($show-headline) {
display: inherit;
} @else {
display: none;
}
}

.db-alert-content-link {
@if ($show-headline) {
display: none;
} @else {
display: inherit;
}
}
}

.db-alert {
@extend %shadow-dom-extend;
@extend %db-bg-neutral-0;

@include handle-links(true);

@media screen and (max-width: $db-screens-s) {
@include handle-links(false);
}

padding: $db-spacing-fixed-md;
display: flex;
gap: $db-spacing-fixed-md;
width: 100%;

.db-icon {
&::before {
annsch marked this conversation as resolved.
Show resolved Hide resolved
/* TODO: Take filled icons if they are ready */
--icon-font-family: var(--db-base-icon-font-family);
--icon-font-size: var(--db-base-icon-font-size);
}
}

&[data-type="inline"] {
@include handle-links(false);

width: fit-content;
min-width: calc($db-screens-xs - $db-spacing-fixed-md);
}

@each $name, $icon-color in $variants {
&[data-variant="#{$name}"] {
@if ($name == "critical") {
@extend %db-bg-critical-light;
} @else if ($name == "information") {
@extend %db-bg-information-light;
} @else if ($name == "warning") {
@extend %db-bg-warning-light;
} @else if ($name == "success") {
@extend %db-bg-success-light;
}

.db-alert-icon-container {
color: $icon-color;
}
}
}
}

.db-alert-content-container {
display: flex;
flex-direction: column;
gap: $db-spacing-fixed-xs;
width: 100%;
}

.db-alert-headline-container {
display: flex;
gap: $db-spacing-fixed-lg;
justify-content: space-between;
}

.db-alert-close-container {
display: flex;
gap: $db-spacing-fixed-md;
}
58 changes: 58 additions & 0 deletions packages/components/src/components/alert/alert.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { test, expect } from '@playwright/experimental-ct-react';
import AxeBuilder from '@axe-core/playwright';

import { DBAlert } from './index';
import { TESTING_VIEWPORTS, VARIANTS } from '../../shared/constants';

const comp = <DBAlert>Test</DBAlert>;

const testComponent = (viewport) => {
test(`should contain text for device ${viewport.name}`, async ({
mount
}) => {
const component = await mount(comp);
await expect(component).toContainText('Test');
});

test(`should match screenshot for device ${viewport.name}`, async ({
mount
}) => {
const component = await mount(comp);
await expect(component).toHaveScreenshot();
});
};

const testVariants = (viewport) => {
for (const variant of VARIANTS) {
test(`should match screenshot for variant ${variant} and device ${viewport.name}`, async ({
mount
}) => {
const component = await mount(
<DBAlert variant={variant}>Test</DBAlert>
);
await expect(component).toHaveScreenshot();
});
}
};

test.describe('DBAlert component', () => {
TESTING_VIEWPORTS.forEach((viewport) => {
test.use({ viewport });
testComponent(viewport);
testVariants(viewport);
});
});

test.describe('DBAlert component A11y', () => {
test('should not have any accessibility issues', async ({
page,
mount
}) => {
await mount(comp);
const accessibilityScanResults = await new AxeBuilder({ page })
.include('.db-alert')
.analyze();

expect(accessibilityScanResults.violations).toEqual([]);
});
});
1 change: 1 addition & 0 deletions packages/components/src/components/alert/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as DBAlert } from './alert';
29 changes: 29 additions & 0 deletions packages/components/src/components/alert/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
ClickEventProps,
ClickEventState,
DefaultVariantProps,
GlobalProps,
GlobalState,
LinkProps
} from '../../shared/model';

export interface DBAlertDefaultProps {
closeButtonText?: string;
headline?: string;
icon?: string;
link?: LinkProps;
type?: 'alert' | 'inline';
slotLink?: any;
variant?: 'adaptive' | DefaultVariantProps;
}

export type DBAlertProps = DBAlertDefaultProps & GlobalProps & ClickEventProps;

export interface DBAlertDefaultState {
getIcon: (
icon?: string,
variant?: 'adaptive' | DefaultVariantProps
) => string;
}

export type DBAlertState = DBAlertDefaultState & GlobalState & ClickEventState;
2 changes: 0 additions & 2 deletions packages/components/src/components/infotext/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import {
export interface DBInfotextDefaultProps {
icon?: string;
size?: 'medium' | 'small';

title?: string;
variant?: 'adaptive' | DefaultVariantProps;
}

Expand Down
10 changes: 7 additions & 3 deletions packages/components/src/components/link/link.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,13 @@ export default function DBLink(props: DBLinkProps) {
<link rel="stylesheet" href={state.stylePath} />
</Show>
{props.children}
<DBIcon
icon={props.content == 'external' ? 'link-external' : 'link'}
icntxt={true}></DBIcon>
<Show when={props.variant !== 'inline'}>
<DBIcon
icon={
props.content == 'external' ? 'link-external' : 'link'
}
icntxt={true}></DBIcon>
</Show>
</a>
);
}
Loading