Tuesday, February 16, 2021

Dvorak navigations - there's no place like home keys

The Karabiner-Element configuration below enable users to use the home keys for cursor navigation

For best experience, map caps lock to control key, map left control key to esc key.

Not all apps honor the unix-y way of moving the cursor, the Karabiner-Element configuration below will enable it on almost all apps (except Microsoft Office). Microsoft Office apps still interprets Control+B as bold, Control+F as find

I noticed that on online code editors like codepen.io, though they recognize control+F and control+B as right and left arrow respectively, they does not recognize option+control+F as one word to the right, and option+control+B as one word to the left. Worse yet, option+control+F triggers full screen on codesandbox.io, the configuration below solves this problem too.

Up = control+P
Down = control+N
Left = control+B
Right = control+F

option + Right (One word to the right) = option + control+F
option + Left (One word to the left) = option + control+B

delete = control+H
fn+delete = control+D

option + delete (delete one word to the left) = option + control+H
option + fn+delete (delete one word to the right) = option + control+D

{
    "description": "Dvorak navigations - no place like home keys",
    "manipulators": [
        {
            "from": {
                "key_code": "j",
                "modifiers": {
                    "mandatory": [
                        "left_control"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "delete_or_backspace"
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "j",
                "modifiers": {
                    "mandatory": [
                        "left_control",
                        "left_option"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "delete_or_backspace",
                    "modifiers": [
                        "left_option"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "h",
                "modifiers": {
                    "mandatory": [
                        "left_control"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "delete_forward"
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "h",
                "modifiers": {
                    "mandatory": [
                        "left_control",
                        "left_option"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "delete_forward",
                    "modifiers": [
                        "left_option"
                    ]
                }
            ],
            "type": "basic"
        },                            
        {
            "from": {
                "key_code": "l",
                "modifiers": {
                    "mandatory": [
                        "left_control"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "down_arrow"
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "l",
                "modifiers": {
                    "mandatory": [
                        "left_control",
                        "left_shift"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "down_arrow",
                    "modifiers": [
                        "left_shift"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "r",
                "modifiers": {
                    "mandatory": [
                        "left_control"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "up_arrow"
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "r",
                "modifiers": {
                    "mandatory": [
                        "left_control",
                        "left_shift"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "up_arrow",
                    "modifiers": [
                        "left_shift"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "y",
                "modifiers": {
                    "mandatory": [
                        "left_control",
                        "left_option"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "right_arrow",
                    "modifiers": [
                        "left_option"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "y",
                "modifiers": {
                    "mandatory": [
                        "left_control",
                        "left_option",
                        "left_shift"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "right_arrow",
                    "modifiers": [
                        "left_option",
                        "left_shift"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "n",
                "modifiers": {
                    "mandatory": [
                        "left_control",
                        "left_option"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "left_arrow",
                    "modifiers": [
                        "left_option"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "n",
                "modifiers": {
                    "mandatory": [
                        "left_control",
                        "left_option",
                        "left_shift"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "left_arrow",
                    "modifiers": [
                        "left_option",
                        "left_shift"
                    ]
                }
            ],
            "type": "basic"
        }
    ]
}

Friday, February 5, 2021

create react app + typescript script


% cat ~/.scripts/cra.sh 
#!/bin/zsh

if [ $# -eq 0 ] ; then
	echo "Pass the name of project"
	exit 1
fi

NAME="$1"

yarn dlx create-react-app $NAME --template typescript 

cd $NAME
yarn dlx @yarnpkg/pnpify --sdk vscode

yarn add react-refresh eslint-config-react-app

TO_DECLARE="declare module '@testing-library/react';"
printf $TO_DECLARE >> src/react-app-env.d.ts

code-insiders .

Tuesday, August 18, 2020

Avoiding name clashes when using HoC in React

After watching Michael Jackson's video on HoC vs render props, I noticed that the problems in HoC he mentioned can be avoided, albeit the component authors have to make their component's property names be dynamic. The component's property name(s) have to be explicitly set.

To cut to the chase, here's one implementation: https://codesandbox.io/s/compassionate-curie-i1x7w

App.js
import React from "react";
import "./styles.css";
import { withMouse } from "./Mouse";
import { withCat } from "./Cat";

const withMouseProp = "mouse";
const withCatProp = "spawnDate";

class App extends React.Component {
  render() {
    const mouseProp = this.props[withMouseProp];
    const catProp = this.props[withCatProp];
    const { message } = this.props;

    return (
      <div className="App">
        <h1>{message}</h1>
        <h2>Start editing to see some magic happen!</h2>
        mouse is at {mouseProp.x} {mouseProp.y}
        <br />
        Cat spawn date: {catProp}
      </div>
    );
  }
}

export default withMouse(
  withCat(App, withCatProp, withMouseProp),
  withMouseProp
);
Mouse.js
import React from "react";

export function withMouse(Component, mousePropName) {
  return class extends React.Component {
    state = { x: 0, y: 0 };

    handleMouseMove = (event) =  {
      this.setState({
        x: event.clientX,
        y: event.clientY
      });
    };

    render() {
      const withPropName = { ...this.props, [mousePropName]: this.state };
      return (
        <div onMouseMove={this.handleMouseMove}>
          <Component {...withPropName} />
        </div>
      );
    }
  };
}
Cat.js
import React from "react";

export function withCat(Component, catPropName, mousePropName) {
  return class extends React.Component {
    state = { x: 0, y: 0 };

    componentDidUpdate(prevProps) {
      const mouse = this.props[mousePropName];
      if (
        mouse.x !== prevProps[mousePropName].x ||
        mouse.y !== prevProps[mousePropName].y
      ) {
        this.setState(mouse);
      }
    }

    render() {
      const mouse = this.props[mousePropName];
      const withPropName = {
        ...this.props,
        [catPropName]: new Date().toISOString()
      };
      return (
        <>
          <Component {...withPropName} />
          <div>
            style={{
              position: "absolute",
              left: mouse.x,
              top: mouse.y,
              width: "25px",
              height: "25px",
              backgroundColor: "red"
            }}
          >
            cat
          </div>
        </>
      );
    }
  };
}

The above solution is moot point now, use React hooks instead.

Monday, August 17, 2020

Center

.container {
    min-height: 100vh; 
    
    display: flex;
    justify-content: center;
    align-items: center;
}
Details: scotch.io: Centering things with CSS Flexbox

Sunday, August 16, 2020

Create React App with TypeScript and PnP (no npx)

#!/bin/zsh

if [ $# -eq 0 ] ; then
	echo "Pass the name of project"
	exit 1
fi

yarn set version berry

NAME="$1"

yarn dlx create-react-app $NAME --template typescript 

cd $NAME
yarn dlx @yarnpkg/pnpify --sdk vscode

TO_DECLARE="declare module '@testing-library/react';"
printf $TO_DECLARE >> src/react-app-env.d.ts

code .
The above is same as https://www.anicehumble.com/2020/08/create-react-app-with-typescript-and-pnp.html 

The previous one does not create hidden directory(.yarn) and file (.yarnrc.yml) on the parent directory of the project, while the script above do.

The advantage of the script above is almost everything works out of the box, but you just have to tolerate the creation of .yarn directory and .yarnrc.yml file on the directory where you run the create-react-app

Looks like it is safe to run "yarn set version berry" once on the home directory if you don't have any project that is dependent on yarn version 1. Setting yarn to berry on home folder would make yarn use the version 2 globally. With that said, the "yarn set version berry" above can be removed from the script.

If you set the yarn to version 2 globally and you need to go back to version 1, just delete the .yarn directory and .yarnrc file, yarn will run as version 1 again.