Skip to content

Instantly share code, notes, and snippets.

View thomaswilburn's full-sized avatar
🦝

Thomas Wilburn thomaswilburn

🦝
View GitHub Profile

Development By Proxy

There's an argument that if you use private class fields in JavaScript, your code is incompatible with Vue (and other frameworks that use proxies to provide reactive data binding). That's interesting! Why is that? And is it actually impossible to use private fields with @vue/reactivity? To find out, let's take a look at how both private fields and proxies work in JavaScript, and see some possible solutions.

How Proxies break Vue

A proxy in JavaScript is an object that can stand in for another and "trap" various operations, like calling methods or getting/setting properties. They're useful for mocking or logging, because you can effectively wrap an object in a proxy and see (or interfere with) all the actions that code takes on that object, without having to actually touch either side of the original code.

Here's a quick example:

@thomaswilburn
thomaswilburn / writeup.md
Last active January 16, 2024 03:33
Creating a document minimap with SVG

One of my favorite no-so-secret weapons for data visualization on the web is the SVG viewBox attribute. I've written about it before: in my textbook, I have a whole chapter on art direction with viewBox, and I also talk about it in the section on rendering SVG from JS.

Essentially, the viewBox attribute lets you set up the... view box. SVG works on a 2d coordinate system that can (but doesn't have to) match the CSS positioning grid for an element. You can use the attribute to tell the SVG to set an offset for the rendering canvas, to zoom in or out, or to crop the image to keep an area in view while still fitting in an arbitrary aspect ratio (similar to how object-fit and object-position work in CSS, but more granular).

But on a recent project, I also had a chance to use viewBox as a literal view box: for a [Votebeat story](https://arizona.votebeat.org/2022/10/18/23410059/ma

@thomaswilburn
thomaswilburn / Code.js
Last active September 28, 2022 13:00
=importJSON support for Sheets, producing keypath/value pairs
function IMPORTJSON(url) {
var response = UrlFetchApp.fetch(url);
var text = response.getContentText();
var json = JSON.parse(text);
var output = [];
var step = function(at, value) {
if (value instanceof Array) {
for (var i = 0; i < value.length; i++) {
@thomaswilburn
thomaswilburn / download_sheet.deno.js
Created August 11, 2022 14:23
Download a Google sheet via Deno
import * as google from "https://esm.sh/@googleapis/sheets";
import { stringify } from "https://esm.sh/csv-stringify/sync";
var clientID = Deno.env.get("GOOGLE_OAUTH_CLIENT_ID");
var secret = Deno.env.get("GOOGLE_OAUTH_CONSUMER_SECRET");
var spreadsheetId = "1R78UCHNrc2VrTuObhduVZNpgSZJDV5-kuw8S4gzJV9k";
var HOME = Deno.env.get("HOME");
@thomaswilburn
thomaswilburn / media-favicon.js
Created May 25, 2022 16:43
Add a favicon with media playback progress in Firefox
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 32;
var context = canvas.getContext("2d");
var link = document.createElement("link");
link.setAttribute("rel", "icon");
var media = document.querySelector("audio, video");
media.addEventListener("timeupdate", function() {
// get the current ratio
@thomaswilburn
thomaswilburn / tcaer.md
Created May 9, 2022 15:23
React but make it imperative

What if React was imperative instead of being functional?

When you write JSX, it compiles down to nested calls to createElement() (or the equivalent, I don't know if that's still the function React uses). Because this ends up being a single recursive function call, you can only use value expressions inside the code--that's why you have to map() when you loop, and you have to use ternaries instead of actual conditional statements.

Over time, the React team's thinking about architecture has clearly shifted a lot, to the point now where hook functions create implicit, hidden state that's preserved in the order of the function calls. What if JSX worked this way? What if when you wrote a template, instead of a single function call with nested expressions, it used imperative, IMGUI-like function calls instead? In that case, the raw code might look something like this:

template(html => {
  var { footer, a, button, text, div, ul, li } = html;
  div`.outer`;
@thomaswilburn
thomaswilburn / re-iterate.md
Last active April 30, 2023 13:26
Putting JavaScript's iterable protocol into context

Re: Iterate

I'm so old I remember when arrays in JavaScript didn't have forEach() or map(), and a lot of libraries would implement their own functional looping constructs, which were better than regular loops because you got a new function scope (remember, we didn't have let or const either). We all had to adjust when native forEach() landed because we were used to jQuery's each(), which had the arguments in the wrong order.

I was reminded of this while doing some scraping last week using Cheerio to load and traverse an HTML page in Node. Cheerio implements a jQuery-like API, which is genuinely pleasant to use, but carries some of that legacy behavior (like each(index, item) argument ordering) with it in ways that are jarring if you haven't used actual jQuery in a while. Fortunately, Cheerio also implements the iterator protocol on its collections, so if you just want the items for a given selector, you can use for ... of loops and not have to think abo

@thomaswilburn
thomaswilburn / keymap.c
Last active April 3, 2022 13:52
QMK retro toggle lighting for CTRL
#include "print.h"
#include QMK_KEYBOARD_H
enum ctrl_keycodes {
L_BRI = SAFE_RANGE, //LED Brightness Increase //Working
L_BRD, //LED Brightness Decrease //Working
L_EDG_I, //LED Edge Brightness Increase
L_EDG_D, //LED Edge Brightness Decrease
L_EDG_M, //LED Edge lighting mode
L_PTN, //LED Pattern Select Next //Working
@thomaswilburn
thomaswilburn / keymap.c
Last active March 31, 2022 18:28
Personalized QMK for CTRL
#include QMK_KEYBOARD_H
enum ctrl_keycodes {
L_BRI = SAFE_RANGE, //LED Brightness Increase //Working
L_BRD, //LED Brightness Decrease //Working
L_EDG_I, //LED Edge Brightness Increase
L_EDG_D, //LED Edge Brightness Decrease
L_EDG_M, //LED Edge lighting mode
L_PTN, //LED Pattern Select Next //Working
L_PTP, //LED Pattern Select Previous //Working
@thomaswilburn
thomaswilburn / zip-it.md
Last active April 18, 2024 11:56
Exploring generators and iteration through zip()

Win zip()

I don't often use zip(), but by coincidence this week I ran into it a few times, using both Python and JavaScript. In the former, it's a built-in, but in the latter it's typically provided by a library like D3. And it struck me as kind of a fun warm-up challenge. How would you write this function in modern JavaScript?

Well, let's see how D3 does it. Oh, it's a wrapper around transpose(), here we go...

import min from "./min.js";

function length(d) {