Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
ryanflorence / feedback.md
Last active September 18, 2024 17:20
Feedback for José

Article Feedback

Shared Links UI

I decided to give it a try, find some bugs, and discuss possible root causes.

This UI doesn't use Remix's built-in conventions, it uses React Query talking to a backend API like many React SPAs.

The behavior shown in this video is not the behavior of Remix: https://x.com/josevalim/status/1832509464240374127

You can leave them in the module scope and use the new types:

import {
-  LoaderFunctionArgs,
-  ActionFunctionArgs,
+  LoaderArgs,
+  ActionArgs
  useLoaderData,
+  defineRoute

View Transitions

Scroll Restoration

When the user has a history stack with element transitions, it's possible for them to scroll the element out of view on one or both pages. This can cause elements to translate thousands of pixels across the document and should be avoided.

Here are a few product-level use cases that I would consider good practice with a the proverbial grid-to-hero-image CSS transform.

Scroll Position Priority

function App() {
return (
<Routes>
<Route path="/" element={<Root />}>
<Route index element={<Index />} />
<Route path="projects" element={<Projects />} />
</Route>
</Routes>
);
}
import type { V2_HtmlMetaDescriptor, V2_MetaFunction } from "@remix-run/node";
export const mergeMeta = (
overrideFn: V2_MetaFunction,
appendFn?: V2_MetaFunction,
): V2_MetaFunction => {
return arg => {
// get meta from parent routes
let mergedMeta = arg.matches.reduce((acc, match) => {
return acc.concat(match.meta || []);
import { riff, route, html, indexRoute } from "../riff/riff.mjs";
import { serve } from "../riff/riff-express.mjs";
import {
deleteTask,
getProjects,
getTasks,
getUser,
sendEmail,
updateTask,
createTask,
import { useFetcher } from "@remix-run/react";
import { useCallback, useMemo } from "react";
export function useRevalidator() {
let fetcher = useFetcher();
let revalidate = useCallback(
() => {
fetcher.submit(null, { action: "/", method: "post" });
},
type InitFunction = (send: SendFunction) => CleanupFunction;
type SendFunction = (event: string, data: string) => void;
type CleanupFunction = () => void;
export function eventStream(request: Request, init: InitFunction) {
let stream = new ReadableStream({
start(controller) {
let encoder = new TextEncoder();
let send = (event: string, data: string) => {
controller.enqueue(encoder.encode(`event: ${event}\n`));
import invariant from "tiny-invariant";
class AmalgoBox extends HTMLElement {
get input() {
return this.querySelector("input") as HTMLInputElement;
}
get button() {
return this.querySelector("button") as HTMLButtonElement;
}
// WIP, just finding all the boxes and glue, implementation is woefully incomplete
import type { DOMAttributes } from "react";
import { assign, createMachine, interpret } from "@xstate/fsm";
import invariant from "tiny-invariant";
type CustomElement<T> = Partial<
T & DOMAttributes<T> & { children: any; class: string }
>;