(renderer)
| 267 | } |
| 268 | |
| 269 | function buildView(renderer) { |
| 270 | return (state) => |
| 271 | renderer(state, { |
| 272 | onIncrement: () => { |
| 273 | updateState((prev) => ({ ...prev, count: prev.count + 1 })); |
| 274 | }, |
| 275 | onDecrement: () => { |
| 276 | updateState((prev) => ({ ...prev, count: prev.count - 1 })); |
| 277 | }, |
| 278 | onNameInput: (value) => { |
| 279 | updateState((prev) => ({ ...prev, name: value })); |
| 280 | }, |
| 281 | onNotesInput: (value) => { |
| 282 | updateState((prev) => Object.freeze({ ...prev, notes: value })); |
| 283 | }, |
| 284 | onCodeEditorChange: (lines, cursor) => { |
| 285 | updateState((prev) => { |
| 286 | const normalizedLines = splitCodeDraft(joinCodeLines(lines)); |
| 287 | const normalizedCursor = clampCodeCursor(normalizedLines, cursor); |
| 288 | const nextDraft = joinCodeLines(normalizedLines); |
| 289 | return Object.freeze({ |
| 290 | ...prev, |
| 291 | codeDraft: nextDraft, |
| 292 | codeLines: normalizedLines, |
| 293 | codeCursor: normalizedCursor, |
| 294 | bannerDraft: extractBannerFromSnippet(nextDraft, prev.bannerDraft), |
| 295 | }); |
| 296 | }); |
| 297 | }, |
| 298 | onCodeEditorSelectionChange: (selection) => { |
| 299 | updateState((prev) => |
| 300 | Object.freeze({ |
| 301 | ...prev, |
| 302 | codeSelection: selection ?? null, |
| 303 | }), |
| 304 | ); |
| 305 | }, |
| 306 | onCodeEditorScroll: (scrollTop, scrollLeft) => { |
| 307 | const nextScrollTop = Number.isFinite(scrollTop) ? Math.max(0, Math.floor(scrollTop)) : 0; |
| 308 | const nextScrollLeft = Number.isFinite(scrollLeft) |
| 309 | ? Math.max(0, Math.floor(scrollLeft)) |
| 310 | : 0; |
| 311 | updateState((prev) => { |
| 312 | if (prev.codeScrollTop === nextScrollTop && prev.codeScrollLeft === nextScrollLeft) { |
| 313 | return prev; |
| 314 | } |
| 315 | return Object.freeze({ |
| 316 | ...prev, |
| 317 | codeScrollTop: nextScrollTop, |
| 318 | codeScrollLeft: nextScrollLeft, |
| 319 | }); |
| 320 | }); |
| 321 | }, |
| 322 | onSaveBannerToFile: () => { |
| 323 | void saveBannerToWidgetFile(); |
| 324 | }, |
| 325 | onCloseFeedbackModal: () => { |
| 326 | closeFeedbackModal(); |
no test coverage detected