diff --git a/src/widgets/index.js b/src/widgets/index.js index aed84309c..4ccd6fc88 100644 --- a/src/widgets/index.js +++ b/src/widgets/index.js @@ -26,7 +26,8 @@ const widgets = Object.assign( require('./dragAndDrop'), // uploadFiles etc require('./error'), // UI.widgets.errorMessageBlock require('./buttons'), - require('./forms') + require('./forms'), + require('./modals') ) module.exports = widgets diff --git a/src/widgets/modals.ts b/src/widgets/modals.ts new file mode 100644 index 000000000..515db3e9b --- /dev/null +++ b/src/widgets/modals.ts @@ -0,0 +1,95 @@ +import { + ModalWidgetStyleOptions, + modalStyles, + getModalStyle, + getModalContentStyle, + getModalCloseStyle +} from './modalsStyle' +import { getClasses } from '../jss' + +export type ListItem = { + label: string, + link: string +} + +// Two functions that need to be implemented to use the modal +// When the user clicks the button, open the modal +/* Click handler on the button to display it. +btn.onclick = function() { + modal.style.display = "block"; +} + +// When the user clicks anywhere outside of the modal, close it +Window click handler so that the modal will close +even if the user doesn't click close +window.onclick = function(event) { + if (event.target == modal) { + modal.style.display = "none"; + } */ +const closeClickHandler = () => { + const modal: HTMLDivElement | null = document.querySelector('.modal') + if (modal) { + modal.style.display = 'none' + } +} + +const createModal = (dom: HTMLDocument, options: ModalWidgetStyleOptions) => { + const modal = dom.createElement('div') + const style = getModalStyle(options) + const { classes } = getClasses(dom.head, { + modal: style + }) + modal.classList.add(classes.modal) + return modal +} + +const createModalContent = (dom: HTMLDocument) => { + const modalContent: HTMLDivElement = dom.createElement('div') + const style = getModalContentStyle() + const { classes } = getClasses(dom.head, { + modalContent: style + }) + modalContent.classList.add(classes.modalContent) + return modalContent +} + +const createCloseButton = (dom: HTMLDocument) => { + const closeButton: HTMLSpanElement = dom.createElement('span') + closeButton.addEventListener('click', closeClickHandler) + const style = getModalCloseStyle() + const { classes } = getClasses(dom.head, { + close: style + }) + closeButton.classList.add(classes.close) + return closeButton +} + +const createListItems = (dom: HTMLDocument, list: ListItem) => { + const li:HTMLLIElement = dom.createElement('li') + li.setAttribute('style', modalStyles.listItemStyle) + const link: HTMLAnchorElement = dom.createElement('a') + link.setAttribute('style', modalStyles.anchorStyle) + link.href = list.link + link.innerHTML = list.label + li.appendChild(link) + return li +} + +const createUnOrderedList = (dom: HTMLDocument, listOfLinks: ListItem[]) => { + const ul: HTMLUListElement = dom.createElement('ul') + ul.setAttribute('style', modalStyles.unorderedListStyle) + listOfLinks.forEach(list => { + const li = createListItems(dom, list) + ul.appendChild(li) + }) + return ul +} +export const createWindow = (dom: HTMLDocument, listOfLinks: ListItem[], options: ModalWidgetStyleOptions) => { + const modal = createModal(dom, options) + const modalContent = createModalContent(dom) + const closeButton = createCloseButton(dom) + const ul = createUnOrderedList(dom, listOfLinks) + modalContent.appendChild(closeButton) + modalContent.appendChild(ul) + modal.appendChild(modalContent) +} diff --git a/src/widgets/modalsStyle.ts b/src/widgets/modalsStyle.ts new file mode 100644 index 000000000..3766c1714 --- /dev/null +++ b/src/widgets/modalsStyle.ts @@ -0,0 +1,72 @@ +/** + * Get the button style, based on options. + * See https://design.inrupt.com/atomic-core/?cat=Atoms#Buttons + */ +export type ModalWidgetStyleOptions = { + topPosition?: string, + leftPosition?: string, + withGreyedBackground?: boolean +} + +export const modalStyles = { + unorderedListStyle: 'padding: 0 .2em;', + listItemStyle: 'list-style: none; box-shadow: 1px 1px 1px 1px #888888; padding: .5em', + anchorStyle: 'text-decoration: none' +} + +export const getModalStyle = (options: ModalWidgetStyleOptions = {}) => { + const topPosition = (options.topPosition) ? options.topPosition : '50px' + const leftPosition = (options.leftPosition) ? options.leftPosition : '50px' + + if (options.withGreyedBackground) { + return { + display: 'none', + position: 'fixed', + 'z-index': '1', + overflow: 'auto', /* Enable scroll if needed */ + 'background-color': 'rgba(0,0,0,0.4)', /* Black w/ opacity */ + 'padding-top': '100px', + left: '0', + top: '0', + width: '100%', + height: '100%' + } + } + + return { + display: 'none', + position: 'fixed', + 'z-index': '1', + top: `${topPosition}`, + left: `${leftPosition}`, + overflow: 'auto', /* Enable scroll if needed */ + 'background-color': 'rgba(0,0,0,0.4)' /* Black w/ opacity */ + } +} + +export const getModalContentStyle = () => { + return { + display: 'flex', + 'flex-direction': 'column', + 'background-color': '#fefefe' + } +} + +export const getModalCloseStyle = () => { + return { + color: '#aaaaaa', + 'align-self': 'flex-end', + 'font-size': '20px', + 'font-weight': 'bold', + 'margin-right': '.2em', + 'margin-top': '.2em', + '&:hover': { + 'text-decoration': 'none', + cursor: 'pointer' + }, + '&:focus': { + 'text-decoration': 'none', + cursor: 'pointer' + } + } +}