nitro-web 0.0.16 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,7 +26,7 @@
26
26
  @apply text-dark mb-2 text-sm font-bold;
27
27
  }
28
28
  label, .label {
29
- @apply text-sm-label font-medium;
29
+ @apply text-sm font-medium;
30
30
  }
31
31
  }
32
32
 
@@ -1,4 +1,3 @@
1
-
2
1
  import 'nitro-web/client/globals'
3
2
  import { setupApp } from 'nitro-web'
4
3
 
@@ -6,5 +5,5 @@ import './css/index.css'
6
5
  import config from './config'
7
6
  import { Layout1, Layout2 } from '../components/partials/layouts'
8
7
 
9
- // Auto-import page components, initilize app, and run config.beforeApp
8
+ // Auto-import page components, initialise app, and run config.beforeApp
10
9
  setupApp(config, [Layout1, Layout2])
@@ -4,6 +4,7 @@ import path from 'path'
4
4
  import Color from 'color'
5
5
 
6
6
  const lighten = (clr, val) => Color(clr).lighten(val).rgb().string()
7
+ const darken = (clr, val) => Color(clr).darken(val).rgb().string()
7
8
  const nitroDir = path.dirname(require.resolve('nitro-web'))
8
9
 
9
10
  export default {
@@ -25,13 +26,11 @@ export default {
25
26
  },
26
27
  colors: {
27
28
  // Main colors
28
- 'primary': colors.indigo[500],
29
- 'primary-dark': colors.indigo[600],
30
- 'primary-light': colors.indigo[400],
31
- 'primary-hover': lighten(colors.indigo[500], 0.05),
29
+ 'primary': '#4c50f9',
30
+ 'primary-dark': darken('#4c50f9', 0.05),
31
+ 'primary-hover': lighten('#4c50f9', 0.05),
32
32
  'secondary': colors.green[500],
33
33
  'secondary-dark': colors.green[600],
34
- 'secondary-light': colors.green[400],
35
34
  'secondary-hover': lighten(colors.green[500], 0.05),
36
35
  'label': colors.gray[900],
37
36
  'link': colors.black,
@@ -40,6 +39,7 @@ export default {
40
39
  'light': colors.gray[100],
41
40
  'dark': colors.gray[900],
42
41
  // Alert colors
42
+ 'critical': '#ff0000',
43
43
  'danger': '#ff0000',
44
44
  'danger-dark': colors.red[800],
45
45
  'info': colors.blue[500],
@@ -54,15 +54,15 @@ export default {
54
54
  sans: ['Inter', ...defaultTheme.fontFamily.sans],
55
55
  },
56
56
  fontSize: {
57
- '2xs': ['0.77rem', { lineHeight: '1.5' }],
58
- 'xs': ['0.83rem', { lineHeight: '1.5' }],
59
- 'sm-label': ['0.87rem', { lineHeight: '1.5' }],
60
- 'sm': ['0.90rem', { lineHeight: '1.5' }],
61
- 'base': ['1rem', { lineHeight: '1.5' }],
62
- 'lg': ['1.16rem', { lineHeight: '1.75' }],
63
- 'xl': ['1.29rem', { lineHeight: '1.75' }],
64
- '2xl': ['1.45rem', { lineHeight: '1.75' }],
65
- '3xl': ['1.94rem', { lineHeight: '1.75' }],
57
+ '2xs': ['12px', { lineHeight: '1.5' }],
58
+ 'xs': ['13px', { lineHeight: '1.5' }],
59
+ 'sm': ['13.5px', { lineHeight: '1.5' }],
60
+ 'md': ['14px', { lineHeight: '1.5' }],
61
+ 'base': ['15.5px', { lineHeight: '1.5' }],
62
+ 'lg': ['18px', { lineHeight: '1.75' }],
63
+ 'xl': ['20px', { lineHeight: '1.75' }],
64
+ '2xl': ['22.5px', { lineHeight: '1.75' }],
65
+ '3xl': ['30px', { lineHeight: '1.75' }],
66
66
  },
67
67
  spacing: {
68
68
  'input-before': '0.625rem',
package/client/index.ts CHANGED
@@ -22,11 +22,12 @@ export { Styleguide } from '../components/partials/styleguide'
22
22
  export { Accordion } from '../components/partials/element/accordion'
23
23
  export { Avatar } from '../components/partials/element/avatar'
24
24
  export { Button } from '../components/partials/element/button'
25
+ export { Calendar, type CalendarProps } from '../components/partials/element/calendar'
25
26
  export { Dropdown } from '../components/partials/element/dropdown'
26
27
  export { GithubLink } from '../components/partials/element/github-link'
27
28
  export { Initials } from '../components/partials/element/initials'
28
29
  export { Message } from '../components/partials/element/message'
29
- // export { Modal } from '../components/partials/element/modal'
30
+ export { Modal } from '../components/partials/element/modal'
30
31
  export { Sidebar, type SidebarProps } from '../components/partials/element/sidebar'
31
32
  export { Tooltip } from '../components/partials/element/tooltip'
32
33
  export { Topbar } from '../components/partials/element/topbar'
@@ -36,10 +37,10 @@ export { Checkbox } from '../components/partials/form/checkbox'
36
37
  export { Drop } from '../components/partials/form/drop'
37
38
  export { DropHandler } from '../components/partials/form/drop-handler'
38
39
  export { FormError } from '../components/partials/form/form-error'
39
- export { Input } from '../components/partials/form/input'
40
- export { InputColor } from '../components/partials/form/input-color'
41
- export { InputCurrency } from '../components/partials/form/input-currency'
42
- // export { InputDate } from '../components/partials/form/input-date'
40
+ export { Field } from '../components/partials/form/input'
41
+ export { FieldColor, type FieldColorProps } from '../components/partials/form/input-color'
42
+ export { FieldCurrency, type FieldCurrencyProps } from '../components/partials/form/input-currency'
43
+ export { FieldDate, type FieldDateProps } from '../components/partials/form/input-date'
43
44
  export { Location } from '../components/partials/form/location'
44
45
  export { Select, getSelectStyle } from '../components/partials/form/select'
45
46
  export { Toggle } from '../components/partials/form/toggle'
@@ -1,4 +1,4 @@
1
- import { Topbar, Input, FormError, Button, util } from 'nitro-web'
1
+ import { Topbar, Field, FormError, Button, util } from 'nitro-web'
2
2
  import { Errors } from 'types'
3
3
 
4
4
  export function ResetInstructions() {
@@ -24,7 +24,7 @@ export function ResetInstructions() {
24
24
  <form onSubmit={onSubmit}>
25
25
  <div>
26
26
  <label for="email">Email Address</label>
27
- <Input name="email" type="email" state={state} onChange={onChange.bind(setState)} placeholder="Your email address..." />
27
+ <Field name="email" type="email" state={state} onChange={onChange.bind(setState)} placeholder="Your email address..." />
28
28
  </div>
29
29
 
30
30
  <div class="mb-14">
@@ -67,11 +67,11 @@ export function ResetPassword() {
67
67
  <form onSubmit={onSubmit}>
68
68
  <div>
69
69
  <label for="password">Your New Password</label>
70
- <Input name="password" type="password" state={state} onChange={onChange.bind(setState)} />
70
+ <Field name="password" type="password" state={state} onChange={onChange.bind(setState)} />
71
71
  </div>
72
72
  <div>
73
73
  <label for="password2">Repeat Your New Password</label>
74
- <Input name="password2" type="password" state={state} onChange={onChange.bind(setState)} />
74
+ <Field name="password2" type="password" state={state} onChange={onChange.bind(setState)} />
75
75
  </div>
76
76
 
77
77
  <div class="mb-14">
@@ -1,4 +1,4 @@
1
- import { Topbar, Input, Button, FormError, util } from 'nitro-web'
1
+ import { Topbar, Field, Button, FormError, util } from 'nitro-web'
2
2
  import { Config, Errors } from 'types'
3
3
 
4
4
  export function Signin({ config }: { config: Config }) {
@@ -50,14 +50,14 @@ export function Signin({ config }: { config: Config }) {
50
50
  <form onSubmit={onSubmit}>
51
51
  <div>
52
52
  <label for="email">Email Address</label>
53
- <Input name="email" type="email" state={state} onChange={onChange.bind(setState)} placeholder="Your email address..." />
53
+ <Field name="email" type="email" state={state} onChange={onChange.bind(setState)} placeholder="Your email address..." />
54
54
  </div>
55
55
  <div>
56
56
  <div class="flex justify-between">
57
57
  <label for="password">Password</label>
58
58
  <Link to="/reset" class="label underline2">Forgot?</Link>
59
59
  </div>
60
- <Input name="password" type="password" state={state} onChange={onChange.bind(setState)}/>
60
+ <Field name="password" type="password" state={state} onChange={onChange.bind(setState)}/>
61
61
  </div>
62
62
 
63
63
  <div class="mb-14">
@@ -1,4 +1,4 @@
1
- import { Button, Input, FormError, Topbar, util } from 'nitro-web'
1
+ import { Button, Field, FormError, Topbar, util } from 'nitro-web'
2
2
  import { Config, Errors } from 'types'
3
3
 
4
4
  export function Signup({ config }: { config: Config}) {
@@ -32,20 +32,20 @@ export function Signup({ config }: { config: Config}) {
32
32
  <div class="grid grid-cols-2 gap-6">
33
33
  <div>
34
34
  <label for="name">Your Name</label>
35
- <Input name="name" placeholder="E.g. Bruce Wayne" state={state} onChange={onChange.bind(setState)} />
35
+ <Field name="name" placeholder="E.g. Bruce Wayne" state={state} onChange={onChange.bind(setState)} />
36
36
  </div>
37
37
  <div>
38
38
  <label for="business.name">Company Name</label>
39
- <Input name="business.name" placeholder="E.g. Wayne Enterprises" state={state} onChange={onChange.bind(setState)} />
39
+ <Field name="business.name" placeholder="E.g. Wayne Enterprises" state={state} onChange={onChange.bind(setState)} />
40
40
  </div>
41
41
  </div>
42
42
  <div>
43
43
  <label for="email">Email Address</label>
44
- <Input name="email" type="email" state={state} onChange={onChange.bind(setState)} placeholder="Your email address..." />
44
+ <Field name="email" type="email" state={state} onChange={onChange.bind(setState)} placeholder="Your email address..." />
45
45
  </div>
46
46
  <div>
47
47
  <label for="password">Password</label>
48
- <Input name="password" type="password" state={state} onChange={onChange.bind(setState)}/>
48
+ <Field name="password" type="password" state={state} onChange={onChange.bind(setState)}/>
49
49
  </div>
50
50
 
51
51
  <div class="mb-14">
@@ -1,5 +1,5 @@
1
1
  import { twMerge } from 'tailwind-merge'
2
- import { ChevronDownIcon } from '@heroicons/react/20/solid'
2
+ import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/20/solid'
3
3
 
4
4
  type Props = {
5
5
  color?: 'primary'|'secondary'|'white'
@@ -16,7 +16,7 @@ type Props = {
16
16
  export function Button({ color='primary', size='md', className, isLoading, IconLeft, IconRight, IconRight2, children, ...props }: Props) {
17
17
  // const size = (color.match(/xs|sm|md|lg/)?.[0] || 'md') as 'xs'|'sm'|'md'|'lg'
18
18
  const iconPosition = IconLeft ? 'left' : IconRight ? 'right' : IconRight2 ? 'right2' : 'none'
19
- const base = 'relative inline-block font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2'
19
+ const base = 'relative inline-block font-medium shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2'
20
20
 
21
21
  // Button types
22
22
  const primary = 'bg-primary text-white shadow-sm hover:bg-primary-hover focus-visible:outline-primary'
@@ -48,7 +48,8 @@ export function Button({ color='primary', size='md', className, isLoading, IconL
48
48
  const loading = isLoading ? '[&>*]:opacity-0 text-opacity-0' : ''
49
49
 
50
50
  function getIcon(Icon: React.ReactNode | 'v') {
51
- if (Icon == 'v') return <ChevronDownIcon className="size-6 -my-6 -mx-1" />
51
+ if (Icon == 'v' || Icon == 'down') return <ChevronDownIcon className="size-5 -my-6 -mx-1" />
52
+ if (Icon == '^' || Icon == 'up') return <ChevronUpIcon className="size-5 -my-6 -mx-1" />
52
53
  else return Icon
53
54
  }
54
55
 
@@ -0,0 +1,123 @@
1
+ import { DayPicker, getDefaultClassNames } from 'react-day-picker'
2
+ import { isValid } from 'date-fns'
3
+ import 'react-day-picker/style.css'
4
+ import { IsFirstRender } from 'nitro-web'
5
+
6
+ type Mode = 'single'|'multiple'|'range'
7
+ type ModeSelection<T extends Mode> = (
8
+ T extends 'single' ? Date | undefined
9
+ : T extends 'multiple' ? Date[]
10
+ : { from?: Date; to?: Date }
11
+ )
12
+
13
+ export type CalendarProps = {
14
+ mode?: Mode
15
+ onChange?: (mode: Mode, value: null|number|(null|number)[]) => void
16
+ value?: null|number|string|(null|number|string)[]
17
+ numberOfMonths?: number
18
+ month?: number // the value may be updated from an outside source, thus the month may have changed
19
+ className?: string
20
+ preserveTime?: boolean
21
+ }
22
+
23
+ export function Calendar({ mode='single', onChange, value, numberOfMonths, month: monthProp, className, preserveTime }: CalendarProps) {
24
+ const isFirstRender = IsFirstRender()
25
+ const isRange = mode == 'range'
26
+
27
+ // Convert the value to an array of valid* dates
28
+ const dates = useMemo(() => {
29
+ const _dates = Array.isArray(value) ? value : [value]
30
+ return _dates.map(date => isValid(date) ? new Date(date as number) : undefined) ////change to null
31
+ }, [value])
32
+
33
+ // Hold the month in state to control the calendar when the input changes
34
+ const [month, setMonth] = useState(dates[0])
35
+
36
+ // Update the month if its changed from an outside source
37
+ useEffect(() => {
38
+ if (!isFirstRender && monthProp) setMonth(new Date(monthProp))
39
+ }, [monthProp])
40
+
41
+ function handleDayPickerSelect<T extends Mode>(newDate: ModeSelection<T>) {
42
+ switch (mode as T) {
43
+ case 'single': {
44
+ const date = newDate as ModeSelection<'single'>
45
+ preserveTimeFn(date)
46
+ onChange?.(mode, date?.getTime() ?? null)
47
+ break
48
+ }
49
+ case 'range': {
50
+ const { from, to } = (newDate ?? {}) as ModeSelection<'range'>
51
+ onChange?.(mode, from ? [from.getTime() || null, to?.getTime() || null] : null)
52
+ break
53
+ }
54
+ case 'multiple': {
55
+ const dates = (newDate as ModeSelection<'multiple'>)?.filter(Boolean) ?? []
56
+ onChange?.(mode, dates.map((d) => d.getTime()))
57
+ break
58
+ }
59
+ }
60
+ }
61
+
62
+ function preserveTimeFn(date?: Date) {
63
+ // Preserve time from the original date if needed
64
+ if (preserveTime && dates[0] && date) {
65
+ const originalDate = dates[0]
66
+ date.setHours(
67
+ originalDate.getHours(),
68
+ originalDate.getMinutes(),
69
+ originalDate.getSeconds(),
70
+ originalDate.getMilliseconds()
71
+ )
72
+ }
73
+ }
74
+
75
+ const d = getDefaultClassNames()
76
+ const common = {
77
+ month: month,
78
+ onMonthChange: setMonth,
79
+ onSelect: handleDayPickerSelect,
80
+ numberOfMonths: numberOfMonths || (isRange ? 2 : 1),
81
+ modifiersClassNames: {
82
+ // Add a class without _, TW seems to replace this with a space in the css definition, e.g. &:not(.range middle)
83
+ range_middle: `${d.range_middle} rangemiddle`,
84
+ },
85
+ classNames: {
86
+ root: `${d.root} flex`,
87
+ months: `${d.months} flex-nowrap`,
88
+ month_caption: `${d.month_caption} text-2xs pl-2`,
89
+ caption_label: `${d.caption_label} z-auto`,
90
+ button_previous: `${d.button_previous} size-8`,// [&:hover>svg]:fill-primary-dark`,
91
+ button_next: `${d.button_next} size-8`,// [&:hover>svg]:fill-primary-dark`,
92
+ chevron: `${d.chevron} fill-black size-[18px]`,
93
+
94
+ // Days
95
+ weekday: `${d.weekday} text-[11px] font-bold uppercase`,
96
+ day: `${d.day} size-[33px]`,
97
+ day_button: `${d.day_button} size-[33px] text-sm`,
98
+
99
+ // States
100
+ focused: `${d.focused} [&>button]:bg-gray-200 [&>button]:border-gray-200`,
101
+ range_start: `${d.range_start} [&>button]:!bg-primary-dark [&>button]:!border-primary-dark`,
102
+ range_end: `${d.range_end} [&>button]:!bg-primary-dark [&>button]:!border-primary-dark`,
103
+ selected: `${d.selected} font-normal `
104
+ + '[&:not(.rangemiddle)>button]:!text-white '
105
+ + '[&:not(.rangemiddle)>button]:!bg-primary-dark '
106
+ + '[&:not(.rangemiddle)>button]:!border-primary-dark ',
107
+ },
108
+ }
109
+
110
+ return (
111
+ <div>
112
+ {
113
+ mode === 'single' ? (
114
+ <DayPicker mode="single" selected={dates[0]} {...common} className={className} />
115
+ ) : mode === 'range' ? (
116
+ <DayPicker mode="range" selected={{ from: dates[0], to: dates[1] }} {...common} className={className} />
117
+ ) : (
118
+ <DayPicker mode="multiple" selected={dates.filter((d) => !!d)} {...common} className={className} />
119
+ )
120
+ }
121
+ </div>
122
+ )
123
+ }
@@ -104,7 +104,7 @@ export const Dropdown = forwardRef(function Dropdown({
104
104
  return cloneElement(el, { key, onMouseDown, onKeyDown }) // adds onClick
105
105
  })
106
106
  }
107
- <ul
107
+ <ul
108
108
  style={{ minWidth }}
109
109
  class={`${menuStyle} absolute invisible opacity-0 select-none min-w-full z-[1]`}
110
110
  >
@@ -132,7 +132,9 @@ export const Dropdown = forwardRef(function Dropdown({
132
132
 
133
133
  const style = css`
134
134
  ul {
135
- transition: transform 0.15s ease, opacity 0.15s ease, visibility 0s 0.15s ease;
135
+ transition: transform 0.15s ease, opacity 0.15s ease, visibility 0s 0.15s ease, max-width 0s 0.15s ease, max-height 0s 0.15s ease;
136
+ max-width: 0; // handy if the dropdown ul exceeds the viewport width
137
+ max-height: 0; // handy if the dropdown ul exceeds the viewport height
136
138
  }
137
139
  &.is-bottom-right,
138
140
  &.is-top-right {
@@ -166,6 +168,8 @@ const style = css`
166
168
  opacity: 1;
167
169
  visibility: visible;
168
170
  transition: transform 0.15s ease, opacity 0.15s ease;
171
+ max-width: 1000px;
172
+ max-height: 1000px;
169
173
  }
170
174
  &.is-bottom-left > ul,
171
175
  &.is-bottom-right > ul {
@@ -1,111 +1,84 @@
1
- // @ts-nocheck
2
- // todo: finish tailwind conversion
3
- import { css } from 'twin.macro'
4
1
  import { IsFirstRender } from 'nitro-web'
5
2
  import SvgX1 from 'nitro-web/client/imgs/icons/x1.svg'
6
3
 
7
- export function Modal({ show, setShow, children, className, maxWidth, minHeight, dismissable = true }) {
8
- const [state, setState] = useState()
9
- const containerEl = useRef()
4
+ type ModalProps = {
5
+ show: boolean
6
+ setShow: (show: boolean) => void
7
+ children: React.ReactNode
8
+ maxWidth?: string
9
+ minHeight?: string
10
+ dismissable?: boolean
11
+ [key: string]: unknown
12
+ }
13
+
14
+ export function Modal({ show, setShow, children, maxWidth, minHeight, dismissable = true, ...props }: ModalProps) {
15
+ const [state, setState] = useState(show ? 'open' : 'close')
16
+ const containerEl = useRef<HTMLDivElement>(null)
10
17
  const isFirst = IsFirstRender()
11
18
 
12
- useEffect(() => {
13
- createScrollbarClasses()
14
- return () => {
15
- elementWithScrollbar().classList.remove('scrollbarPadding')
16
- } // cleanup
17
- }, [])
19
+ const states = {
20
+ 'close': {
21
+ root: 'left-[-100vw] transition-[left] duration-0 delay-200',
22
+ bg: 'opacity-0',
23
+ container: 'opacity-0 scale-[0.97]',
24
+ },
25
+ 'close-now': {
26
+ root: '',
27
+ bg: '',
28
+ container: 'opacity-0 !transition-none',
29
+ },
30
+ 'open': {
31
+ root: 'left-0 transition-none model-open',
32
+ bg: 'opacity-100 duration-200',
33
+ container: 'opacity-100 scale-[1] duration-200',
34
+ },
35
+ }
36
+ const _state = states[state as keyof typeof states]
37
+
18
38
 
19
39
  useEffect(() => {
40
+ if (isFirst) return
20
41
  if (show) {
21
- elementWithScrollbar().classList.add('scrollbarPadding')
22
- setState('modal-open')
23
- } else if (!isFirst) {
24
- // Dont close if first render (forgot what use case this was needed for)
42
+ setState('open')
43
+ } else {
25
44
  setTimeout(() => {
26
45
  // If another modal is being opened, force close the container for a smoother transition
27
46
  if (document.getElementsByClassName('modal-open').length > 1) {
28
- setState('modal-close-immediately')
47
+ setState('close-now')
29
48
  } else {
30
- setState('')
31
- elementWithScrollbar().classList.remove('scrollbarPadding')
49
+ setState('close')
32
50
  }
33
51
  }, 10)
34
52
  }
35
53
  // There is a bug during hot-reloading where the modal does't open if we don't ensure
36
54
  // the same truthy/falsey type is used.
37
55
  }, [!!show])
38
-
39
- function elementWithScrollbar() {
40
- // this needs to be non-body element otherwise the Modal.jsx doesn't open/close smoothly
41
- //document.getElementsByTagName('body')[0] // document.getElementsByClassName('page')[0]
42
- return document.getElementById('app')
43
- }
44
56
 
45
- function onClick(e) {
46
- let clickedOnContainer = containerEl.current && containerEl.current.contains(e.target)
47
- if (!clickedOnContainer && dismissable) {
57
+ function onClick(e: React.MouseEvent) {
58
+ const clickedOnModal = containerEl.current && containerEl.current.contains(e.target as Node)
59
+ if (!clickedOnModal && dismissable) {
48
60
  setShow(false)
49
61
  }
50
62
  }
51
63
 
52
- function createScrollbarClasses() {
53
- /**
54
- * Creates reusable margin and padding classes containing the scrollbar width and
55
- * sets window.scrollbarWidth
56
- * @return width
57
- */
58
- if (typeof window.scrollbarWidth !== 'undefined') return
59
-
60
- var outer = document.createElement('div')
61
- outer.style.visibility = 'hidden'
62
- outer.style.width = '100px'
63
- outer.style.margin = '0px'
64
- outer.style.padding = '0px'
65
- outer.style.border = '0'
66
- document.body.appendChild(outer)
67
-
68
- var widthNoScroll = outer.offsetWidth
69
- // force scrollbars
70
- outer.style.overflow = 'scroll'
71
-
72
- // add innerdiv
73
- var inner = document.createElement('div')
74
- inner.style.width = '100%'
75
- outer.appendChild(inner)
76
-
77
- var widthWithScroll = inner.offsetWidth
78
-
79
- // Remove divs
80
- outer.parentNode.removeChild(outer)
81
- let width = (window.scrollbarWidth = widthNoScroll - widthWithScroll)
82
-
83
- // Create new inline stylesheet and append to the head
84
- let style = document.createElement('style')
85
- let css = (
86
- '.scrollbarPadding {padding-right:' + width + 'px !important; overflow:hidden !important;}' +
87
- '.scrollbarMargin {margin-right:' + width + 'px !important; overflow:hidden !important;}'
88
- )
89
- style.type = 'text/css'
90
- if (style.styleSheet) style.styleSheet.cssText = css //<=IE8
91
- else style.appendChild(document.createTextNode(css))
92
- document.getElementsByTagName('head')[0].appendChild(style)
93
-
94
- return width
95
- }
96
-
97
64
  return (
98
- <div css={style} class={`${state}`} onClick={(e) => e.stopPropagation()}>
99
- <div class="modal-bg wrapper scrollbarPadding"></div>
100
- <div class="modal-container">
101
- {/* we also need to be able to scroll without closing */}
102
- <div onMouseDown={onClick}>
65
+ <div
66
+ onClick={(e) => e.stopPropagation()}
67
+ class={`fixed top-0 w-[100vw] h-[100vh] z-[700] ${_state.root}`}
68
+ >
69
+ <div class={`!absolute inset-0 box-content bg-gray-500/70 transition-opacity ${_state.bg}`}></div>
70
+ <div class={`relative h-[100vh] overflow-y-auto transition-[opacity,transform] ${_state.container}`}>
71
+ <div class="flex items-center justify-center min-h-full" onMouseDown={onClick}>
103
72
  <div
104
73
  ref={containerEl}
105
- style={{ maxWidth: maxWidth || '740px', minHeight: typeof minHeight == 'undefined' ? '487px' : minHeight }}
106
- class={`modal1 ${className}`}
74
+ style={{ maxWidth: maxWidth || '550px', minHeight: minHeight }}
75
+ class={`relative w-full mx-6 mt-4 mb-8 bg-white rounded-lg shadow-lg ${props.className}`}
107
76
  >
108
- <div class="modal-close" onClick={() => { if (dismissable) { setShow(false) }}}><SvgX1 /></div>
77
+ <div
78
+ class="absolute top-0 right-0 p-3 m-1 cursor-pointer"
79
+ onClick={() => { if (dismissable) { setShow(false) }}}>
80
+ <SvgX1 />
81
+ </div>
109
82
  {children}
110
83
  </div>
111
84
  </div>
@@ -113,118 +86,3 @@ export function Modal({ show, setShow, children, className, maxWidth, minHeight,
113
86
  </div>
114
87
  )
115
88
  }
116
-
117
- const style = css`
118
- /* Modal structure */
119
- & {
120
- position: fixed;
121
- top: 0;
122
- width: 100%;
123
- height: calc(100vh);
124
- z-index: 699;
125
- .modal-bg {
126
- position: absolute !important;
127
- display: flex;
128
- top: 0;
129
- left: 0;
130
- right: 0;
131
- bottom: 0;
132
- box-sizing: content-box;
133
- &:before {
134
- content: '';
135
- display: block;
136
- flex: 1;
137
- background: rgba(255, 255, 255, 0.82);
138
- /* backdrop-filter: blur(1px);
139
- -webkit-backdrop-filter: blur(1px); */
140
- }
141
- }
142
- .modal-container {
143
- position: relative;
144
- height: calc(100vh);
145
- // horisontal centering
146
- > div {
147
- display: flex;
148
- align-items: center;
149
- justify-content: center;
150
- min-height: 100%;
151
- // vertical centering
152
- > div {
153
- margin: 30px 20px 90px;
154
- width: 100%;
155
- }
156
- }
157
- }
158
- &.modal-close-immediately {
159
- .modal-container > div > div {
160
- transition: none !important;
161
- }
162
- }
163
- }
164
-
165
- /* Animation */
166
-
167
- & {
168
- left: -100%;
169
- transition: left 0s 0.2s;
170
- }
171
- .modal-bg {
172
- opacity: 0;
173
- transition: opacity 0.15s ease, transform 0.15s ease;
174
- }
175
- .modal-container {
176
- /*overflow: hidden;*/
177
- overflow-y: scroll;
178
- overflow-x: auto;
179
- }
180
- .modal-container > div > div {
181
- opacity: 0;
182
- transform: scale(0.97);
183
- transition: opacity 0.15s ease, transform 0.15s ease;
184
- }
185
- &.modal-open {
186
- left: 0;
187
- transition: none;
188
- .modal-bg {
189
- opacity: 1;
190
- transition: opacity 0.2s ease, transform 0.2s ease;
191
- }
192
- .modal-container {
193
- overflow-y: scroll;
194
- overflow-x: auto;
195
- }
196
- .modal-container > div > div {
197
- opacity: 1;
198
- transform: scale(1);
199
- transition: opacity 0.2s ease, transform 0.2s ease;
200
- }
201
- }
202
-
203
- /* Modal customisations */
204
-
205
- .modal1 {
206
- background: white;
207
- border: 2px solid #27242C;
208
- box-shadow: 0px 1px 29px rgba(31, 29, 36, 0.07);
209
- border-radius: 8px;
210
- .subtitle {
211
- margin-bottom: 34px; // same as form pages
212
- }
213
- .modal-close {
214
- position: absolute;
215
- margin: 10px;
216
- padding: 15px 20px;
217
- top: 0;
218
- right: 0;
219
- cursor: pointer;
220
- line {
221
- transition: all 0.1s;
222
- }
223
- &:hover {
224
- line {
225
- /* stroke: theme'colors.primary-dark'; */
226
- }
227
- }
228
- }
229
- }
230
- `