1c24140227f4

click-to-edit length number in GeneratorDrawer — both compact and full layouts, Enter/blur commits clamped to 8-128, Escape cancels, slider stays synced (v2.38.3)

time
2026-05-10 18:41 UTC · 5 months ago
machine
koh2
parent
104b98beeb6a
5 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/components/GeneratorDrawer.tsx+51 −2src/popup/styles/popup.css+16 −0
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach",4-  "version": "2.38.2",4+  "version": "2.38.3",55   "description": "Zero-knowledge password manager",66   "browser_specific_settings": {77     "gecko": {

view file

manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach",4-  "version": "2.38.2",4+  "version": "2.38.3",55   "description": "Zero-knowledge password manager",66   "action": {77     "default_popup": "src/popup/index.html",

view file

package.json+1 −1
@@ -1,6 +1,6 @@11 {22   "name": "peach",3-  "version": "2.38.2",3+  "version": "2.38.3",44   "description": "Zero-knowledge password manager",55   "type": "module",66   "scripts": {

view file

src/popup/components/GeneratorDrawer.tsx+51 −2
@@ -21,6 +21,8 @@2121   const [symbols, setSymbols] = createSignal(true);2222   const [forbiddenChars, setForbiddenChars] = createSignal("");2323   const [copied, setCopied] = createSignal(false);24+  const [editingLength, setEditingLength] = createSignal(false);25+  const [lengthDraft, setLengthDraft] = createSignal("");2426 2527   function initFromPolicy(policy: PasswordPolicy) {2628     let nextLength = length();@@ -119,6 +121,21 @@119121     regenerate({ symbols: next });120122   }121123 124+  function startEditingLength() {125+    setLengthDraft(String(length()));126+    setEditingLength(true);127+  }128+129+  function commitLength() {130+    const n = parseInt(lengthDraft(), 10);131+    if (!isNaN(n)) {132+      const clamped = Math.max(8, Math.min(128, n));133+      setLength(clamped);134+      regenerate({ length: clamped });135+    }136+    setEditingLength(false);137+  }138+122139   const passwordFontSize = () => {123140     const value = password();124141     if (value.length > 48) return "16px";@@ -179,7 +196,23 @@179196                   regenerate({ length: n });180197                 }}181198               />182-              <span class="peach-pwgen-len-num">{length()}</span>199+              <Show200+                when={editingLength()}201+                fallback={202+                  <span class="peach-pwgen-len-num peach-pwgen-len-num--edit" onClick={startEditingLength}>{length()}</span>203+                }204+              >205+                <input206+                  class="peach-pwgen-len-input"207+                  type="text"208+                  inputmode="numeric"209+                  value={lengthDraft()}210+                  ref={(el) => requestAnimationFrame(() => el.select())}211+                  onInput={(e) => setLengthDraft((e.currentTarget as HTMLInputElement).value)}212+                  onKeyDown={(e) => { if (e.key === "Enter") commitLength(); else if (e.key === "Escape") setEditingLength(false); }}213+                  onBlur={commitLength}214+                />215+              </Show>183216               <div class="peach-pwgen-compact-pills">184217                 <button class={`peach-pwgen-pill ${upper() ? "is-on" : ""}`} onClick={toggleUppercase} type="button">A-Z</button>185218                 <button class={`peach-pwgen-pill ${lower() ? "is-on" : ""}`} onClick={toggleLowercase} type="button">a-z</button>@@ -225,7 +258,23 @@225258             <div class="peach-pwgen-length-row">226259               <div class="peach-pwgen-length-labels">227260                 <span class="peach-label">length</span>228-                <span class="peach-pwgen-len-num">{length()}</span>261+                <Show262+                  when={editingLength()}263+                  fallback={264+                    <span class="peach-pwgen-len-num peach-pwgen-len-num--edit" onClick={startEditingLength}>{length()}</span>265+                  }266+                >267+                  <input268+                    class="peach-pwgen-len-input"269+                    type="text"270+                    inputmode="numeric"271+                    value={lengthDraft()}272+                    ref={(el) => requestAnimationFrame(() => el.select())}273+                    onInput={(e) => setLengthDraft((e.currentTarget as HTMLInputElement).value)}274+                    onKeyDown={(e) => { if (e.key === "Enter") commitLength(); else if (e.key === "Escape") setEditingLength(false); }}275+                    onBlur={commitLength}276+                  />277+                </Show>229278               </div>230279               <input231280                 type="range"

view file

src/popup/styles/popup.css+16 −0
@@ -3125,6 +3125,22 @@31253125   font-family: "IBM Plex Mono", monospace;31263126   font-size: 0.75rem; color: var(--peach-accent);31273127 }3128+.peach-pwgen-len-num--edit {3129+  cursor: text;3130+  border-bottom: 1px dotted color-mix(in srgb, var(--peach-accent) 50%, transparent);3131+}3132+.peach-pwgen-len-input {3133+  font-family: "IBM Plex Mono", monospace;3134+  font-size: 0.75rem;3135+  color: var(--peach-accent);3136+  background: transparent;3137+  border: none;3138+  border-bottom: 1px solid var(--peach-accent);3139+  outline: none;3140+  width: 32px;3141+  text-align: right;3142+  padding: 0;3143+}31283144 .peach-pwgen-slider { width: 100%; accent-color: var(--peach-accent); cursor: pointer; height: 2px; }31293145 .peach-pwgen-toggles { display: flex; flex-direction: column; }31303146 .peach-pwgen-charset-pills {

view file