commit b89d16fb8af83161b538ef58b826ef39d0b4b78d
parent 138c6d3f81b993e5f6b17456199438441db764b1
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Thu, 1 Oct 2026 01:21:36 -0400
editor: the shared widgets' controlled checkboxes and selects survive the reset too — DurationField, SocialLinksField, SiteMembershipsSection, WorkersField
The ruling named these as the model that already survives, and their TEXT
inputs do. Their checkboxes and selects do not: react-dom sets a controlled
checkbox's defaultChecked and a controlled select's defaultSelected only at
mount, so the reset after any submit (a refusal or a save) showed what each one
mounted with while state held the choice — a cadence select back on its old
preset beside the new amount, a worker's Enabled box ticked again after it was
saved off. What they post is from state (a hidden input), so nothing saved was
wrong; what the operator saw was. One tag swap each to ControlledCheck /
ControlledSelect (forms/Controlled.tsx); nothing else in them changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
4 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/editor/app/channels/components/SiteMembershipsSection.tsx b/editor/app/channels/components/SiteMembershipsSection.tsx
@@ -1,6 +1,12 @@
"use client";
import { useState } from "react";
+// Its controlled checkboxes and selects sit inside action forms, whose reset they would not
+// survive alone (forms/Controlled.tsx).
+import {
+ ControlledCheck,
+ ControlledSelect,
+} from "../../components/forms/Controlled";
// The channel form's per-site membership picker: every configured site with a
// checkbox (member or not) plus a group dropdown, including a "+ New group…"
@@ -137,7 +143,7 @@ export function SiteMembershipsSection({
>
<div className="flex items-center gap-2 text-sm">
<label className="flex items-center gap-2 flex-1 min-w-0">
- <input
+ <ControlledCheck
type="checkbox"
checked={on}
onChange={(e) => toggle(s.siteId, e.target.checked)}
@@ -151,7 +157,7 @@ export function SiteMembershipsSection({
</span>
</label>
{on && (
- <select
+ <ControlledSelect
value={row.groupId}
onChange={(e) => setGroup(s.siteId, e.target.value)}
aria-label={`Group for ${label}`}
@@ -164,7 +170,7 @@ export function SiteMembershipsSection({
</option>
))}
<option value={NEW_GROUP}>+ New group…</option>
- </select>
+ </ControlledSelect>
)}
</div>
{on && row.groupId === NEW_GROUP && (
diff --git a/editor/app/components/DurationField.tsx b/editor/app/components/DurationField.tsx
@@ -11,6 +11,9 @@ import {
unitLabel,
type DurationUnit,
} from "yt-dlp-transcript-common/lib/duration";
+// Its controlled selects sit inside action forms, whose reset they would not
+// survive alone (forms/Controlled.tsx).
+import { ControlledSelect } from "./forms/Controlled";
// A cadence control: pick a preset, or type an amount and choose a unit.
//
@@ -163,7 +166,7 @@ export function DurationField({
{!hideLabel && <span className="font-medium">{label}</span>}
<div className="flex flex-wrap items-center gap-2">
{hasModeSelect && (
- <select
+ <ControlledSelect
aria-label={label}
value={mode}
onChange={(e) => setMode(e.target.value)}
@@ -182,7 +185,7 @@ export function DurationField({
</option>
))}
<option value={DURATION_CUSTOM}>Custom…</option>
- </select>
+ </ControlledSelect>
)}
{isCustom && (
<>
@@ -197,7 +200,7 @@ export function DurationField({
min={1}
className={`${inputClass} w-24`}
/>
- <select
+ <ControlledSelect
aria-label={`${label} unit`}
value={unit}
onChange={(e) => setUnit(e.target.value as DurationUnit)}
@@ -208,7 +211,7 @@ export function DurationField({
{unitLabel(u, parsedAmount || 2)}
</option>
))}
- </select>
+ </ControlledSelect>
</>
)}
</div>
diff --git a/editor/app/components/SocialLinksField.tsx b/editor/app/components/SocialLinksField.tsx
@@ -2,6 +2,9 @@
import type { SocialLink } from "yt-dlp-transcript-common/lib/settings";
import { socialLinksJson, type SocialRow } from "./socialLinksJson";
+// Its controlled checkboxes sit inside action forms, whose reset they would not
+// survive alone (forms/Controlled.tsx).
+import { ControlledCheck } from "./forms/Controlled";
export type { SocialRow };
@@ -101,7 +104,7 @@ export function SocialLinksField({ value, onChange, name }: Props) {
kept first (common/lib/socialLinks.ts headerSocialLinks). */}
<div className="flex flex-wrap items-center gap-x-3 gap-y-1">
<label className="flex items-center gap-2 text-sm">
- <input
+ <ControlledCheck
type="checkbox"
checked={s.featured === true}
onChange={(e) => update(idx, { featured: e.target.checked })}
diff --git a/editor/app/workers/components/WorkersField.tsx b/editor/app/workers/components/WorkersField.tsx
@@ -3,6 +3,12 @@
import { useId, useState } from "react";
import type { Worker } from "yt-dlp-transcript-common/lib/workers";
import type { TranscriptionAppDescriptor } from "yt-dlp-transcript-common/lib/transcriptionApps";
+// Its controlled checkboxes and selects sit inside action forms, whose reset they would not
+// survive alone (forms/Controlled.tsx).
+import {
+ ControlledCheck,
+ ControlledSelect,
+} from "../../components/forms/Controlled";
// Editor for the transcription worker list. Manages an ordered array of workers
// (list order == priority, top = highest) and serializes it to a hidden JSON
@@ -248,7 +254,7 @@ function WorkerCard({
className="flex-1 min-w-40 rounded border border-border bg-card px-2 py-1 text-sm"
/>
<label className="flex items-center gap-1 text-xs">
- <input
+ <ControlledCheck
type="checkbox"
checked={row.enabled}
onChange={(e) => onPatch({ enabled: e.target.checked })}
@@ -299,7 +305,7 @@ function WorkerCard({
{row.kind === "local" && (
<label className="flex flex-col gap-1 text-xs">
<span className="font-medium">Engine</span>
- <select
+ <ControlledSelect
value={row.appId ?? ""}
onChange={(e) => onPatch({ appId: e.target.value })}
aria-label={`worker ${index + 1} engine`}
@@ -310,7 +316,7 @@ function WorkerCard({
{a.label}
</option>
))}
- </select>
+ </ControlledSelect>
</label>
)}
<span className="text-xs text-muted-foreground">
@@ -460,7 +466,7 @@ function WorkerCard({
id={`${uid}-slots`}
/>
<label className="flex items-center gap-2 text-xs">
- <input
+ <ControlledCheck
type="checkbox"
checked={remote.sharedFs === true}
onChange={(e) => onPatchRemote({ sharedFs: e.target.checked })}