I wanted to create a drop down field with many options eg:
It was inspired by the Google search bar.
Drop Down FIeld works really nicely. It has more and better optons than all drop downs I've seen.
Check out the examples, click the SEE EXAMPLES button above.
Javascript
HTML
CSS
Sass
Rollup
Git
Github
Creating any control is very delicate, especially a drop down field control which is one of the most difficult. And even more difficult is all the great options I have been able to do with this Drop Down Field. There are different browsers and different environments to consider. In hindsight, it's best to rely on a UI libraries instead of build your own. Even though they don't have the options that Drop Down field has. It's a very difficult process to build and test a control you built yourself. It takes time and it's been done before. It's best to use a UI library which will allow you to customize the look and feel quite a bit.
Javascript projects like this are not React compatible. To make it React compatible took a long time and it still wasn't fully working. I had to abandon it.
Some of the many early Javascript projects I did were done knowing that I would learn some really hard lessons. But I'd also learn some very crucial lessons too while along the way learning Javascript to a deeper level. I didn't mind crashing hard.
Most events that occur on document elements by default bubble. Exceptions are the “focus,” “blur,” and “scroll” events.
The blur event does not bubble, but the related focusout event that follows does bubble. blur is not fired when a focused element is removed from the document. Blur only fires when it's capture.
Communication between a dropdown list and a button is very difficult when they rely on each other and one loses focus and the other gets focus and the state of each are dependent on each other. It's really difficult to make UI components for various environments.
Two things within a container that depend on each other, clicking on one then clicking on the other, it still goes all the way up to the document before going down to the other item. You can't shortcircuit it. Even if you put a click event on the container, it still goes all the way back up
Key events aren't symetrical. You can have several keydowns but only one keyup. keydown is 30 keydowns a second.
When there is a sequence list eg 1, 2, 3, 4...., you don't need a dropdown list to show all the options, the user can just select the up or down arrows. They know the next value.
Although childNodes is newer, children is better for drop down lists, it doesn't have the text node elements.
A div can only have a 'focus' event if it gets the focus and you can do that by having a tabindex in html.
Some elements are by default able to get focus but not be clickable:
<input type="text">
or
<textarea></textarea>
Elements that are clickable but can't get focus:
<div onclick="alert('clicked!')"></div>
These don't guarantee focus of an element on load:
autofocus, tabindex="1" or event .focus()
Even this won't guarantee you focus on load:
window.addEventListener("load", () => { el.focus() })
To be able to do it, do this:
document.addEventListener("DOMContentLoaded", function () { window.addEventListener("load", function (e) { document.querySelector(".autofocus").focus() })
It seems like there is no spec on page load hooks and DOM focus hooks.
children is a special property for Render Props.
<Outer> <Inner></Inner> // Inner is the children prop </Outer>
Render props allow you to have state from outside. props.children is sort of outside but inside Render props are good for a dropdown that changes it's list like when filtering eg
<DropdownField .....> [listOptions].map((item, idx) => { <MenuItem key={idx}>{item}</MenuItem> }) </DropdownField>
Props can take components as arguments because you can put args in curly brackets eg
<App arg={<MyComponent />} /> <MyComponent arg={<h1>Hi</h1>} />
When a component renders, it re-renders the component and all it's children.
Render props can be good for when you have a component with heavy computation and you don't want it to re-render a part of it. This is the distinct advantage of render props and arguably the only benefit.
It may be the only reason to use Render Props. Render props cause the Triangle of Death in your code.You don't get the keyboard on a virtual keyboard. Mobile devices don't have real keyboards so they don't have those key input events. There may be more virtual keyboards than real ones. Some platforms, most notably the virtual keyboard on Android phones, don't fire key events.
Saying something into your phone and then your smart phone type it into the text box or using a spellchecker on your phone, that's how to think of text input. Not character by character input.
If the input device isn't a physical keyboard, but is instead a virtual keyboard or accessibility device, the returned value will be set by the browser to match as closely as possible to what would happen with a physical keyboard, to maximize compatibility between physical and virtual input devices.
Key-codes are simply not possible in many of the modern input methods and thus it's better to not send them at all so developers will create systems that work for all users and not just some narrow audience using a particular subset of all possible interfaces.
Mobile virtual keyboards are primarily for inputting, not for interacting, which is where the issues come from. whereas physical keyboards are very simple devices that send known signals.
Assignment of variables is the same for primitive and non-primitive. People get mistaken on how this works. Comparing values and behaviour is where it's very different. Primitive variables compare by value, non-primitive variables by reference.
All variables regardless of primitive or non primitve are declared at the start of the scope.
'=' means assign a memory address to it. Regardless of primitive/non-primitive.
When reassigning the same value eg
let a = 1; a = 20;
It does not overwrite it on the same address space regardless of whether its primitive or non-primitive.
Reassigning makes a new address and the old address is cleaned up later. That's how it works regardless of if it's a primitive or non-primitive value.
let arr1=[1]; let arr2=[2,2]; let arrMain=[arr1, arr2]; arr1=[1,1]; console.log(arrMain); console.log(arr1); > [ [ 1 ], [ 2, 2 ] ] > [ 1, 1 ]
Primitives and non-primitives both have an address space assigned to it and Javascript doesn't give the address out ever, it just gives the value. Javascript also doesn't update the links from old address to new address. It's too much work, it would slow it down. Immutable just means that when you use '=', you are re-assigning, you can't overwrite the old value with the new one, it makes a new memory space for it.
If you change a value within the array, the array keeps pointing to the same address, values within it may change.
An analogy I could use is, it's like a bus, people get on and get off, but the value of the bus stays the same. Arrays are just a container, as long as that container keeps the same address ie it's not re-assigned.
let a = 1 let b = 2 let arr = [a, b] a = 11 console.log(arr) console.log(a) > [ 1, 2 ] > 11
arr[0] is given the value 1, it's not a reference. Javascript doesn't go around looking for anything that pointed to 'a' and redirect to the new address.
Garbage collector cleans up the old memory addresses that aren't used anymore but it doesn't do it immediately.
A non-primitve has values within it that can't be const, they are let.
This is very relevant for how IIFEs and closure work:
let outeriife = function() { let firstvar = 1 function inc() { firstvar += 1 console.log("firstvar - " + firstvar) } return { inc } } let o = outeriife() // this makes it keep context and scope o.inc() firstvar - 2 o.inc() firstvar - 3
Scope is held in 'o' in this above case. But in the case below, scope isn't held.
outeriife().inc() >firstvar - 2 outeriife().inc() >firstvar - 2 outeriife().inc() >firstvar - 2
In Drop Down Field, I use render() within the main iife and executed within it to put the drop down box on the page. Each Drop Down Field has its own scope. DOMContentLoaded events launch focus event. The focus event adds blur and other events, blur removes these events.
<select>-<option> has less control over the look and style esp the line-height. It has key event behaviour build in. <select>-<option> automatically has arrow key control up and down to select a different value. Space to drop down the list and Enter to select a value. It has a debounce feature in it. My drop down field uses filter instead which I think is better. <select>-<option> was before <ul>-<li>.
Communication between a dropdown list and a button is very difficult when they rely on each other and one loses focus and the other gets focus and the state of each are dependent on each other. I overcame most of this problem by using state in the DOM via an attribute.
Event sequence was really confusing. Click, focus and mousedown. But when it goes from one element immediately to events firing on another element and understanding the bubbling and capture was very confusing. Once I knew exact order of events and experimented with bubbling and capture, it made more sense. I also logged state and event sequences to help debug.
Autofocus was confusing, especially that the 'autofocus' attribute doesn't always work. I researched it but never got a definitive answer. I experimented and came up with a good solution (mentioned above).
To make this Drop Down Field for React was very hard and I gave up on it because of time pressures.