Skip to content

Commit 633d4f7

Browse files
committed
✨ Add Modal component
1 parent 7de1a37 commit 633d4f7

File tree

15 files changed

+535
-4
lines changed

15 files changed

+535
-4
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,30 +107,51 @@ Default component styles can be changed by overriding the following CSS variable
107107

108108
```scss
109109
html body {
110+
// Avatar component
110111
--w-avatar-border: var(--w-color-primary-70);
112+
113+
// Checkbox component
111114
--w-checkbox-color: var(--w-color-primary);
115+
116+
// Progress component
112117
--w-progress-color: var(--w-color-primary);
113118
--w-progress-background: var(--w-color-primary-50);
114119
--w-progress-stripe-light: var(--w-color-primary);
115120
--w-progress-stripe-dark: var(--w-color-primary-10);
121+
122+
// Radio component
116123
--w-radio-color: var(--w-color-primary);
124+
125+
// Rating component
117126
--w-rating-color: var(--w-color-primary);
118127
--w-rating-empty-color: var(--w-color-primary);
119128
--w-rating-empty-background: var(--w-color-primary-70);
120129
--w-rating-size: 18px;
130+
131+
// Scrollbars
121132
--w-scrollbar-bg: var(--w-color-primary-60);
122133
--w-scrollbar-fg: var(--w-color-primary-50);
134+
135+
// Spinner component
123136
--w-spinner-color: var(--w-color-primary);
124137
--w-spinner-width: 2px;
125138
--w-spinner-speed: 2s;
126139
--w-spinner-size: 30px;
127140
--w-spinner-dash: 8;
141+
142+
// Switch component
128143
--w-switch-off-color: var(--w-color-primary-50);
129144
--w-switch-on-color: var(--w-color-primary);
145+
146+
// ThemeSwitcher component
130147
--w-theme-switcher-size: 20px;
148+
149+
// Timeline component
131150
--w-timeline-color: var(--w-color-primary-50);
132151
--w-timeline-text-color: var(--w-color-primary);
133152
--w-timeline-counter: decimal;
153+
154+
// Tooltips
134155
--w-tooltip-background: var(--w-color-primary);
135156
--w-tooltip-color: var(--w-color-primary-70);
136157

@@ -175,6 +196,7 @@ import { Accordion } from 'webcoreui/react'
175196
- [Icon](https://github.com/Frontendland/webcoreui/tree/main/src/components/Icon)
176197
- [Input](https://github.com/Frontendland/webcoreui/tree/main/src/components/Input)
177198
- [Menu](https://github.com/Frontendland/webcoreui/tree/main/src/components/Menu)
199+
- [Modal](https://github.com/Frontendland/webcoreui/tree/main/src/components/Modal)
178200
- [Progress](https://github.com/Frontendland/webcoreui/tree/main/src/components/Progress)
179201
- [Radio](https://github.com/Frontendland/webcoreui/tree/main/src/components/Radio)
180202
- [Rating](https://github.com/Frontendland/webcoreui/tree/main/src/components/Rating)

src/components/Button/button.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ export type SvelteButtonProps = {
1818

1919
export type ReactButtonProps = {
2020
onClick?: () => any
21-
children: React.ReactNode
21+
children?: React.ReactNode
2222
} & ButtonProps

src/components/Icon/map.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Alert from '../../icons/alert.svg?raw'
22
import ArrowDown from '../../icons/arrow-down.svg?raw'
33
import Check from '../../icons/check.svg?raw'
44
import CircleCheck from '../../icons/circle-check.svg?raw'
5+
import Close from '../../icons/close.svg?raw'
56
import Github from '../../icons/github.svg?raw'
67
import Info from '../../icons/info.svg?raw'
78
import Moon from '../../icons/moon.svg?raw'
@@ -13,6 +14,7 @@ const iconMap = {
1314
'arrow-down': ArrowDown,
1415
'check': Check,
1516
'circle-check': CircleCheck,
17+
'close': Close,
1618
'github': Github,
1719
'info': Info,
1820
'moon': Moon,

src/components/Modal/Modal.astro

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
import type { ModalProps } from './modal'
3+
import styles from './modal.module.scss'
4+
5+
import Button from '../Button/Button.astro'
6+
import closeIcon from '../../icons/close.svg?raw'
7+
8+
interface Props extends ModalProps {}
9+
10+
const {
11+
title,
12+
subTitle,
13+
showCloseIcon = true,
14+
closeOnEsc = true,
15+
closeOnOverlay = true,
16+
id,
17+
className
18+
} = Astro.props
19+
20+
const close = [
21+
showCloseIcon && 'icon',
22+
closeOnEsc && 'esc',
23+
closeOnOverlay && 'overlay'
24+
].filter(Boolean).join(',')
25+
26+
const classes = [
27+
styles.modal,
28+
className
29+
]
30+
---
31+
32+
<dialog
33+
class:list={classes}
34+
id={id}
35+
data-close={close.length ? close : undefined}
36+
>
37+
{showCloseIcon && (
38+
<Button
39+
theme="flat"
40+
className={styles.close}
41+
data-id="close"
42+
>
43+
<Fragment set:html={closeIcon} />
44+
</Button>
45+
)}
46+
{title && <strong class={styles.title}>{title}</strong>}
47+
{subTitle && <div class={styles.subTitle}>{subTitle}</div>}
48+
<slot />
49+
</dialog>
50+
<div class={styles.overlay} />

src/components/Modal/Modal.svelte

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<script lang="ts">
2+
import type { ModalProps } from './modal'
3+
4+
import styles from './modal.module.scss'
5+
import { classNames } from '../../utils/classNames'
6+
7+
import Button from '../Button/Button.svelte'
8+
import closeIcon from '../../icons/close.svg?raw'
9+
10+
export let title: ModalProps['title'] = ''
11+
export let subTitle: ModalProps['subTitle'] = ''
12+
export let showCloseIcon: ModalProps['showCloseIcon'] = true
13+
export let closeOnEsc: ModalProps['closeOnEsc'] = true
14+
export let closeOnOverlay: ModalProps['closeOnOverlay'] = true
15+
export let id : ModalProps['className'] = ''
16+
export let className: ModalProps['className'] = ''
17+
18+
const classes = classNames([
19+
styles.modal,
20+
className
21+
])
22+
23+
const close = [
24+
showCloseIcon && 'icon',
25+
closeOnEsc && 'esc',
26+
closeOnOverlay && 'overlay'
27+
].filter(Boolean).join(',')
28+
</script>
29+
30+
<dialog
31+
class={classes}
32+
id={id}
33+
data-close={close.length ? close : undefined}
34+
>
35+
{#if showCloseIcon}
36+
<Button
37+
theme="flat"
38+
className={styles.close}
39+
data-id="close"
40+
>
41+
{@html closeIcon}
42+
</Button>
43+
{/if}
44+
{#if title}
45+
<strong class={styles.title}>{title}</strong>
46+
{/if}
47+
{#if subTitle}
48+
<div class={styles.subTitle}>{subTitle}</div>
49+
{/if}
50+
<slot />
51+
</dialog>
52+
<div class={styles.overlay} />

src/components/Modal/Modal.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react'
2+
import type { ReactModalProps } from './modal'
3+
4+
import styles from './modal.module.scss'
5+
import { classNames } from '../../utils/classNames'
6+
7+
import Button from '../Button/Button.tsx'
8+
import closeIcon from '../../icons/close.svg?raw'
9+
10+
const Modal = ({
11+
title,
12+
subTitle,
13+
showCloseIcon = true,
14+
closeOnEsc = true,
15+
closeOnOverlay = true,
16+
id,
17+
className,
18+
children
19+
}: ReactModalProps) => {
20+
const classes = classNames([
21+
styles.modal,
22+
className
23+
])
24+
25+
const close = [
26+
showCloseIcon && 'icon',
27+
closeOnEsc && 'esc',
28+
closeOnOverlay && 'overlay'
29+
].filter(Boolean).join(',')
30+
31+
return (
32+
<React.Fragment>
33+
<dialog
34+
className={classes}
35+
id={id}
36+
data-close={close.length ? close : undefined}
37+
>
38+
{showCloseIcon && (
39+
<Button
40+
theme="flat"
41+
className={styles.close}
42+
data-id="close"
43+
dangerouslySetInnerHTML={{ __html: closeIcon }}
44+
/>
45+
)}
46+
{title && <strong className={styles.title}>{title}</strong>}
47+
{subTitle && <div className={styles.subTitle}>{subTitle}</div>}
48+
{children}
49+
</dialog>
50+
<div className={styles.overlay} />
51+
</React.Fragment>
52+
)
53+
}
54+
55+
export default Modal
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
@import '../../scss/config.scss';
2+
3+
.modal {
4+
@include transition();
5+
@include position(fixed, 't50%', 'l50%');
6+
@include spacing(0, p-default);
7+
@include layer(modal);
8+
@include visibility(block, 0);
9+
@include border(primary-50);
10+
@include background(primary-70);
11+
@include typography(primary);
12+
@include border-radius(md);
13+
@include size('w90%');
14+
15+
transform: translate(-50%, calc(-50% + 15px));
16+
max-width: 500px;
17+
pointer-events: none;
18+
19+
&[data-show="true"] {
20+
@include visibility(1);
21+
22+
transform: translate(-50%, -50%);
23+
pointer-events: all;
24+
25+
+ .overlay {
26+
@include visibility(1);
27+
pointer-events: all;
28+
}
29+
}
30+
31+
.close {
32+
@include position(absolute, t10px, r10px);
33+
@include spacing(p-xs);
34+
35+
svg {
36+
@include size(10px);
37+
}
38+
}
39+
40+
.title {
41+
@include typography(lg);
42+
@include spacing(mb-xs);
43+
display: block;
44+
}
45+
46+
.subTitle {
47+
@include typography(primary-20);
48+
@include spacing(mb-xs);
49+
}
50+
}
51+
52+
.overlay {
53+
@include transition(opacity);
54+
@include position(fixed);
55+
@include background(overlay);
56+
@include layer(header);
57+
@include visibility(0);
58+
59+
inset: 0;
60+
pointer-events: none;
61+
}
62+
63+
@include media(xs) {
64+
.modal {
65+
@include size('wauto');
66+
}
67+
}

src/components/Modal/modal.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export type ModalProps = {
2+
title?: string
3+
subTitle?: string
4+
showCloseIcon?: boolean
5+
closeOnEsc?: boolean
6+
closeOnOverlay?: boolean
7+
id?: string
8+
className?: string
9+
}
10+
11+
export type ReactModalProps = {
12+
children?: React.ReactNode
13+
} & ModalProps

src/icons/close.svg

Lines changed: 3 additions & 0 deletions
Loading

src/pages/index.astro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ const tabItems = [{
137137
<Fragment set:html={logo} />
138138
</Menu>
139139
</CardWrapper>
140+
<CardWrapper title="Modal" href="/modal">
141+
<Button theme="outline">Trigger Modal</Button>
142+
</CardWrapper>
140143
<CardWrapper title="Progress" href="/progress">
141144
<Progress value={33} />
142145
</CardWrapper>

0 commit comments

Comments
 (0)