npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sanity/block-insert-picker

v1.0.4

Published

Slash-command block-insert picker and markdown input rules for Portable Text fields in Sanity Studio

Readme

@sanity/block-insert-picker

Slash-command block-insert picker and markdown input rules for Portable Text fields in Sanity Studio.

Type / at the start of a line (or press Cmd/Ctrl + / anywhere) to open a caret-anchored menu of every object block the field's schema allows — searchable by title, trigger, and alias keywords, grouped into sections, keyboard-first. Selecting an item resolves the member type's initial value, inserts the block as a single undo step, and opens it for editing. Optional markdown input rules give the heaviest block types an even faster path, for example ```ts + space straight into a code block.

Installation

npm install @sanity/block-insert-picker

Requires sanity v5.6 or later.

Usage

Attach the picker to a Portable Text array type via components.portableText.plugins. Zero config is the intended call — the picker detects the array it is mounted on and derives its items from that array's members, so it only ever offers blocks the field accepts:

import {blockInsertPicker} from '@sanity/block-insert-picker'
import {defineType} from 'sanity'

export const content = defineType({
  name: 'content',
  type: 'array',
  of: [{type: 'block'}, {type: 'callout'}, {type: 'codeBlock'}],
  components: {
    portableText: {
      plugins: blockInsertPicker(),
    },
  },
})

Titles, icons, and descriptions come from each member's schema type (with the same fallbacks Studio's built-in insert menu uses), and detection handles aliased members ({type: 'image', name: 'photo'}) and inline-declared members with full fidelity.

When an array derives zero items — its only member is the text block — and no inputRules are configured, the picker disables itself: no behaviors register and / inserts plain text (with a console.warn in dev builds). Items appended via resolveItems (or configured inputRules) re-enable it, so a custom-command-only picker on a text-only field works.

Curating items

The optional items metadata curates the derived items — slash triggers, alias keywords, section grouping, badges, per-item visibility, and rank (array order). Entries match a member's name or any name in its resolved type chain, and a curated description wins over the schema type's:

blockInsertPicker({
  items: [
    {
      type: 'codeBlock',
      trigger: '/code',
      keywords: ['snippet', 'syntax'],
      group: 'Code',
      description: 'Syntax-highlighted code sample',
    },
    {
      type: 'callout',
      trigger: '/callout',
      keywords: ['note', 'warning', 'tip'],
      group: 'Callouts',
    },
    {type: 'legacyEmbed', hidden: true},
  ],
})

Members without an entry still get picker items, appended in schema order. Entries whose type matches no member log a dev-mode warning.

Presets for well-known blocks

Members whose type resolves to a well-known name — image, file, code (@sanity/code-input), table, color, latex, mux.video, sanity.video — get default triggers and search keywords out of the box. Presets never add items, never group, and always lose to your items metadata. Opt out with presets: false.

Markdown input rules

inputRules adds typed transforms that replace markdown-style text with an inserted block — one undo step, and the block opens for editing just like a picker insert. Rules are opt-in; two factories cover the common cases:

import {blockInsertPicker, blockquoteRule, codeFenceRule} from '@sanity/block-insert-picker'

blockInsertPicker({
  inputRules: [
    // "```lang" + space inserts a code block with the language resolved
    codeFenceRule({
      blockType: 'codeBlock',
      defaultLanguage: 'typescript',
      languages: [
        {value: 'typescript', aliases: ['ts'], filename: 'index.ts'},
        {value: 'javascript', aliases: ['js'], filename: 'index.js'},
      ],
      createValue: ({language, filename}) => ({
        language,
        ...(filename ? {filename} : {}),
      }),
    }),
    // "> " at the start of a block inserts a quote/callout
    blockquoteRule({
      blockType: 'callout',
      createValue: () => ({tone: 'info'}),
    }),
  ],
})

createValue builds the inserted block's fields synchronously from the resolved fence language (and optional tab filename), shaped for your schema. Each rule's blockType resolves against the array's members by name or resolved type chain (aliased members included; the inserted _type is always the member name); rules matching nothing are ignored. For fully custom transforms, pass a {pattern, blockType, buildValue} config directly. A ready-made wellKnownInputRules bundle covers @sanity/code-input's code type: inputRules: [...wellKnownInputRules].

Reacting to inserts

onInsert fires after every successful insert, from either path:

blockInsertPicker({
  onInsert: ({blockKey, blockType, via, mode, query}) => {
    // via is 'picker' or 'inputRule'; mode and query are picker-only
  },
})

Escape hatches

For anything the declarative options don't cover:

  • resolveItems — a function over the fully-presented item list: reorder, remove, relabel, or append items. Appended items can carry a custom action that runs your code instead of inserting a block:

    blockInsertPicker({
      resolveItems: (items, {schemaType}) => [
        ...items,
        {
          id: 'ai-draft',
          title: 'Draft with AI',
          action: {type: 'custom', onSelect: ({editor}) => startDraft(editor)},
        },
      ],
    })
  • filter — replaces the built-in matching (case-insensitive substring over title, keywords, and description, plus trigger prefixes). It receives the bare query in both modes; the slash-mode / prefix is stripped.

  • labels — overrides any user-facing string in the picker chrome (header, empty state, footer hints, error toast), for reworded or translated UI.

  • shortcut: false — disables the Cmd/Ctrl + / shortcut; openOnInsert: false — keeps inserted blocks closed (also available per item via metadata).

  • BlockInsertPicker / MarkdownInputRules — the underlying components, exported for hosts composing their own components.portableText.plugins chain, along with the pure derivePickerItems and filterPickerItems utilities.

  • arrayTypeName — names the array type explicitly, for environments where the member-schema context is unavailable. Normally unnecessary.

Keyboard reference

| Key | Action | | ------------------ | -------------------------------------------------- | | / at line start | Open the picker; keep typing to filter | | Cmd/Ctrl + / | Open the picker anywhere; type to filter privately | | / | Move the highlight | | Enter | Insert the highlighted block | | Escape | Dismiss |

License

MIT © Sanity.io