--- title: "The block browser" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{The block browser} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include=FALSE} knitr::opts_chunk$set(eval = FALSE, comment = "#>") ``` `blockr.ui::block_browser_ui()` is a card-list block picker designed to live inside the [sidebar primitive](sidebar.html). It replaces the legacy single-select form used by `blockr.dock`'s add / append / prepend block flows. Each card represents a registered block (one row of `blockr.core::available_blocks()`), grouped by category and filterable with the search bar. ## Adding a block Adding is single-shot and works two ways: * **Click the card body** to add the block immediately with sensible defaults - a freshly-generated unique id, the block's default title, and (for append / prepend) a default link and input port. * **Open the card** with its chevron to tweak the id, title, link id and input port first, then click the in-card add button. Either way the browser publishes a single Shiny input `_block_commit` carrying the block to create. ## Minimal example ```{r} library(shiny) library(blockr.ui) library(blockr.core) board <- new_board(blocks = list(src = new_dataset_block())) ui <- fluidPage( actionButton("open", "Add block"), sidebar_ui("panel", side = "right", width = "420px"), verbatimTextOutput("spec") ) server <- function(input, output, session) { observeEvent(input$open, { show_sidebar( "panel", title = "Add new block", ui = block_browser_ui(session$ns, board, mode = "add") ) }) observeEvent(input$add_block_commit, { str(input$add_block_commit) }) output$spec <- renderPrint({ spec <- input$add_block_commit if (is.null(spec)) cat("(no commit yet)") else str(spec) }) } shinyApp(ui, server) ``` ## The commit spec The `_block_commit` input is a single block to create: ```r list( type = "dataset_block", id = "intimate_hind", # unique, avoids the board's existing ids title = NULL, # NULL -> the block keeps its default title link_id = NULL, # set for append / prepend block_input = NULL, # set for append (the new block's input port) target_input = NULL # set for prepend into a multi-input target ) ``` Fields not applicable to the current mode are `NULL` (R reads JS's `null` as `NULL`). The action handler turns this into a single `update()` call against the board. ## Unique ids and repeated adds The suggested `id` (and `link_id`) defaults are generated avoiding the board's existing block / link ids. When the action handler re-renders the browser with the updated board after each add (e.g. while the sidebar is pinned), the next suggestion is fresh. This means clicking the same card several times produces several distinct blocks - the simple way to, say, drop three dataset blocks onto the board. ## Per-mode fields The per-card form shows only the fields relevant to the mode: | Mode | Fields | |-----------|------------------------------------------------------------| | `add` | `id`, `title` | | `append` | `id`, `title`, `link_id`, `block_input` | | `prepend` | `id`, `title`, `link_id`, `target_input` (only if arity>1) | For `prepend`, `target_input` is shown only when the target block has more than one input slot (e.g. a merge block, arity 2); arity-1 and variadic targets hide it. ## Search The search bar does a case-insensitive substring match against each card's `name + description + package + category`. Empty category sections collapse automatically. (A future iteration may replace this with an AI-assisted search that maps a natural-language question to candidate blocks - see the change's design notes.)