Initial commit
This commit is contained in:
		
						commit
						ccaadf06ca
					
				
							
								
								
									
										11
									
								
								.eslintrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.eslintrc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "extends": ["eslint:recommended"], | ||||||
|  |   "parserOptions": { | ||||||
|  |     "sourceType": "module", | ||||||
|  |     "ecmaVersion": 2019 | ||||||
|  |   }, | ||||||
|  |   "env": { | ||||||
|  |     "browser": true, | ||||||
|  |     "jest": true | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | node_modules/ | ||||||
|  | coverage/ | ||||||
							
								
								
									
										4
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | { | ||||||
|  |   "semi": false, | ||||||
|  |   "singleQuote": true | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								babel.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								babel.config.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | module.exports = { | ||||||
|  |   presets: ['@babel/preset-env'], | ||||||
|  | } | ||||||
							
								
								
									
										101
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | |||||||
|  | <html lang="en"> | ||||||
|  |   <head> | ||||||
|  |     <meta charset="UTF-8" /> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||||
|  |     <title>Context Menu demo</title> | ||||||
|  |     <link rel="stylesheet" href="style.css" /> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  |     <main> | ||||||
|  |       <h1>Context Menu Demo</h1> | ||||||
|  |       <div id="container"> | ||||||
|  |         <div id="parent"> | ||||||
|  |           <div id="context"></div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  | 
 | ||||||
|  |       <div id="options"> | ||||||
|  |         <h2>Explanation</h2> | ||||||
|  |         <p>Drag the blue box to see how the red box will be aligned.</p> | ||||||
|  |         <h2>Options</h2> | ||||||
|  |         <h3>Alignments</h3> | ||||||
|  |         <form> | ||||||
|  |           <label | ||||||
|  |             ><span>parentH</span> | ||||||
|  |             <select id="parentH"> | ||||||
|  |               <option>left</option> | ||||||
|  |               <option>right</option> | ||||||
|  |             </select></label | ||||||
|  |           > | ||||||
|  |           <label | ||||||
|  |             ><span>parentV</span> | ||||||
|  |             <select id="parentV"> | ||||||
|  |               <option>bottom</option> | ||||||
|  |               <option>top</option> | ||||||
|  |             </select></label | ||||||
|  |           > | ||||||
|  |           <label | ||||||
|  |             ><span>childH</span> | ||||||
|  |             <select id="childH"> | ||||||
|  |               <option>left</option> | ||||||
|  |               <option>right</option> | ||||||
|  |             </select></label | ||||||
|  |           > | ||||||
|  |           <label | ||||||
|  |             ><span>childV</span> | ||||||
|  |             <select id="childV"> | ||||||
|  |               <option>top</option> | ||||||
|  |               <option>bottom</option> | ||||||
|  |             </select></label | ||||||
|  |           > | ||||||
|  |           <h3>Box sizes</h3> | ||||||
|  |           <label | ||||||
|  |             ><span>parentWidth</span> | ||||||
|  |             <input | ||||||
|  |               id="parentWidth" | ||||||
|  |               type="range" | ||||||
|  |               min="100" | ||||||
|  |               max="500" | ||||||
|  |               value="300" /></label | ||||||
|  |           ><label | ||||||
|  |             ><span>parentHeight</span> | ||||||
|  |             <input | ||||||
|  |               id="parentHeight" | ||||||
|  |               type="range" | ||||||
|  |               min="100" | ||||||
|  |               max="500" | ||||||
|  |               value="300" /></label | ||||||
|  |           ><label | ||||||
|  |             ><span>contextWidth</span> | ||||||
|  |             <input | ||||||
|  |               id="contextWidth" | ||||||
|  |               type="range" | ||||||
|  |               min="100" | ||||||
|  |               max="500" | ||||||
|  |               value="100" /></label | ||||||
|  |           ><label | ||||||
|  |             ><span>contextHeight</span> | ||||||
|  |             <input | ||||||
|  |               id="contextHeight" | ||||||
|  |               type="range" | ||||||
|  |               min="100" | ||||||
|  |               max="500" | ||||||
|  |               value="100" | ||||||
|  |           /></label> | ||||||
|  |           <h3>Containment</h3> | ||||||
|  |           <label | ||||||
|  |             ><span>InvertH</span><input id="invertH" type="checkbox" checked | ||||||
|  |           /></label> | ||||||
|  |           <label | ||||||
|  |             ><span>InvertV</span><input id="invertV" type="checkbox" checked | ||||||
|  |           /></label> | ||||||
|  |           <label | ||||||
|  |             ><span>Contain into</span | ||||||
|  |             ><input id="containInto" type="checkbox" checked | ||||||
|  |           /></label> | ||||||
|  |         </form> | ||||||
|  |       </div> | ||||||
|  |     </main> | ||||||
|  |     <script type="module" src="src/index.js"></script> | ||||||
|  |   </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										7104
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7104
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										20
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | { | ||||||
|  |   "name": "html-context-menu", | ||||||
|  |   "version": "0.1.0", | ||||||
|  |   "description": "", | ||||||
|  |   "main": "index.js", | ||||||
|  |   "scripts": { | ||||||
|  |     "test": "jest --coverage", | ||||||
|  |     "test-watch": "jest --watch --coverage", | ||||||
|  |     "lint": "eslint ./**/*.js" | ||||||
|  |   }, | ||||||
|  |   "author": "Alfred Melch <dev@melch.pro>", | ||||||
|  |   "license": "ISC", | ||||||
|  |   "devDependencies": { | ||||||
|  |     "@babel/preset-env": "^7.9.5", | ||||||
|  |     "eslint": "^6.8.0", | ||||||
|  |     "jest": "^25.3.0", | ||||||
|  |     "prettier": "^2.0.4", | ||||||
|  |     "rewire": "^5.0.0" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								src/context.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/context.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | |||||||
|  | export function calculatePosition(parentRect, childRect, alignments) { | ||||||
|  |   const { parentH, parentV, childH, childV } = alignments | ||||||
|  |   const baseLeft = parentRect[parentH] | ||||||
|  |   const baseTop = parentRect[parentV] | ||||||
|  |   const left = childH === 'left' ? baseLeft : baseLeft - childRect.width | ||||||
|  |   const top = childV === 'top' ? baseTop : baseTop - childRect.height | ||||||
|  | 
 | ||||||
|  |   return updateRect(childRect, { left, top }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function alignChild(parent, child, container, alignments, containment) { | ||||||
|  |   const parentRect = parent.getBoundingClientRect() | ||||||
|  |   let childRect = child.getBoundingClientRect() | ||||||
|  |   const containerRect = container.getBoundingClientRect() | ||||||
|  | 
 | ||||||
|  |   childRect = calculatePosition(parentRect, childRect, alignments) | ||||||
|  |   const overflows = getOverflows(containerRect, childRect) | ||||||
|  |   if (containment.invertH && overflows.h) { | ||||||
|  |     alignments = invertH(alignments) | ||||||
|  |   } | ||||||
|  |   if (containment.inoverV && overflows.v) { | ||||||
|  |     alignments = invertV(alignments) | ||||||
|  |   } | ||||||
|  |   childRect = calculatePosition(parentRect, childRect, alignments) | ||||||
|  | 
 | ||||||
|  |   if (containment.containInto) { | ||||||
|  |     childRect = containInto(containerRect, childRect) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   child.style.top = childRect.top | ||||||
|  |   child.style.left = childRect.left | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const alignMapping = { | ||||||
|  |   top: 'bottom', | ||||||
|  |   bottom: 'top', | ||||||
|  |   left: 'right', | ||||||
|  |   right: 'left', | ||||||
|  | } | ||||||
|  | function invertH(alignments) { | ||||||
|  |   const parentH = alignMapping[alignments.parentH] | ||||||
|  |   const childH = alignMapping[alignments.childH] | ||||||
|  |   return { ...alignments, parentH, childH } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function invertV(alignments) { | ||||||
|  |   const parentV = alignMapping[alignments.parentV] | ||||||
|  |   const childV = alignMapping[alignments.childV] | ||||||
|  |   return { ...alignments, parentV, childV } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Sets new top and left property of a rectangle | ||||||
|  |  * @param {Object} rect | ||||||
|  |  * @param {Object} updates | ||||||
|  |  */ | ||||||
|  | export function updateRect(rect, { left, top }) { | ||||||
|  |   const { width, height } = rect | ||||||
|  |   top = top || rect.top | ||||||
|  |   left = left || rect.left | ||||||
|  |   const right = left + width | ||||||
|  |   const bottom = top + height | ||||||
|  |   return { top, bottom, left, right, width, height } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function getOverflows(parentRect, childRect) { | ||||||
|  |   const top = childRect.top < parentRect.top | ||||||
|  |   const bottom = childRect.bottom > parentRect.bottom | ||||||
|  |   const left = childRect.left < parentRect.left | ||||||
|  |   const right = childRect.right > parentRect.right | ||||||
|  |   const h = left || right | ||||||
|  |   const v = top || bottom | ||||||
|  |   const any = h || v | ||||||
|  |   return { top, bottom, left, right, h, v, any } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function containInto(parent, child) { | ||||||
|  |   let top = child.top | ||||||
|  |   top = Math.min(top, parent.bottom - child.height) | ||||||
|  |   top = Math.max(top, parent.top) | ||||||
|  | 
 | ||||||
|  |   let left = child.left | ||||||
|  |   left = Math.min(left, parent.right - child.width) | ||||||
|  |   left = Math.max(left, parent.left) | ||||||
|  | 
 | ||||||
|  |   return updateRect(child, { top, left }) | ||||||
|  | } | ||||||
							
								
								
									
										106
									
								
								src/context.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/context.spec.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,106 @@ | |||||||
|  | import { calculatePosition, updateRect, getOverflows } from './context' | ||||||
|  | 
 | ||||||
|  | // const {updateRect} = _private
 | ||||||
|  | 
 | ||||||
|  | describe('calculatePosition', () => { | ||||||
|  |   it.each` | ||||||
|  |     parentH    | parentV     | childH     | childV      | expLeft | expTop | ||||||
|  |     ${'left'}  | ${'top'}    | ${'left'}  | ${'top'}    | ${40}   | ${40} | ||||||
|  |     ${'left'}  | ${'top'}    | ${'left'}  | ${'bottom'} | ${40}   | ${35} | ||||||
|  |     ${'left'}  | ${'top'}    | ${'right'} | ${'top'}    | ${35}   | ${40} | ||||||
|  |     ${'left'}  | ${'top'}    | ${'right'} | ${'bottom'} | ${35}   | ${35} | ||||||
|  |     ${'left'}  | ${'bottom'} | ${'left'}  | ${'top'}    | ${40}   | ${60} | ||||||
|  |     ${'left'}  | ${'bottom'} | ${'left'}  | ${'bottom'} | ${40}   | ${55} | ||||||
|  |     ${'left'}  | ${'bottom'} | ${'right'} | ${'top'}    | ${35}   | ${60} | ||||||
|  |     ${'left'}  | ${'bottom'} | ${'right'} | ${'bottom'} | ${35}   | ${55} | ||||||
|  |     ${'right'} | ${'top'}    | ${'left'}  | ${'top'}    | ${60}   | ${40} | ||||||
|  |     ${'right'} | ${'top'}    | ${'left'}  | ${'bottom'} | ${60}   | ${35} | ||||||
|  |     ${'right'} | ${'top'}    | ${'right'} | ${'top'}    | ${55}   | ${40} | ||||||
|  |     ${'right'} | ${'top'}    | ${'right'} | ${'bottom'} | ${55}   | ${35} | ||||||
|  |     ${'right'} | ${'bottom'} | ${'left'}  | ${'top'}    | ${60}   | ${60} | ||||||
|  |     ${'right'} | ${'bottom'} | ${'left'}  | ${'bottom'} | ${60}   | ${55} | ||||||
|  |     ${'right'} | ${'bottom'} | ${'right'} | ${'top'}    | ${55}   | ${60} | ||||||
|  |     ${'right'} | ${'bottom'} | ${'right'} | ${'bottom'} | ${55}   | ${55} | ||||||
|  |   `('works with $parentH $parentV $childH $childV', (params) => {
 | ||||||
|  |     const { expLeft, expTop, ...alignments } = params | ||||||
|  |     const parent = makeRect(40, 40, 60, 60) | ||||||
|  |     const child = makeRect(0, 0, 5, 5) | ||||||
|  |     const newPosition = calculatePosition(parent, child, alignments) | ||||||
|  | 
 | ||||||
|  |     const expectedRect = makeRect(expTop, expLeft, expTop + 5, expLeft + 5) | ||||||
|  |     expect(newPosition).toEqual(expectedRect) | ||||||
|  |   }) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | describe('getOverflows', () => { | ||||||
|  |   function makeOverflows(top, left, bottom, right) { | ||||||
|  |     return { | ||||||
|  |       top, | ||||||
|  |       left, | ||||||
|  |       bottom, | ||||||
|  |       right, | ||||||
|  |       h: left || right, | ||||||
|  |       v: top || bottom, | ||||||
|  |       any: top || left || bottom || right, | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   it('no overflows, when parent contains child', () => { | ||||||
|  |     const parent = makeRect(0, 0, 20, 20) | ||||||
|  |     const child = makeRect(5, 5, 15, 15) | ||||||
|  |     const expected = makeOverflows(false, false, false, false) | ||||||
|  |     expect(getOverflows(parent, child)).toEqual(expected) | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   it('does not overflow itself', () => { | ||||||
|  |     const parent = makeRect(0, 0, 20, 20) | ||||||
|  |     const expected = makeOverflows(false, false, false, false) | ||||||
|  |     expect(getOverflows(parent, parent)).toEqual(expected) | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   it('overflowTop', () => { | ||||||
|  |     const parent = makeRect(0, 0, 20, 20) | ||||||
|  |     const child = makeRect(-5, 5, 10, 15) | ||||||
|  |     const expected = makeOverflows(true, false, false, false) | ||||||
|  |     expect(getOverflows(parent, child)).toEqual(expected) | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   it('overflowLeft', () => { | ||||||
|  |     const parent = makeRect(0, 0, 20, 20) | ||||||
|  |     const child = makeRect(5, -5, 10, 15) | ||||||
|  |     const expected = makeOverflows(false, true, false, false) | ||||||
|  |     expect(getOverflows(parent, child)).toEqual(expected) | ||||||
|  |   }) | ||||||
|  |   it('overflowBottom', () => { | ||||||
|  |     const parent = makeRect(0, 0, 20, 20) | ||||||
|  |     const child = makeRect(5, 5, 25, 15) | ||||||
|  |     const expected = makeOverflows(false, false, true, false) | ||||||
|  |     expect(getOverflows(parent, child)).toEqual(expected) | ||||||
|  |   }) | ||||||
|  |   it('overflowRight', () => { | ||||||
|  |     const parent = makeRect(0, 0, 20, 20) | ||||||
|  |     const child = makeRect(5, 5, 10, 25) | ||||||
|  |     const expected = makeOverflows(false, false, false, true) | ||||||
|  |     expect(getOverflows(parent, child)).toEqual(expected) | ||||||
|  |   }) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | describe('updateRect', () => { | ||||||
|  |   it('works with squares', () => { | ||||||
|  |     const rect = makeRect(0, 0, 5, 5) | ||||||
|  |     const shift = { left: 10, top: 10 } | ||||||
|  |     const expected = makeRect(10, 10, 15, 15) | ||||||
|  |     expect(updateRect(rect, shift)).toEqual(expected) | ||||||
|  |   }) | ||||||
|  |   it('works with non squares', () => { | ||||||
|  |     const rect = makeRect(0, 0, 200, 100) | ||||||
|  |     const shift = { left: 10, top: 10 } | ||||||
|  |     const expected = makeRect(10, 10, 210, 110) | ||||||
|  |     expect(updateRect(rect, shift)).toEqual(expected) | ||||||
|  |   }) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | function makeRect(top, left, bottom, right) { | ||||||
|  |   const width = right - left | ||||||
|  |   const height = bottom - top | ||||||
|  |   return { top, left, bottom, right, width, height } | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								src/dragable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/dragable.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | export function makeDragable(node) { | ||||||
|  |   let offsetX = 0 | ||||||
|  |   let offsetY = 0 | ||||||
|  | 
 | ||||||
|  |   const mouseMoveHandler = (evt) => { | ||||||
|  |     const [x, y] = getMousePos(evt) | ||||||
|  |     node.style.left = `${x - offsetX}px` | ||||||
|  |     node.style.top = `${y - offsetY}px` | ||||||
|  |     node.dispatchEvent(new Event('custom-drag')) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const dragStart = (evt) => { | ||||||
|  |     const [mouseX, mouseY] = getMousePos(evt) | ||||||
|  |     const [nodeX, nodeY] = getNodePos(node) | ||||||
|  |     offsetX = mouseX - nodeX | ||||||
|  |     offsetY = mouseY - nodeY | ||||||
|  |     window.addEventListener('mousemove', mouseMoveHandler) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const dragStop = () => { | ||||||
|  |     window.removeEventListener('mousemove', mouseMoveHandler) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   node.addEventListener('mousedown', dragStart) | ||||||
|  |   window.addEventListener('mouseup', dragStop) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getMousePos(evt) { | ||||||
|  |   return [evt.pageX, evt.pageY] | ||||||
|  | } | ||||||
|  | function getNodePos(node) { | ||||||
|  |   const { top, left } = node.getBoundingClientRect() | ||||||
|  |   return [left, top] | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								src/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | import { makeDragable } from './dragable.js' | ||||||
|  | import { alignChild } from './context.js' | ||||||
|  | import { optionsListener, getOptions } from './options.js' | ||||||
|  | 
 | ||||||
|  | const parent = document.getElementById('parent') | ||||||
|  | const context = document.getElementById('context') | ||||||
|  | const container = document.getElementById('container') | ||||||
|  | 
 | ||||||
|  | makeDragable(parent) | ||||||
|  | 
 | ||||||
|  | let options = getOptions() | ||||||
|  | 
 | ||||||
|  | function render() { | ||||||
|  |   console.log(options) | ||||||
|  |   const { alignments, boxSizes, containment } = options | ||||||
|  |   parent.style.width = boxSizes.parentWidth | ||||||
|  |   parent.style.height = boxSizes.parentHeight | ||||||
|  |   context.style.width = boxSizes.contextWidth | ||||||
|  |   context.style.height = boxSizes.contextHeight | ||||||
|  |   alignChild(parent, context, container, alignments, containment) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | optionsListener((newOptions) => { | ||||||
|  |   options = newOptions | ||||||
|  |   render() | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | render() | ||||||
|  | parent.addEventListener('custom-drag', render) | ||||||
							
								
								
									
										45
									
								
								src/options.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/options.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | const options = {} | ||||||
|  | 
 | ||||||
|  | function updateOptions() { | ||||||
|  |   updateAlignments() | ||||||
|  |   updateBoxSizes() | ||||||
|  |   updateContainment() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function updateAlignments() { | ||||||
|  |   options.alignments = {} | ||||||
|  |   for (const option of ['parentH', 'parentV', 'childH', 'childV']) { | ||||||
|  |     options.alignments[option] = document.getElementById(option).value | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function updateBoxSizes() { | ||||||
|  |   options.boxSizes = {} | ||||||
|  |   for (const option of [ | ||||||
|  |     'parentWidth', | ||||||
|  |     'parentHeight', | ||||||
|  |     'contextWidth', | ||||||
|  |     'contextHeight', | ||||||
|  |   ]) { | ||||||
|  |     options.boxSizes[option] = document.getElementById(option).value | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function updateContainment() { | ||||||
|  |   options.containment = {} | ||||||
|  |   for (const option of ['invertH', 'invertV', 'containInto']) { | ||||||
|  |     options.containment[option] = document.getElementById(option).checked | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | /** Calls callback when options change */ | ||||||
|  | export function optionsListener(callback) { | ||||||
|  |   window.addEventListener('change', () => { | ||||||
|  |     updateOptions() | ||||||
|  |     callback(options) | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function getOptions() { | ||||||
|  |   updateOptions() | ||||||
|  |   return options | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								style.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | |||||||
|  | html body { | ||||||
|  |   margin: 0; | ||||||
|  |   padding: 0; | ||||||
|  |   overflow: hidden; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | main { | ||||||
|  |   height: 100vh; | ||||||
|  |   display: grid; | ||||||
|  |   grid-template-columns: 10% 2fr 1fr; | ||||||
|  |   grid-template-rows: 10% auto 10%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | h1 { | ||||||
|  |   grid-column: 2 / 3; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #container { | ||||||
|  |   border: 1px solid green; | ||||||
|  |   grid-column: 2 / 3; | ||||||
|  |   grid-row: 2 / 3; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #parent { | ||||||
|  |   border: 1px solid blue; | ||||||
|  |   height: 300px; | ||||||
|  |   width: 300px; | ||||||
|  |   position: absolute; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #context { | ||||||
|  |   border: 1px solid red; | ||||||
|  |   height: 100px; | ||||||
|  |   width: 100px; | ||||||
|  |   position: fixed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #options { | ||||||
|  |   grid-column: 3 / 4; | ||||||
|  |   grid-row: 1 /3; | ||||||
|  |   padding: 1em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | form > label { | ||||||
|  |   display: flex; | ||||||
|  |   background-color: white; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | form > label > span { | ||||||
|  |   flex: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | form > label > select { | ||||||
|  |   margin-left: 8px; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user