commit
248473cacc
@ -0,0 +1,4 @@ |
||||
{ |
||||
"presets": ["@nrwl/react/babel"], |
||||
"plugins": [] |
||||
} |
@ -0,0 +1,18 @@ |
||||
{ |
||||
"env": { |
||||
"browser": true, |
||||
"es6": true |
||||
}, |
||||
"extends": "../../../.eslintrc", |
||||
"globals": { |
||||
"Atomics": "readonly", |
||||
"SharedArrayBuffer": "readonly" |
||||
}, |
||||
"parserOptions": { |
||||
"ecmaVersion": 11, |
||||
"sourceType": "module" |
||||
}, |
||||
"rules": { |
||||
"standard/no-callback-literal": "off" |
||||
} |
||||
} |
@ -0,0 +1,7 @@ |
||||
# remix-ui-modal-dialog |
||||
|
||||
This library was generated with [Nx](https://nx.dev). |
||||
|
||||
## Running unit tests |
||||
|
||||
Run `nx test remix-ui-modal-dialog` to execute the unit tests via [Jest](https://jestjs.io). |
@ -0,0 +1,14 @@ |
||||
{ |
||||
"presets": [ |
||||
[ |
||||
"@babel/preset-env", |
||||
{ |
||||
"targets": { |
||||
"node": "current" |
||||
} |
||||
} |
||||
], |
||||
"@babel/preset-typescript", |
||||
"@babel/preset-react" |
||||
] |
||||
} |
@ -0,0 +1,12 @@ |
||||
module.exports = { |
||||
name: 'remix-ui-modal-dialog', |
||||
preset: '../../../jest.config.js', |
||||
transform: { |
||||
'^.+\\.[tj]sx?$': [ |
||||
'babel-jest', |
||||
{ cwd: __dirname, configFile: './babel-jest.config.json' } |
||||
] |
||||
}, |
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], |
||||
coverageDirectory: '../../../coverage/libs/remix-ui/modal-dialog' |
||||
} |
@ -0,0 +1,2 @@ |
||||
export * from './lib/modal-dialog-custom' |
||||
export * from './lib/remix-ui-modal-dialog' |
@ -0,0 +1,16 @@ |
||||
import React from 'react' // eslint-disable-line
|
||||
|
||||
import './modal-dialog-custom.css' |
||||
|
||||
/* eslint-disable-next-line */ |
||||
export interface ModalDialogCustomProps {} |
||||
|
||||
export const ModalDialogCustom = (props: ModalDialogCustomProps) => { |
||||
return ( |
||||
<div> |
||||
<h1>Welcome to modal-dialog-custom!</h1> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default ModalDialogCustom |
@ -0,0 +1,19 @@ |
||||
.remixModalContent { |
||||
box-shadow: 0 0 8px 1000px rgba(0,0,0,0.6),0 6px 20px 0 rgba(0,0,0,0.19); |
||||
-webkit-animation-name: animatetop; |
||||
-webkit-animation-duration: 0.4s; |
||||
animation-name: animatetop; |
||||
animation-duration: 0.4s |
||||
} |
||||
.remixModalBody { |
||||
overflow-y: auto; |
||||
max-height: 600px; |
||||
} |
||||
@-webkit-keyframes animatetop { |
||||
from {top: -300px; opacity: 0} |
||||
to {top: 0; opacity: 1} |
||||
} |
||||
@keyframes animatetop { |
||||
from {top: -300px; opacity: 0} |
||||
to {top: 0; opacity: 1} |
||||
} |
@ -0,0 +1,114 @@ |
||||
import React, { useRef, useState, useEffect } from 'react' // eslint-disable-line
|
||||
import { ModalDialogProps } from './types' // eslint-disable-line
|
||||
|
||||
import './remix-ui-modal-dialog.css' |
||||
|
||||
export const ModalDialog = (props: ModalDialogProps) => { |
||||
const [state, setState] = useState({ |
||||
toggleBtn: true |
||||
}) |
||||
const modal = useRef(null) |
||||
const handleHide = () => { |
||||
props.hide() |
||||
} |
||||
|
||||
useEffect( |
||||
() => { |
||||
modal.current.focus() |
||||
}, [] |
||||
) |
||||
|
||||
const modalKeyEvent = (keyCode) => { |
||||
if (keyCode === 27) { // Esc
|
||||
if (props.cancel && props.cancel.fn) props.cancel.fn() |
||||
handleHide() |
||||
} else if (keyCode === 13) { // Enter
|
||||
enterHandler() |
||||
} else if (keyCode === 37) { |
||||
// todo && footerIsActive) { // Arrow Left
|
||||
setState((prevState) => { return { ...prevState, toggleBtn: true } }) |
||||
} else if (keyCode === 39) { |
||||
// todo && footerIsActive) { // Arrow Right
|
||||
setState((prevState) => { return { ...prevState, toggleBtn: false } }) |
||||
} |
||||
} |
||||
|
||||
const enterHandler = () => { |
||||
if (state.toggleBtn) { |
||||
if (props.ok && props.ok.fn) props.ok.fn() |
||||
} else { |
||||
if (props.cancel && props.cancel.fn) props.cancel.fn() |
||||
} |
||||
handleHide() |
||||
} |
||||
return (<> |
||||
<div |
||||
id="modal-dialog" |
||||
data-id="modalDialogContainer" |
||||
data-backdrop="static" |
||||
data-keyboard="false" |
||||
tabIndex={-1} |
||||
className="modal d-block" |
||||
role="dialog" |
||||
> |
||||
<div id="modal-background" className="modal-dialog" role="document"> |
||||
<div |
||||
tabIndex={1} |
||||
onBlur={(e) => { |
||||
e.stopPropagation() |
||||
handleHide() |
||||
}} |
||||
ref={modal} |
||||
className={'modal-content remixModalContent ' + (props.opts ? props.opts.class ? props.opts.class : '' : '')} |
||||
onKeyDown={({ keyCode }) => { modalKeyEvent(keyCode) }} |
||||
> |
||||
<div className="modal-header"> |
||||
<h6 className="modal-title" data-id="modalDialogModalTitle"> |
||||
{props.title && props.title} |
||||
</h6> |
||||
{!props.opts.hideClose && |
||||
<span className="modal-close" onClick={() => handleHide()}> |
||||
<i id="modal-close" title="Close" className="fas fa-times" aria-hidden="true"></i> |
||||
</span> |
||||
} |
||||
</div> |
||||
<div className="modal-body text-break remixModalBody" data-id="modalDialogModalBody"> |
||||
{props.content && |
||||
props.content |
||||
} |
||||
</div> |
||||
<div className="modal-footer" data-id="modalDialogModalFooter"> |
||||
{/* todo add autofocus ^^ */} |
||||
{props.ok && |
||||
<span |
||||
id="modal-footer-ok" |
||||
className={'modal-ok btn btn-sm ' + (state.toggleBtn ? 'btn-dark' : 'btn-light')} |
||||
onClick={() => { |
||||
if (props.ok && props.ok.fn) props.ok.fn() |
||||
handleHide() |
||||
}} |
||||
tabIndex={1} |
||||
> |
||||
{props.ok && props.ok.label ? props.ok.label : 'OK'} |
||||
</span> |
||||
} |
||||
<span |
||||
id="modal-footer-cancel" |
||||
className={'modal-cancel btn btn-sm ' + (state.toggleBtn ? 'btn-light' : 'btn-dark')} |
||||
data-dismiss="modal" |
||||
onClick={() => { |
||||
if (props.cancel && props.cancel.fn) props.cancel.fn() |
||||
handleHide() |
||||
}} |
||||
tabIndex={2} |
||||
> |
||||
{props.cancel && props.cancel.label ? props.cancel.label : 'Cancel'} |
||||
</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</>) |
||||
} |
||||
|
||||
export default ModalDialog |
@ -0,0 +1,9 @@ |
||||
export interface ModalDialogProps { |
||||
title?: string, |
||||
content?: JSX.Element, |
||||
ok?: {label:string, fn: () => void}, |
||||
cancel?: {label:string, fn: () => void}, |
||||
focusSelector?: string, |
||||
opts?: {class: string, hideClose?: boolean}, |
||||
hide: () => void |
||||
} |
@ -0,0 +1,19 @@ |
||||
{ |
||||
"extends": "../../../tsconfig.json", |
||||
"compilerOptions": { |
||||
"jsx": "react", |
||||
"allowJs": true, |
||||
"esModuleInterop": true, |
||||
"allowSyntheticDefaultImports": true |
||||
}, |
||||
"files": [], |
||||
"include": [], |
||||
"references": [ |
||||
{ |
||||
"path": "./tsconfig.lib.json" |
||||
}, |
||||
{ |
||||
"path": "./tsconfig.spec.json" |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,13 @@ |
||||
{ |
||||
"extends": "./tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "../../../dist/out-tsc", |
||||
"types": ["node"] |
||||
}, |
||||
"files": [ |
||||
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", |
||||
"../../../node_modules/@nrwl/react/typings/image.d.ts" |
||||
], |
||||
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"], |
||||
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] |
||||
} |
@ -0,0 +1,15 @@ |
||||
{ |
||||
"extends": "./tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "../../../dist/out-tsc", |
||||
"module": "commonjs", |
||||
"types": ["jest", "node"] |
||||
}, |
||||
"include": [ |
||||
"**/*.spec.ts", |
||||
"**/*.spec.tsx", |
||||
"**/*.spec.js", |
||||
"**/*.spec.jsx", |
||||
"**/*.d.ts" |
||||
] |
||||
} |
Loading…
Reference in new issue