Skip to content

Instantly share code, notes, and snippets.

View donaldpipowitch's full-sized avatar

Donald Pipowitch donaldpipowitch

View GitHub Profile
@donaldpipowitch
donaldpipowitch / README.md
Created November 13, 2023 08:46
Custom ESLint Rules to support in migrating React Router v5 to v6
View README.md

Use at your own risk! Feel free to modify. They were customized for our code base and help to automate 90% of the migration our big React Router v5 app.

You will notice some data-exact field on routes. Those are only needed while you have some merge requests still on v5 and some on v6. When your whole code base (including pending merge requests) is using v6 you can safely delete all those ESLint rules and you can just run a string-replace on your code base to remove data-exact="true" and data-exact="false".

My two biggest gotchas during the migration:

Regarding the first point we created this file src/components/root-routes that is also expected by one of the ESLint Rules:

@donaldpipowitch
donaldpipowitch / .gitlab-ci.yml
Last active October 18, 2023 23:10
Visual Regression Testing with Storybook Test Runner
View .gitlab-ci.yml
storybook:test-runner8:
image: mcr.microsoft.com/playwright:v1.39.0-jammy
stage: build-and-test
artifacts:
expire_in: 2 weeks
when: always
paths:
- .storybook-images/__diff_output__/
- .storybook-images/__received_output__/
before_script:
@donaldpipowitch
donaldpipowitch / extension.ts
Created September 27, 2023 13:25
A VS Code extension which checks if a React component was created by styled-components.
View extension.ts
import * as vscode from 'vscode';
import * as ts from 'typescript';
import * as path from 'path';
export function activate(context: vscode.ExtensionContext) {
const decorationType = vscode.window.createTextEditorDecorationType({
light: {
before: {
contentText: 'S.',
color: 'rgba(255, 0, 255, 0.7)',
@donaldpipowitch
donaldpipowitch / README.md
Created September 27, 2023 06:22
Storybook: Conditionally show story/canvas
View README.md

In our Storybook we document components, but also whole pages. We also use the Docs addon. Sadly our Docs pages became pretty slow when a lot of documented pages were included. With the following solution we only render the first story/canvas by default and the remaining stories will only be rendered, when you click on them.

We do this by introducing a custom and component. Afterwards we can wrap every story/canvas in a ``.

@donaldpipowitch
donaldpipowitch / disallow-storybook-jest-import.js
Created February 14, 2023 09:40
ESLint rule which disallows importing "@storybook/jest" (it shall not be used inside "./tests")
View disallow-storybook-jest-import.js
// @ts-check
/** @type {import("eslint").Rule.RuleModule} */
const rule = {
meta: {
docs: {
description: '"@storybook/jest" should not be used inside "./tests".',
},
},
create(context) {
@donaldpipowitch
donaldpipowitch / README.md
Last active November 24, 2022 07:41
Storybook Addon
View README.md

This example shows how you can easily add a custom addon with TypeScript in an existing Storybook project.

This addon renders data on the manager side of Storybook, but what will be rendered can be influenced by the preview side of Storybook. We can easily interact with the addon within any Story.

import { useCounter } from './counter-addon';

// just use this hook in your stories like every other hook
const { add } = useCounter();
add(17);
@donaldpipowitch
donaldpipowitch / README.md
Created November 3, 2022 09:15
Codemod to add missing import, if a certain JSX Element is encountered
View README.md

I have a small helper file called prettiermod.js which I use to run codemods. You need to copy'n'paste the prettiermod.js file and install the dependencies ($ pnpm add globby@^11.0.0 @babel/traverse prettier).

After this you can create new codemods which use prettiermod.js. The following codemod adds an import in case we find a specific component (add import { SuspenseLoader } from 'src/components/spinner-container'; in case <SuspenseLoader/> can be found).

Just call $ node run-codemod.js to execute the codemod.

I use AST explorer for debugging (@babel/parser with flow disabled and typescript enabled and babelv7).

@donaldpipowitch
donaldpipowitch / README.md
Last active November 3, 2022 09:08
Codemod to add an attribute to a JSX Element
View README.md

I have a small helper file called prettiermod.js which I use to run codemods. You need to copy'n'paste the prettiermod.js file and install the dependencies ($ pnpm add globby@^11.0.0 @babel/traverse prettier).

After this you can create new codemods which use prettiermod.js. The following codemod adds a property with a default value to a specific component in case it is not there (flow="column" will be added to the <Stack /> component).

Just call $ node run-codemod.js to execute the codemod.

I use AST explorer for debugging (@babel/parser with flow disabled and typescript enabled and babelv7).

@donaldpipowitch
donaldpipowitch / README.md
Last active November 1, 2023 06:25
Type-safe query params in React with a "Hook Builder"
View README.md

Everyone loves type-safe APIs nowadays, but as far as I can tell query parameters are a blind spot to most people right now.

I create a hook which uses a builder pattern a while ago, which allows you to create type-safe query parameters. It is not very polished and contains some specific use cases, that's why I hesitated to share it. But as I successfully use it for a couple of month already and (afaik) no one came up with something similar so far, I wanted to share it.

How does it look like?

import * as pp from './page-params';

type FavoriteFood = 'pizza' | 'noodles' | 'wraps' | 'hot-dogs';
@donaldpipowitch
donaldpipowitch / use-timeout.ts
Created October 6, 2021 07:53
use-timeout.ts
View use-timeout.ts
// it's like setTimeout as a hook, but with a small twist:
// you can make multiple subsequent calls and can increase or decrease
// the delay (e.g. useful to create polling like functionality)
type Options = {
delay: number;
multiplier?: number;
};
type State = {