Summary
puter.ui.showFontPicker(defaultFont) and showFontPicker({ defaultFont }) preselect the font on websites but not inside Puter apps, and the string form never resolves at all on the desktop.
Why. Three things in the desktop path:
- The
showFontPickerIPC handler assignedwindow_optionsontoevent.data.optionswithout first normalizing a string argument, so the documentedshowFontPicker('Georgia')form threw on property assignment and the app never receivedfontPicked. TheshowColorPickerhandler right below already normalizes strings. UIWindowFontPickeronly readoptions.default, sodefaultFont(the documented option) anddefaultValue(the alias the color picker accepts) were ignored.onAppend: function (window)shadowed the globalwindow, sowindow.scrollParentToChild(...)threw whenever a font actually was preselected and the Select button handlers were never attached. This was unreachable before because preselection never matched.
What. IPC normalizes a string to { defaultFont } the same way the color picker does. The picker window resolves defaultValue ?? defaultFont ?? default (same precedence as UIWindowColorPicker) and matches the name case-insensitively, as the puter.js PuterFontPicker web component already does, so both environments behave the same. The onAppend parameter is renamed so the global is reachable. The SDK standalone fallback accepts defaultValue too, the JSDoc mirrors showColorPicker, and the docs page documents the options object and the return value.
Testing
- New Playwright spec
tests/e2e/specs/showFontPicker.spec.jswith fixturefont-picker.html, covering the string,{ defaultFont }and lowercase{ defaultValue }forms in an app: the picker window opens, exactly one.font-selector-activeentry isGeorgia, and Select resolves{ fontFamily: 'Georgia' }in the app. All 6 cases (chromium and mobile projects) fail before the fix and pass after. npm run check:puterjs:typespasses.- Verified manually on a local
npm startdesktop.
Activity
5Thanks for this. I looked at the same bug and found a few gaps you might want to cover here:
- Cancel result isn't in the types or docs. If the user closes the picker without choosing, the promise resolves
falseinside Puter andnullon a website. I checked both against a local Puter. The JSDoc still saysPromise<{ fontFamily: string }>, the Return value section doesn't mention cancelling, and the docs example (andplayground/examples/ui-show-font-picker.html) readsfont.fontFamilywithout checking, which throws onnull. - No
@overloadblocks. AGENTS.md asks for one@overloadper call form on public puter.js methods, soshowFontPicker(defaultFont?: string)andshowFontPicker(options?: FontPickerOptions). - Docs don't give the alias order. They say
defaultValueanddefaultare aliases, but in the codedefaultValuewins overdefaultFont. Stating the order would help. - The test doesn't check scrolling. Georgia sits in the middle of the list. Preselecting a font near the end (e.g. Verdana) and asserting
toBeInViewport()on.font-selector-activewould cover thescrollParentToChildpath theonAppendfix restores. A case that closes the window and expectsfalsewould cover point 1.
Thanks, I checked each point against the code and all four hold. Addressed in 31b9bb5:
- Cancel result. Confirmed: the desktop window resolves
falseon close and IPC forwards it as-is, while the web component emitsnull. I kept the runtime as it is (changing either value would break callers that already check for it) and made the types and docs tell the truth instead: the return type is nowPromise<{ fontFamily: string } | false | null>, the Return value section states both cases, and the docs example and playground example guard the result before readingfontFamily. @overloadblocks. Added one for the string form and one for the options form, following thelaunchApppattern in the same file.npm run check:puterjs:typesis clean.- Alias order. Documented:
defaultValue, thendefaultFont, thendefault, in both the JSDoc and the docs page. - Tests. Added a
Verdanacase assertingtoBeInViewport()on the active entry, and a close-without-selecting case expectingfalse. I verified the scroll assertion is meaningful by removing theonAppendbody locally: that test fails with viewport ratio 0 and passes with it restored. Spec is at 10/10 across both Playwright projects.
All committers have signed the CLA.