@sanity/block-insert-picker 0.0.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +150 -43
- package/dist/index.d.ts +385 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1195 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["PickerItem","PickerItemMetadata","PickerItemsContext","typeNameChain","memberType","name","type","names","current","push","undefined","derivePickerItems","context","metadata","memberTypes","map","schemaIndex","chain","nameRank","findIndex","entry","rank","includes","Number","MAX_SAFE_INTEGER","filter","hidden","sort","a","b","action","blockType","const","badge","description","group","id","keywords","openOnInsert","title","trigger","unknownMetadataTypes","known","Set","flatMap","has","PickerItem","filterPickerItems","items","query","queryLower","toLowerCase","bareQuery","startsWith","slice","filter","item","bareTrigger","trigger","replace","title","includes","description","keywords","some","kw","PickerItem","PickerSection","group","items","flattenSections","sections","flatMap","section","groupPickerItems","order","byGroup","Map","item","key","bucket","get","set","push","map","Editor","EditorSelection","EditorSnapshot","defineBehavior","raise","blockOffsetsToSelection","getTextBlockText","isTextBlock","PickerMode","InsertGuardResult","anchor","block","InsertPickerItemPayload","cleanup","placement","anchorBlockKey","_key","_type","Record","mode","query","createInsertBehavior","actions","_","at","type","select","guard","event","snapshot","anchorBlockExists","context","value","some","candidate","offsets","offset","path","focus","resolveQueryCleanup","const","on","sendInsertPickerItem","editor","payload","send","CleanupQueryPayload","Omit","createCleanupQueryBehavior","NonNullable","sendCleanupQuery","length","anchorBlock","find","schema","startsWith","Editor","sendInsertPickerItem","PickerMode","InsertContext","blockType","mode","editor","anchorBlockKey","query","keyGenerator","initialValue","Record","onInsertedKey","key","insertPickerItem","ctx","blockKey","block","_key","_type","BlockInsertPickerLabels","title","noMatches","positionAnnouncement","ungroupedSection","footerNavigate","footerInsert","footerDismiss","footerAnywhere","insertError","insertAnchorRemoved","DEFAULT_LABELS","resolveLabels","overrides","Partial","formatNoMatches","labels","query","replace","formatPosition","index","count","String","ContextType","useContext","useMemo","ObjectSchemaType","useSchema","PortableTextMemberSchemaTypesContext","PickerItemsContext","MemberSchemaTypes","NonNullable","usePickerItemsContext","arrayTypeName","$","_c","memberSchemaTypes","schema","t0","bb0","t1","blockObjects","portableText","memberTypes","schemaType","arrayType","get","undefined","jsonType","of","filter","_temp","member","isTextBlockMember","memberType","name","type","current","useCallback","useContext","useEffect","useRef","useFormCallbacks","PortableTextMemberItemsContext","useOpenBlockOnInsert","$","_c","memberItems","onPathOpen","onSetPathCollapsed","pendingKeyRef","t0","t1","key","current","item","find","m","member","path","t2","Symbol","for","blockKey","defineBehavior","effect","forward","BehaviorEvent","BehaviorGuard","getBlockTextBefore","getFirstBlock","getFocusBlock","getFocusTextBlock","isSelectionCollapsed","PickerIntent","PickerState","GuardResult","blockEvent","intent","PickerBehaviorRefs","onIntent","getState","isShortcutEnabled","createPickerBehavior","guard","event","snapshot","state","mode","type","text","focus","anchorBlockKey","node","_key","query","originEvent","key","metaKey","ctrlKey","fallback","anchorBlock","length","unit","slice","delta","actions","payload","guardResponse","sideEffect","on","PickerIntent","PickerState","pickerReducer","state","intent","type","mode","highlightedIndex","delta","anchorBlockKey","query","index","unhandled","effect","raise","blockOffsetsToSelection","defineInputRule","InputRule","KeyGenerator","MarkdownInputRuleConfig","pattern","RegExp","blockType","buildValue","context","matchText","keyGenerator","Record","BuildRulesDeps","onInserted","block","InsertableBlock","_key","_type","createMarkdownInputRules","allowedBlockTypes","rules","ReadonlySet","filter","config","has","map","createInsertRule","CODE_FENCE_PATTERN","BLOCKQUOTE_PATTERN","LanguageEntry","value","aliases","filename","blockquoteRule","options","createValue","codeFenceRule","languages","defaultLanguage","language","normalizeFenceLanguage","fenceLanguageFromMatch","find","entry","undefined","replace","trim","raw","token","lower","toLowerCase","some","alias","actions","event","snapshot","match","matches","text","at","offsets","anchor","targetOffsets","focus","selection","type","placement","select","on","typeNameChain","codeFenceRule","MarkdownInputRuleConfig","PickerItem","PickerItemMetadata","PickerItemsContext","standardBlockPresets","keywords","trigger","type","wellKnownInputRules","blockType","createValue","language","applyPresetMetadata","items","context","presets","presetByType","Map","map","preset","item","action","undefined","memberType","memberTypes","find","candidate","name","get","Boolean","BlockElementIcon","ComponentType","PickerItem","ItemPresentation","title","icon","description","SchemaTypeLike","name","type","to","ReadonlyArray","resolveItemPresentation","item","schemaType","action","blockType","id","upperFirst","value","charAt","toUpperCase","slice","useEditor","Box","Card","Flex","Hotkeys","Popover","Stack","Text","useToast","CSSProperties","useEffect","useId","useLayoutEffect","useMemo","useReducer","useRef","useState","useResolveInitialValueForType","useSchema","SchemaType","derivePickerItems","unknownMetadataTypes","filterPickerItems","flattenSections","groupPickerItems","createCleanupQueryBehavior","createInsertBehavior","sendCleanupQuery","insertPickerItem","BlockInsertPickerLabels","formatNoMatches","formatPosition","resolveLabels","usePickerItemsContext","useOpenBlockOnInsert","createPickerBehavior","pickerReducer","applyPresetMetadata","resolveItemPresentation","PickerInsertEvent","PickerIntent","PickerItem","PickerItemMetadata","PickerItemsContext","PickerItemsResolver","PickerState","BlockInsertPickerProps","items","arrayTypeName","resolveItems","filter","query","labels","Partial","onInsert","event","openOnInsert","shortcut","presets","BlockInsertPicker","labelOverrides","editor","openBlockOnInsert","itemsContext","schema","resolveInitialValueForType","toast","instanceId","listboxId","optionId","id","pickerItems","derived","presented","map","item","action","type","schemaType","memberTypeFor","blockType","presentation","Object","assign","description","icon","title","hasItems","length","warnedRef","context","empty","unknown","process","env","warned","current","console","warn","join","state","dispatch","mode","stateRef","shortcutRef","open","filterItems","filterQuery","bareQuery","sections","filtered","sectionOffsets","offsets","total","section","push","showGroupHeaders","insertInFlightRef","insertItemAtIndex","Exclude","idx","visible","clamped","Math","max","min","chosen","anchorBlockKey","onSelect","closePicker","initialValue","Record","undefined","snapshot","getSnapshot","anchorStillExists","value","some","b","_key","closable","insertAnchorRemoved","status","insertError","keyGenerator","onInsertedKey","key","blockKey","via","error","Error","message","String","selectItemAtIndex","handleIntent","intent","lastIndex","base","highlightedIndex","next","delta","index","handleIntentRef","behavior","getState","isShortcutEnabled","onIntent","unregisterPicker","registerBehavior","unregisterInsert","unregisterCleanup","highlightedItem","announcement","Boolean","cursorRect","setCursorRect","DOMRect","rect","dom","getSelectionRect","x","y","width","height","blockRect","getStartBlockElement","getBoundingClientRect","popoverContentRef","HTMLDivElement","handlePointerDown","PointerEvent","target","Node","contains","editorElement","getEditorElement","handleFocusOut","Event","FocusEvent","relatedTarget","document","addEventListener","removeEventListener","highlightedRowRef","lastPointerRef","highlightOnPointerMove","last","scrollIntoView","block","cursorElement","HTMLElement","preventFocusSteal","display","flexDirection","maxHeight","minWidth","SR_ONLY","letterSpacing","textTransform","flex","minHeight","overflowY","sectionIndex","sectionLabel","group","ungroupedSection","sectionKey","rows","rowIndex","Icon","isHighlighted","clientX","clientY","cursor","alignItems","justifyContent","badge","trigger","footerNavigate","footerInsert","footerDismiss","OPEN_MODIFIER","footerAnywhere","FooterHint","t0","$","_c","keys","label","t1","t2","t3","get","name","member","memberTypes","find","candidate","startsWith","slice","preventDefault","border","clipPath","margin","overflow","padding","position","whiteSpace","IS_APPLE_PLATFORM","navigator","test","platform","userAgent","useEditor","defineInputRuleBehavior","useEffect","useLayoutEffect","useMemo","useRef","typeNameChain","createMarkdownInputRules","MarkdownInputRuleConfig","usePickerItemsContext","useOpenBlockOnInsert","PickerInsertEvent","MarkdownInputRulesProps","arrayTypeName","rules","onInsert","event","openOnInsert","MarkdownInputRules","t0","$","_c","t1","undefined","editor","itemsContext","openBlockOnInsert","t2","memberTypes","t3","t4","rule","member","find","candidate_0","candidate","name","blockType","includes","flatMap","resolvedRules","onInsertedRef","_temp","current","block","_key","blockKey","_type","via","t5","t6","inputRules","allowedBlockTypes","Set","map","_temp2","keyGenerator","getSnapshot","context","onInserted","block_0","length","registerBehavior","behavior","rule_0","ComponentType","PortableTextPluginsProps","BlockInsertPicker","MarkdownInputRuleConfig","BlockInsertPickerLabels","MarkdownInputRules","PickerInsertEvent","PickerItem","PickerItemMetadata","PickerItemsResolver","BlockInsertPickerConfig","items","resolveItems","inputRules","filter","query","labels","Partial","onInsert","event","openOnInsert","shortcut","presets","arrayTypeName","blockInsertPicker","config","BlockInsertPickerPlugins","props","renderDefault","length"],"sources":["../src/deriveItems.ts","../src/filterItems.ts","../src/groupItems.ts","../src/insertBehavior.ts","../src/insertPickerItem.ts","../src/labels.ts","../src/memberSchemaTypes.ts","../src/openBlockOnInsert.ts","../src/pickerBehavior.ts","../src/pickerReducer.ts","../src/inputRules.ts","../src/presets.ts","../src/resolveItemPresentation.ts","../src/blockInsertPicker.tsx","../src/markdownInputRules.tsx","../src/plugin.tsx"],"sourcesContent":["import type {PickerItem, PickerItemMetadata, PickerItemsContext} from './types'\n\n/**\n * The member's own name plus every name up its compiled `type` chain, most\n * specific first: `{type: 'image', name: 'photo'}` yields `['photo',\n * 'image', ...]`. Metadata and presets match against this chain so curation\n * can target either the member name or the underlying type name.\n */\nexport function typeNameChain(memberType: {\n name: string\n type?: {name: string; type?: unknown} | undefined\n}): string[] {\n const names: string[] = []\n let current: {name: string; type?: unknown} | undefined = memberType\n while (current && typeof current.name === 'string') {\n names.push(current.name)\n current =\n current.type && typeof current.type === 'object' && 'name' in current.type\n ? // oxlint-disable-next-line no-unsafe-type-assertion\n (current.type as {name: string; type?: unknown})\n : undefined\n }\n return names\n}\n\n/**\n * Derives picker items from a portable-text array's insertable member types\n * (see PickerItemsContext), so the picker automatically covers every object\n * block the schema allows. The optional metadata list curates triggers,\n * keywords, grouping, badges, visibility, and descriptions per member type;\n * its array order is the sort rank (see PickerItemMetadata). Titles and\n * icons intentionally stay unresolved here: BlockInsertPicker resolves\n * presentation from the member schema type, which carries member-level\n * config (a member-specific icon, a per-member title override).\n */\nexport function derivePickerItems(\n context: PickerItemsContext,\n metadata: readonly PickerItemMetadata[] = [],\n): PickerItem[] {\n return context.memberTypes\n .map((memberType, schemaIndex) => {\n const chain = typeNameChain(memberType)\n // The member's own name wins over a resolved-chain match, so an entry\n // for `photo` beats an entry for `image` on `{type: 'image', name:\n // 'photo'}` — but whichever matches, its array position is the rank.\n const nameRank = metadata.findIndex((entry) => entry.type === memberType.name)\n const rank =\n nameRank === -1 ? metadata.findIndex((entry) => chain.includes(entry.type)) : nameRank\n const entry = rank === -1 ? undefined : metadata[rank]\n return {\n entry,\n name: memberType.name,\n rank: rank === -1 ? Number.MAX_SAFE_INTEGER : rank,\n schemaIndex,\n }\n })\n .filter(({entry}) => !entry?.hidden)\n .sort((a, b) => a.rank - b.rank || a.schemaIndex - b.schemaIndex)\n .map(({entry, name}) => ({\n action: {blockType: name, type: 'insertBlock' as const},\n badge: entry?.badge,\n description: entry?.description,\n group: entry?.group,\n id: name,\n keywords: entry?.keywords,\n openOnInsert: entry?.openOnInsert,\n title: '',\n trigger: entry?.trigger,\n }))\n}\n\n/**\n * Metadata entries whose `type` matches neither a member name nor any name\n * in a member's resolved type chain — almost always a typo. Surfaced as a\n * dev-mode warning by BlockInsertPicker.\n */\nexport function unknownMetadataTypes(\n context: PickerItemsContext,\n metadata: readonly PickerItemMetadata[],\n): string[] {\n const known = new Set(context.memberTypes.flatMap((memberType) => typeNameChain(memberType)))\n return metadata.map((entry) => entry.type).filter((type) => !known.has(type))\n}\n","import type {PickerItem} from './types'\n\nexport function filterPickerItems(\n items: readonly PickerItem[],\n query: string,\n): readonly PickerItem[] {\n if (query === '' || query === '/') return items\n\n const queryLower = query.toLowerCase()\n // Slash-mode queries always carry the leading \"/\", which titles and\n // keywords never contain — strip it before substring matching.\n const bareQuery = queryLower.startsWith('/') ? queryLower.slice(1) : queryLower\n\n return items.filter((item) => {\n // Triggers match with the slash stripped from both sides so that bare\n // shortcut-mode queries (\"cta\") reach them, not just slash-mode ones.\n const bareTrigger = item.trigger?.toLowerCase().replace(/^\\//, '')\n if (bareTrigger && bareQuery !== '' && bareTrigger.startsWith(bareQuery)) return true\n if (bareQuery === '') return false\n if (item.title.toLowerCase().includes(bareQuery)) return true\n if (item.description?.toLowerCase().includes(bareQuery)) return true\n if (item.keywords?.some((kw) => kw.toLowerCase().includes(bareQuery))) return true\n return false\n })\n}\n","import type {PickerItem} from './types'\n\ntype PickerSection = {\n /** Category label, or null for items that carry no group. */\n group: null | string\n items: readonly PickerItem[]\n}\n\n/**\n * Flattens sections back into the single index space that keyboard navigation,\n * selection, and scroll-into-view all share. Rendering the sections and\n * indexing this array must stay derived from the same `groupPickerItems` call\n * so Enter inserts exactly the highlighted row.\n */\nexport function flattenSections(sections: readonly PickerSection[]): readonly PickerItem[] {\n return sections.flatMap((section) => section.items)\n}\n\n/**\n * Partitions items into sections by their `group`, preserving the incoming\n * order within each section and ordering the sections by first appearance.\n *\n * Because the caller feeds rank-ordered items (see derivePickerItems), the\n * first-appearance rule places the section holding the most-used block first,\n * without a separate ordering constant to drift out of sync. Items without a\n * group collapse into a single `group: null` section (e.g. a curated `items`\n * prop), so the flat/ungrouped case stays a no-op reordering.\n */\nexport function groupPickerItems(items: readonly PickerItem[]): PickerSection[] {\n const order: (null | string)[] = []\n const byGroup = new Map<null | string, PickerItem[]>()\n for (const item of items) {\n const key = item.group ?? null\n let bucket = byGroup.get(key)\n if (!bucket) {\n bucket = []\n byGroup.set(key, bucket)\n order.push(key)\n }\n bucket.push(item)\n }\n return order.map((key) => ({group: key, items: byGroup.get(key)!}))\n}\n","import type {Editor, EditorSelection, EditorSnapshot} from '@portabletext/editor'\nimport {defineBehavior, raise} from '@portabletext/editor/behaviors'\nimport {blockOffsetsToSelection, getTextBlockText, isTextBlock} from '@portabletext/editor/utils'\n\nimport type {PickerMode} from './types'\n\ntype InsertGuardResult = {\n anchor: EditorSelection\n block: InsertPickerItemPayload['block']\n cleanup: EditorSelection\n placement: 'after' | 'auto'\n}\n\ntype InsertPickerItemPayload = {\n anchorBlockKey: string\n block: {_key: string; _type: string} & Record<string, unknown>\n mode: PickerMode\n query: string\n}\n\n/**\n * Performs the picker insertion as a single behavior action set so the whole\n * operation is one undo step, and cleans up the typed \"/query\" text with\n * delete.text over exactly that range (never delete.block) so text that\n * already existed in the anchor block can't be destroyed: the caret can sit\n * at offset 0 of a populated block and still open the picker.\n */\nexport function createInsertBehavior() {\n return defineBehavior<\n InsertPickerItemPayload,\n 'custom.blockInsertPicker.insert',\n InsertGuardResult\n >({\n actions: [\n (_, {anchor, block, cleanup, placement}) => [\n ...(cleanup ? [raise({at: cleanup, type: 'delete.text'})] : []),\n raise({\n block,\n placement,\n select: 'start',\n type: 'insert.block',\n // Pin the insert to the anchor block: the live selection may have\n // moved (e.g. input arriving during the select-time initial-value\n // await) and placement resolves relative to `at` when provided.\n ...(anchor ? {at: anchor} : {}),\n }),\n ],\n ],\n guard: ({event, snapshot}) => {\n const {anchorBlockKey, block, mode} = event\n const anchorBlockExists = snapshot.context.value.some(\n (candidate) => candidate._key === anchorBlockKey,\n )\n const anchor = anchorBlockExists\n ? blockOffsetsToSelection({\n offsets: {\n anchor: {offset: 0, path: [{_key: anchorBlockKey}]},\n focus: {offset: 0, path: [{_key: anchorBlockKey}]},\n },\n snapshot,\n })\n : null\n return {\n anchor,\n block,\n cleanup: resolveQueryCleanup(event, snapshot),\n placement: mode === 'slash' ? ('auto' as const) : ('after' as const),\n }\n },\n on: 'custom.blockInsertPicker.insert',\n })\n}\n\nexport function sendInsertPickerItem(editor: Editor, payload: InsertPickerItemPayload): void {\n editor.send({type: 'custom.blockInsertPicker.insert', ...payload})\n}\n\ntype CleanupQueryPayload = Omit<InsertPickerItemPayload, 'block'>\n\n/**\n * The query-cleanup half of the insert behavior on its own, for `custom`\n * picker actions that don't insert a block: the typed \"/query\" text still\n * leaves the document before the host's `onSelect` runs, under the same\n * only-if-unchanged guard as a real insert.\n */\nexport function createCleanupQueryBehavior() {\n return defineBehavior<\n CleanupQueryPayload,\n 'custom.blockInsertPicker.cleanupQuery',\n NonNullable<EditorSelection>\n >({\n actions: [(_, cleanup) => [raise({at: cleanup, type: 'delete.text'})]],\n guard: ({event, snapshot}) => resolveQueryCleanup(event, snapshot) ?? false,\n on: 'custom.blockInsertPicker.cleanupQuery',\n })\n}\n\nexport function sendCleanupQuery(editor: Editor, payload: CleanupQueryPayload): void {\n editor.send({type: 'custom.blockInsertPicker.cleanupQuery', ...payload})\n}\n\n/**\n * The selection spanning the typed \"/query\" text in the anchor block, when it\n * is safe to delete. Only slash mode leaves query text in the document, and\n * only when the anchor block still starts with the typed query; if it changed\n * underneath us (collaborator edit, uncaptured caret movement) the action is\n * still the user's intent, but nothing may be deleted.\n */\nfunction resolveQueryCleanup(\n event: {anchorBlockKey: string; mode: PickerMode; query: string},\n snapshot: EditorSnapshot,\n): EditorSelection {\n const {anchorBlockKey, mode, query} = event\n if (mode !== 'slash' || query.length === 0) return null\n const anchorBlock = snapshot.context.value.find((candidate) => candidate._key === anchorBlockKey)\n if (\n !anchorBlock ||\n !isTextBlock({schema: snapshot.context.schema}, anchorBlock) ||\n !getTextBlockText(anchorBlock).startsWith(query)\n ) {\n return null\n }\n return blockOffsetsToSelection({\n offsets: {\n anchor: {offset: 0, path: [{_key: anchorBlockKey}]},\n focus: {offset: query.length, path: [{_key: anchorBlockKey}]},\n },\n snapshot,\n })\n}\n","import type {Editor} from '@portabletext/editor'\n\nimport {sendInsertPickerItem} from './insertBehavior'\nimport type {PickerMode} from './types'\n\ntype InsertContext = {\n /** The `_type` of the block to insert — an `insertBlock` action's target. */\n blockType: string\n mode: PickerMode\n editor: Editor\n anchorBlockKey: string\n query: string\n keyGenerator: () => string\n initialValue?: Record<string, unknown>\n onInsertedKey?: (key: string) => void\n}\n\nexport function insertPickerItem(ctx: InsertContext): void {\n const blockKey = ctx.keyGenerator()\n // One custom event; the registered insert behavior performs the query\n // cleanup and the insertion in a single action set (single undo step).\n sendInsertPickerItem(ctx.editor, {\n anchorBlockKey: ctx.anchorBlockKey,\n block: {\n // Spread the resolved initial value first so the generated `_key` and\n // the target `_type` always win: Sanity's initial-value resolver sets\n // `_type` on object values, and a schema's initialValue could carry\n // stray meta keys. In this flow the resolved `_type` matches\n // `ctx.blockType` by construction, but ordering it last keeps the\n // insert correct even when that assumption doesn't hold.\n ...ctx.initialValue,\n _key: blockKey,\n _type: ctx.blockType,\n },\n mode: ctx.mode,\n query: ctx.query,\n })\n ctx.onInsertedKey?.(blockKey)\n}\n","/**\n * Every user-facing string in the picker chrome, centralized so hosts can\n * translate or reword them via the `labels` option (the same pattern\n * `@sanity/insert-menu` uses for its label overrides). Item titles and\n * descriptions are schema/metadata content, not chrome — localize those\n * through `items` or `resolveItems` instead.\n */\nexport type BlockInsertPickerLabels = {\n /** Popover header; also the listbox aria-label. */\n title: string\n /** Empty state; `{query}` is replaced with the typed filter text. */\n noMatches: string\n /**\n * Screen-reader position announcement for the highlighted row; `{index}`\n * and `{count}` are replaced with the 1-based position and list length.\n */\n positionAnnouncement: string\n /**\n * Section header for items without a `group`, shown only when grouped\n * sections are also present.\n */\n ungroupedSection: string\n /** Footer legend verbs. */\n footerNavigate: string\n footerInsert: string\n footerDismiss: string\n footerAnywhere: string\n /** Toast title when resolving a block's initial value fails. */\n insertError: string\n /**\n * Toast description when the block the picker was anchored to is deleted\n * before the insert completes.\n */\n insertAnchorRemoved: string\n}\n\nconst DEFAULT_LABELS: BlockInsertPickerLabels = {\n footerAnywhere: 'Anywhere',\n footerDismiss: 'Dismiss',\n footerInsert: 'Insert',\n footerNavigate: 'Navigate',\n insertAnchorRemoved: 'The block you were inserting into was removed',\n insertError: 'Could not insert block',\n noMatches: 'No matches for \"{query}\"',\n positionAnnouncement: '{index} of {count}',\n title: 'Insert block',\n ungroupedSection: 'Other blocks',\n}\n\nexport function resolveLabels(\n overrides: Partial<BlockInsertPickerLabels> | undefined,\n): BlockInsertPickerLabels {\n return overrides ? {...DEFAULT_LABELS, ...overrides} : DEFAULT_LABELS\n}\n\n/** Fills the `{query}` placeholder in the no-matches label. */\nexport function formatNoMatches(labels: BlockInsertPickerLabels, query: string): string {\n // Function replacement: a query containing replacement patterns (\"$&\")\n // must land verbatim, not be interpreted by String.replace.\n return labels.noMatches.replace('{query}', () => query)\n}\n\n/** Fills `{index}`/`{count}` in the screen-reader position announcement. */\nexport function formatPosition(\n labels: BlockInsertPickerLabels,\n index: number,\n count: number,\n): string {\n return labels.positionAnnouncement\n .replace('{index}', () => String(index))\n .replace('{count}', () => String(count))\n}\n","import {type ContextType, useContext, useMemo} from 'react'\nimport {type ObjectSchemaType, useSchema} from 'sanity'\nimport {PortableTextMemberSchemaTypesContext} from 'sanity/_singletons'\n\nimport type {PickerItemsContext} from './types'\n\n/**\n * Resolves the Portable Text array type and its insertable member types from\n * where this plugin renders — inside the PT input's `EditorProvider`.\n *\n * Primary source: Studio's own member-schema context, which the PT input\n * provides above the plugins slot. It carries the containing array type and\n * its non-text-block members as full Studio schema types, so aliased members\n * (`{type: 'image', name: 'photo'}`), inline-declared members, and arrays\n * defined inline on a field all resolve with member-level fidelity and no\n * configuration. Fallback: an explicit `arrayTypeName` looked up in the\n * workspace schema — the escape hatch for environments where the context is\n * unavailable. With neither, callers get `null` and must render nothing\n * (never an empty picker).\n *\n * Together with openBlockOnInsert.ts, this module is one of exactly two\n * importers of `sanity/_singletons` — an internal subpath with no stability\n * guarantee (the context exists since sanity 5.6.0, which the peer range\n * pins). The dependency stays quarantined here so it can be swapped for a\n * public API (an exported `usePortableTextMemberSchemaTypes`, or a\n * `schemaType` on `PortableTextPluginsProps`) in one place.\n */\n\n// The context's value type lives in @portabletext/sanity-bridge, which\n// consumer studios cannot resolve directly (it is sanity's own dependency) —\n// extract it from the context instead of importing the bridge.\ntype MemberSchemaTypes = NonNullable<ContextType<typeof PortableTextMemberSchemaTypesContext>>\n\nexport function usePickerItemsContext(arrayTypeName?: string): PickerItemsContext | null {\n const memberSchemaTypes: MemberSchemaTypes | null = useContext(\n PortableTextMemberSchemaTypesContext,\n )\n const schema = useSchema()\n\n return useMemo(() => {\n if (memberSchemaTypes) {\n return {\n memberTypes: memberSchemaTypes.blockObjects,\n schemaType: memberSchemaTypes.portableText,\n }\n }\n const arrayType = arrayTypeName ? schema.get(arrayTypeName) : undefined\n if (!arrayType || arrayType.jsonType !== 'array') return null\n return {\n memberTypes: arrayType.of.filter(\n (member): member is ObjectSchemaType =>\n member.jsonType === 'object' && !isTextBlockMember(member),\n ),\n schemaType: arrayType,\n }\n }, [arrayTypeName, memberSchemaTypes, schema])\n}\n\n/**\n * Whether a member resolves to the built-in text block: walk the compiled\n * `type` chain to its root and compare the root's name — the same algorithm\n * Studio's schema bridge uses to bucketize `of`. A literal `name === 'block'`\n * check would miss aliased text blocks (`{name: 'myBlock', type: 'block'}`)\n * and wrongly offer them as object inserts.\n */\nfunction isTextBlockMember(memberType: {\n name: string\n type?: {name: string; type?: unknown} | undefined\n}): boolean {\n let current: {name: string; type?: unknown} = memberType\n while (current.type && typeof current.type === 'object' && 'name' in current.type) {\n // oxlint-disable-next-line no-unsafe-type-assertion\n current = current.type as {name: string; type?: unknown}\n }\n return current.name === 'block'\n}\n","import {useCallback, useContext, useEffect, useRef} from 'react'\nimport {useFormCallbacks} from 'sanity'\nimport {PortableTextMemberItemsContext} from 'sanity/_singletons'\n\n/**\n * Opens a just-inserted block's editing UI (dialog/popover per the member's\n * config) once its member item mounts. An insert lands synchronously, but the\n * member item only exists on a later render — so callers schedule the key and\n * the effect opens it when it appears.\n *\n * Together with memberSchemaTypes.ts, this module is one of exactly two\n * importers of `sanity/_singletons` in this plugin: the subpath is internal\n * with no stability guarantee, so each dependency stays quarantined where it\n * can be swapped for a public API in one place. Consumers that need to react\n * to inserts without this internal should use the `onInsert` seam on the\n * plugin components instead.\n */\nexport function useOpenBlockOnInsert(): (blockKey: string) => void {\n const memberItems = useContext(PortableTextMemberItemsContext)\n const {onPathOpen, onSetPathCollapsed} = useFormCallbacks()\n const pendingKeyRef = useRef<null | string>(null)\n\n useEffect(() => {\n const key = pendingKeyRef.current\n if (!key) return\n const item = memberItems.find((m) => m.member.key === key)\n if (item) {\n onPathOpen(item.member.item.path)\n onSetPathCollapsed(item.member.item.path, false)\n pendingKeyRef.current = null\n }\n }, [memberItems, onPathOpen, onSetPathCollapsed])\n\n // Stable identity: callers hold this in effect dependency arrays, so it must\n // keep a constant reference — an unstable return would re-run (and re-register\n // behaviors in) every effect that lists it, on every render. The empty-dep\n // `useCallback` states that contract explicitly rather than relying on the\n // React Compiler to infer it.\n return useCallback((blockKey: string) => {\n pendingKeyRef.current = blockKey\n }, [])\n}\n","import {defineBehavior, effect, forward} from '@portabletext/editor/behaviors'\nimport type {BehaviorEvent, BehaviorGuard} from '@portabletext/editor/behaviors'\nimport {\n getBlockTextBefore,\n getFirstBlock,\n getFocusBlock,\n getFocusTextBlock,\n isSelectionCollapsed,\n} from '@portabletext/editor/selectors'\n\nimport type {PickerIntent, PickerState} from './types'\n\ntype GuardResult = {\n // true = block the native/default editor handling; false = allow it to proceed\n blockEvent: boolean\n intent: PickerIntent\n}\n\ntype PickerBehaviorRefs = {\n onIntent: (intent: PickerIntent) => void\n getState: () => PickerState\n /**\n * Whether Cmd/Ctrl+/ may open the picker. Read per keystroke (not captured\n * at registration) so the host toggling `shortcut` doesn't force a\n * re-registration, which would re-sort the editor's behavior chain.\n */\n isShortcutEnabled: () => boolean\n}\n\nexport function createPickerBehavior({getState, isShortcutEnabled, onIntent}: PickerBehaviorRefs) {\n const guard: BehaviorGuard<BehaviorEvent, GuardResult> = ({event, snapshot}) => {\n const state = getState()\n\n // Picker is closed — only the two open triggers can fire.\n if (state.mode === 'closed') {\n if (event.type === 'insert.text' && event.text === '/') {\n const focus = getFocusTextBlock(snapshot)\n if (!focus || !isSelectionCollapsed(snapshot) || getBlockTextBefore(snapshot) !== '') {\n return false\n }\n return {\n blockEvent: false,\n intent: {\n anchorBlockKey: focus.node._key,\n mode: 'slash',\n query: '/',\n type: 'open',\n } satisfies PickerIntent,\n }\n }\n if (\n event.type === 'keyboard.keydown' &&\n event.originEvent.key === '/' &&\n (event.originEvent.metaKey || event.originEvent.ctrlKey) &&\n isShortcutEnabled()\n ) {\n // For the shortcut mode, anchor to the focused block whether it is a\n // text block or a block object (image, callout); fall back to the\n // first block only when there is no selection at all (e.g. when\n // triggered via a toolbar button before the editor is DOM-focused).\n const focus = getFocusBlock(snapshot)\n const fallback = getFirstBlock(snapshot)\n const anchorBlock = focus ?? fallback\n if (!anchorBlock) return false\n return {\n blockEvent: true,\n intent: {\n anchorBlockKey: anchorBlock.node._key,\n mode: 'shortcut',\n query: '',\n type: 'open',\n } satisfies PickerIntent,\n }\n }\n return false\n }\n\n // Picker is open — capture editing/navigation events.\n if (event.type === 'insert.text') {\n if (state.mode === 'slash') {\n if (event.text === ' ') {\n // Space while open: close picker, let the space insert proceed.\n return {blockEvent: false, intent: {type: 'close'}}\n }\n // Character typed while in slash mode: update query; let the editor\n // insert the character into the document as well.\n return {\n blockEvent: false,\n intent: {query: state.query + event.text, type: 'updateQuery'},\n }\n }\n // Shortcut-mode type-to-filter: the query is picker-only state that\n // never entered the document, so capture the character (spaces\n // included — titles contain them) and block the insertion.\n return {\n blockEvent: true,\n intent: {query: state.query + event.text, type: 'updateQuery'},\n }\n }\n\n if (event.type === 'delete.backward') {\n if (state.mode === 'shortcut') {\n // Backspace edits the picker-only query, never the document.\n if (state.query.length === 0) {\n return {blockEvent: true, intent: {type: 'close'}}\n }\n return {\n blockEvent: true,\n intent: {\n // Word/line deletes clear the whole query rather than desyncing.\n query: event.unit === 'character' ? state.query.slice(0, -1) : '',\n type: 'updateQuery',\n },\n }\n }\n // Slash mode: the deletion proceeds in the document, so shrink the\n // query in sync. Deleting the opening \"/\" itself closes, and word/line\n // deletes can outrun the query — close and let them proceed.\n if (event.unit === 'character' && state.query.length > 1) {\n return {\n blockEvent: false,\n intent: {query: state.query.slice(0, -1), type: 'updateQuery'},\n }\n }\n return {blockEvent: false, intent: {type: 'close'}}\n }\n\n if (event.type === 'delete.forward') {\n // Forward delete edits content ahead of the caret, not the query;\n // close and let the deletion proceed in the editor normally.\n return {blockEvent: false, intent: {type: 'close'}}\n }\n\n if (event.type === 'keyboard.keydown') {\n const key = event.originEvent.key\n if (key === 'ArrowDown') {\n return {blockEvent: true, intent: {delta: 1, type: 'navigate'}}\n }\n if (key === 'ArrowUp') {\n return {blockEvent: true, intent: {delta: -1, type: 'navigate'}}\n }\n if (key === 'Enter') {\n return {blockEvent: true, intent: {type: 'select'}}\n }\n if (key === 'Escape') {\n return {blockEvent: true, intent: {type: 'close'}}\n }\n if (\n key === 'ArrowLeft' ||\n key === 'ArrowRight' ||\n key === 'Home' ||\n key === 'End' ||\n key === 'PageUp' ||\n key === 'PageDown'\n ) {\n // The caret is moving off the typed query; close and let the caret\n // move normally so the picker's query can't desync from the document.\n return {blockEvent: false, intent: {type: 'close'}}\n }\n }\n\n return false\n }\n\n return defineBehavior({\n actions: [\n (payload, guardResponse) => {\n // Actions only run when the guard returned a value, so guardResponse\n // is the GuardResult the guard produced.\n const {blockEvent, intent} = guardResponse\n const sideEffect = effect(() => onIntent(intent))\n if (blockEvent) {\n // Stopping propagation: only run the side effect, no forward.\n return [sideEffect]\n }\n // Non-blocking: run side effect and forward the original event so\n // PTE's default handling still executes.\n return [sideEffect, forward(payload.event)]\n },\n ],\n guard,\n on: '*',\n })\n}\n","import type {PickerIntent, PickerState} from './types'\n\nexport function pickerReducer(state: PickerState, intent: PickerIntent): PickerState {\n switch (intent.type) {\n case 'close':\n case 'select':\n return {mode: 'closed'}\n case 'navigate':\n if (state.mode === 'closed') return state\n return {\n ...state,\n highlightedIndex: state.highlightedIndex + intent.delta,\n }\n case 'open':\n if (state.mode !== 'closed') return state\n return {\n anchorBlockKey: intent.anchorBlockKey,\n highlightedIndex: 0,\n mode: intent.mode,\n query: intent.query,\n }\n case 'setHighlightedIndex':\n if (state.mode === 'closed') return state\n // Like `navigate`, the reducer does not clamp — the caller (which knows\n // the filtered list length) is responsible for staying in range.\n return {...state, highlightedIndex: intent.index}\n case 'updateQuery':\n if (state.mode === 'closed') return state\n return {...state, highlightedIndex: 0, query: intent.query}\n default: {\n // All intents are handled above; this arm satisfies consistent-return\n // while keeping the omission of a future variant a compile error.\n const unhandled: never = intent\n return unhandled\n }\n }\n}\n","import {effect, raise} from '@portabletext/editor/behaviors'\nimport {blockOffsetsToSelection} from '@portabletext/editor/utils'\nimport {defineInputRule, type InputRule} from '@portabletext/plugin-input-rule'\n\n/**\n * Generic machinery for markdown-style input rules that replace typed text\n * with an inserted object block, complementing the slash/⌘+/ picker with a\n * keyboard-only path that mirrors what writers already type in markdown.\n *\n * The rules run through `@portabletext/plugin-input-rule` (see\n * `markdownInputRules.tsx`), which applies the delete + insert as a single\n * behavior action set — so each transform is one undo step.\n *\n * Block values are built synchronously via each config's `buildValue` rather\n * than resolved from the schema's async initial values: the insert has to\n * happen inside the rule's action set for that single-undo guarantee to hold,\n * so anything the writer would otherwise have to fill in (language, filename,\n * callout type) is seeded from the host's rule config.\n */\n\nexport type KeyGenerator = () => string\n\n/**\n * One markdown input rule: when `pattern` matches the block text, the match\n * is deleted and a block of `blockType` is inserted in its place, carrying\n * the fields `buildValue` returns. `buildValue` must stay synchronous so the\n * delete + insert land in one action set (one undo step).\n */\nexport type MarkdownInputRuleConfig = {\n pattern: RegExp\n blockType: string\n buildValue: (context: {matchText: string; keyGenerator: KeyGenerator}) => Record<string, unknown>\n}\n\ntype BuildRulesDeps = {\n keyGenerator: KeyGenerator\n /** Called with the inserted block so the caller can open it for editing. */\n onInserted: (block: InsertableBlock) => void\n}\n\ntype InsertableBlock = {_key: string; _type: string} & Record<string, unknown>\n\n/**\n * Builds InputRules for the configs whose block type the host array actually\n * allows, so a rule can't insert a block the field would reject.\n */\nexport function createMarkdownInputRules({\n allowedBlockTypes,\n keyGenerator,\n onInserted,\n rules,\n}: BuildRulesDeps & {\n allowedBlockTypes: ReadonlySet<string>\n rules: readonly MarkdownInputRuleConfig[]\n}): InputRule[] {\n return rules\n .filter((config) => allowedBlockTypes.has(config.blockType))\n .map((config) => createInsertRule(config, keyGenerator, onInserted))\n}\n\n// The plugin matches its regex against the block text AFTER the pending\n// insertion. The trailing \"\\s\" is the space the writer types to commit the\n// fence/quote; it is part of the match and gets deleted along with it.\nexport const CODE_FENCE_PATTERN = /^`{3}\\S*\\s$/\nexport const BLOCKQUOTE_PATTERN = /^>\\s$/\n\n/**\n * A row of a code-fence language table: the stored `value`, the markdown\n * fence tokens that should resolve to it, and an optional tab filename.\n */\nexport type LanguageEntry = {\n value: string\n aliases?: readonly string[]\n filename?: string\n}\n\n/** Sugar: a blockquote rule (\"> \" at the start of a block) for `blockType`. */\nexport function blockquoteRule(options: {\n blockType: string\n createValue?: (context: {keyGenerator: KeyGenerator}) => Record<string, unknown>\n}): MarkdownInputRuleConfig {\n return {\n blockType: options.blockType,\n buildValue: ({keyGenerator}) => options.createValue?.({keyGenerator}) ?? {},\n pattern: BLOCKQUOTE_PATTERN,\n }\n}\n\n/**\n * Sugar: a code-fence rule (\"```lang␣\") for `blockType`. The language table\n * resolves fence tokens (aliases included) to the values the block's language\n * selector stores, plus an optional filename; tokens outside the table pass\n * through as typed so nothing the writer means is lost. `createValue` turns\n * the resolved language and filename into the block's fields.\n */\nexport function codeFenceRule(options: {\n blockType: string\n languages?: readonly LanguageEntry[]\n defaultLanguage?: string\n createValue: (context: {\n filename: string | undefined\n keyGenerator: KeyGenerator\n language: string | undefined\n }) => Record<string, unknown>\n}): MarkdownInputRuleConfig {\n const languages = options.languages ?? []\n return {\n blockType: options.blockType,\n buildValue: ({keyGenerator, matchText}) => {\n const language = normalizeFenceLanguage(\n fenceLanguageFromMatch(matchText),\n languages,\n options.defaultLanguage,\n )\n const filename = language\n ? languages.find((entry) => entry.value === language)?.filename\n : undefined\n return options.createValue({filename, keyGenerator, language})\n },\n pattern: CODE_FENCE_PATTERN,\n }\n}\n\n/** Strips the leading \"```\" fence and surrounding whitespace from a match. */\nexport function fenceLanguageFromMatch(matchText: string): string {\n return matchText.replace(/^`{3}/, '').trim()\n}\n\n/**\n * Resolves a typed fence token against a language table: a canonical value,\n * an alias (`py`→python, `yml`→yaml), or — for anything the table doesn't\n * know — the token as typed. An empty token yields `defaultLanguage`.\n */\nexport function normalizeFenceLanguage(\n raw: string,\n languages: readonly LanguageEntry[],\n defaultLanguage?: string,\n): string | undefined {\n const token = raw.trim()\n const lower = token.toLowerCase()\n if (!lower) return defaultLanguage\n // Match case-insensitively on both sides so a table with mixed-case values\n // or aliases still resolves (and yields its canonical `value`, casing\n // preserved) rather than falling through to the typed token.\n for (const {aliases, value} of languages) {\n if (value.toLowerCase() === lower || aliases?.some((alias) => alias.toLowerCase() === lower))\n return value\n }\n // Unknown token: pass it through as typed (case preserved) per the contract\n // above — not the lowercased form used for matching.\n return token\n}\n\nfunction createInsertRule(\n config: MarkdownInputRuleConfig,\n keyGenerator: KeyGenerator,\n onInserted: (block: InsertableBlock) => void,\n): InputRule {\n return defineInputRule({\n actions: [\n ({event, snapshot}) => {\n const match = event.matches[0]\n if (!match) return []\n const block: InsertableBlock = {\n // Spread the host-built fields first so the generated `_key` and the\n // resolved `_type` always win (mirrors insertPickerItem): a stray\n // `_key`/`_type` from buildValue can't hijack the block identity.\n ...config.buildValue({keyGenerator, matchText: match.text}),\n _key: keyGenerator(),\n _type: config.blockType,\n }\n // `match.selection` is clamped to the text that existed *before* the\n // triggering space, so it stops short of that space and would leave it\n // orphaned as a stray paragraph next to the inserted block.\n // `match.targetOffsets` spans the full match (space included); convert\n // it to a selection so the whole fence/quote is removed cleanly.\n const at =\n blockOffsetsToSelection({\n offsets: {\n anchor: match.targetOffsets.anchor,\n focus: match.targetOffsets.focus,\n },\n snapshot,\n }) ?? match.selection\n return [\n // Remove the typed fence/quote text, then insert the block in its\n // place. Both raises land in one action set (one undo step).\n raise({at, type: 'delete.text'}),\n raise({\n block,\n placement: 'auto',\n select: 'start',\n type: 'insert.block',\n }),\n effect(() => onInserted(block)),\n ]\n },\n ],\n on: config.pattern,\n })\n}\n","import {typeNameChain} from './deriveItems'\nimport {codeFenceRule, type MarkdownInputRuleConfig} from './inputRules'\nimport type {PickerItem, PickerItemMetadata, PickerItemsContext} from './types'\n\n/**\n * Default triggers and search keywords for block types with fixed, official\n * names: Studio's intrinsic types (`image`, `file`), first-party plugin\n * types (`code`, `table`, `color`, `latex`, `mux.video`), and the Media\n * Library's `sanity.video`. Presets are deliberately presentation-only —\n * they never add items (a type must actually be a member of the array),\n * never set groups (partial grouping would strand unmatched items in an\n * \"Other\" bucket), never affect rank, and always lose to a host's `items`\n * entry for the same type. Opt out entirely with `presets: false`.\n */\nexport const standardBlockPresets: readonly PickerItemMetadata[] = [\n {keywords: ['photo', 'picture', 'figure', 'media'], trigger: '/image', type: 'image'},\n {keywords: ['attachment', 'download', 'document'], trigger: '/file', type: 'file'},\n {keywords: ['snippet', 'syntax', 'fence', 'pre'], trigger: '/code', type: 'code'},\n {keywords: ['grid', 'rows', 'columns', 'spreadsheet'], trigger: '/table', type: 'table'},\n {keywords: ['swatch', 'palette'], trigger: '/color', type: 'color'},\n {keywords: ['formula', 'equation', 'math', 'tex', 'katex'], trigger: '/latex', type: 'latex'},\n {keywords: ['video', 'player', 'mux'], trigger: '/video', type: 'mux.video'},\n {keywords: ['video', 'player', 'media'], trigger: '/video', type: 'sanity.video'},\n]\n\n/**\n * Opt-in input rules for well-known block types — spread into `inputRules`\n * (`inputRules: [...wellKnownInputRules]`) rather than applied by default.\n * Today: a code fence for `@sanity/code-input`'s `code` type that stores the\n * typed fence token as the language. Like all rules, each resolves against\n * the array's members by name or resolved type chain (so an aliased\n * `{type: 'code', name: 'snippet'}` member still gets the fence, inserted\n * with the member's `_type`) and is ignored when nothing matches.\n */\nexport const wellKnownInputRules: readonly MarkdownInputRuleConfig[] = [\n codeFenceRule({\n blockType: 'code',\n createValue: ({language}) => (language ? {language} : {}),\n }),\n]\n\n/**\n * Fills preset triggers and keywords into derived items that don't already\n * have them, matching presets against each member's resolved type chain so\n * `{type: 'image', name: 'photo'}` still gets the image preset. Host `items`\n * metadata has already been folded in by derivePickerItems, so anything it\n * set wins by construction.\n */\nexport function applyPresetMetadata(\n items: readonly PickerItem[],\n context: PickerItemsContext,\n presets: readonly PickerItemMetadata[] = standardBlockPresets,\n): PickerItem[] {\n const presetByType = new Map(presets.map((preset) => [preset.type, preset]))\n return items.map((item) => {\n if (item.action.type !== 'insertBlock') return item\n if (item.trigger !== undefined && item.keywords !== undefined) return item\n const blockType = item.action.blockType\n const memberType = context.memberTypes.find((candidate) => candidate.name === blockType)\n if (!memberType) return item\n const preset = typeNameChain(memberType)\n .map((name) => presetByType.get(name))\n .find(Boolean)\n if (!preset) return item\n return {\n ...item,\n keywords: item.keywords ?? preset.keywords,\n trigger: item.trigger ?? preset.trigger,\n }\n })\n}\n","import {BlockElementIcon} from '@sanity/icons/BlockElement'\nimport type {ComponentType} from 'react'\n\nimport type {PickerItem} from './types'\n\ntype ItemPresentation = {\n title: string\n icon: ComponentType\n description: string | undefined\n}\n\ntype SchemaTypeLike = {\n name: string\n title?: string\n description?: string\n icon?: ComponentType\n type?: SchemaTypeLike\n /** Reference types carry their targets here; core reads `to[0].icon`. */\n to?: ReadonlyArray<{icon?: ComponentType}>\n}\n\n/**\n * Resolves what a picker row shows for an item, following the same fallback\n * chains Studio's built-in insert menu uses: icon from the member type, its\n * parent type, a reference target, then the generic block icon; title from\n * the member type or its capitalized name. The curated description (from\n * `items` metadata) wins over the schema type's own — curation is the more\n * specific intent.\n */\nexport function resolveItemPresentation(\n item: PickerItem,\n schemaType: SchemaTypeLike | undefined,\n): ItemPresentation {\n if (!schemaType) {\n return {\n description: item.description,\n icon: item.icon ?? BlockElementIcon,\n title: item.title || (item.action.type === 'insertBlock' ? item.action.blockType : item.id),\n }\n }\n return {\n description: item.description ?? schemaType.description,\n icon: schemaType.icon ?? schemaType.type?.icon ?? schemaType.to?.[0]?.icon ?? BlockElementIcon,\n title: schemaType.title ?? upperFirst(schemaType.name),\n }\n}\n\n// Matches core's lodash `upperFirst`: capitalize the first character, leave\n// the rest untouched (`codeBlock` -> `CodeBlock`, not `Codeblock`).\nfunction upperFirst(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1)\n}\n","import {useEditor} from '@portabletext/editor'\nimport {Box, Card, Flex, Hotkeys, Popover, Stack, Text, useToast} from '@sanity/ui'\nimport type {CSSProperties} from 'react'\nimport {useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState} from 'react'\nimport {useResolveInitialValueForType, useSchema} from 'sanity'\nimport type {SchemaType} from 'sanity'\n\nimport {derivePickerItems, unknownMetadataTypes} from './deriveItems'\nimport {filterPickerItems} from './filterItems'\nimport {flattenSections, groupPickerItems} from './groupItems'\nimport {createCleanupQueryBehavior, createInsertBehavior, sendCleanupQuery} from './insertBehavior'\nimport {insertPickerItem} from './insertPickerItem'\nimport {\n type BlockInsertPickerLabels,\n formatNoMatches,\n formatPosition,\n resolveLabels,\n} from './labels'\nimport {usePickerItemsContext} from './memberSchemaTypes'\nimport {useOpenBlockOnInsert} from './openBlockOnInsert'\nimport {createPickerBehavior} from './pickerBehavior'\nimport {pickerReducer} from './pickerReducer'\nimport {applyPresetMetadata} from './presets'\nimport {resolveItemPresentation} from './resolveItemPresentation'\nimport type {\n PickerInsertEvent,\n PickerIntent,\n PickerItem,\n PickerItemMetadata,\n PickerItemsContext,\n PickerItemsResolver,\n PickerState,\n} from './types'\n\nexport type BlockInsertPickerProps = {\n /**\n * Per-member curation (trigger, keywords, group, description, badge,\n * hidden, openOnInsert) merged into the items derived from the array's\n * members; array order is the rank. Members without an entry still get\n * items, in schema order.\n */\n items?: readonly PickerItemMetadata[]\n /**\n * Escape hatch: names the portable-text array type to resolve items from\n * when Studio's member-schema context is unavailable. With the context\n * present (any supported sanity version) this is ignored — the containing\n * array and its members are detected automatically.\n */\n arrayTypeName?: string\n /**\n * Programmatic seam over the derived-and-curated item list: reorder,\n * remove, relabel, or append items (including `custom`-action items).\n */\n resolveItems?: PickerItemsResolver\n /**\n * Replaces the built-in matching (see filterPickerItems). Receives the\n * bare query in both modes — the slash-mode \"/\" prefix is stripped.\n */\n filter?: (items: readonly PickerItem[], query: string) => readonly PickerItem[]\n /** Overrides for the picker chrome's user-facing strings. */\n labels?: Partial<BlockInsertPickerLabels>\n /** Notified after each successful insert, alongside open-on-insert. */\n onInsert?: (event: PickerInsertEvent) => void\n /**\n * Whether an inserted block opens for editing (default true). Items can\n * override per member via their metadata's `openOnInsert`.\n */\n openOnInsert?: boolean\n /** Whether Cmd/Ctrl+/ opens the picker (default true). */\n shortcut?: boolean\n /**\n * Whether well-known block types (image, file, code, table, ...) get\n * default triggers and keywords when the host's `items` doesn't cover\n * them (default true). See standardBlockPresets.\n */\n presets?: boolean\n}\n\nexport function BlockInsertPicker({\n arrayTypeName,\n filter,\n items,\n labels: labelOverrides,\n onInsert,\n openOnInsert = true,\n presets = true,\n resolveItems,\n shortcut = true,\n}: BlockInsertPickerProps) {\n const editor = useEditor()\n const openBlockOnInsert = useOpenBlockOnInsert()\n const itemsContext = usePickerItemsContext(arrayTypeName)\n const schema = useSchema()\n const resolveInitialValueForType = useResolveInitialValueForType()\n const toast = useToast()\n const labels = useMemo(() => resolveLabels(labelOverrides), [labelOverrides])\n // Instance-scoped so ARIA option ids stay unique when several PTE fields\n // (each with their own picker) mount on the same document.\n const instanceId = useId()\n const listboxId = `${instanceId}-listbox`\n const optionId = (id: string) => `${instanceId}-option-${id}`\n\n // Items derive from the array's member types (via Studio's member-schema\n // context, or the arrayTypeName fallback), curated by the metadata in\n // `items` and decorated by presets. Titles and icons are then enriched\n // ONCE from the member type — not the global type of the same name — so\n // member-level config wins: a member that redefines a core type's name\n // shows its own icon and title rather than the global type's. Enriching\n // before filtering keeps query matching aligned with what the popover\n // displays, and `resolveItems` runs last over the fully-presented list so\n // hosts relabel or append against what would actually render.\n const pickerItems = useMemo(() => {\n if (!itemsContext) return []\n const derived = presets\n ? applyPresetMetadata(derivePickerItems(itemsContext, items), itemsContext)\n : derivePickerItems(itemsContext, items)\n const presented = derived.map((item) => {\n if (item.action.type !== 'insertBlock') return item\n const schemaType = memberTypeFor(itemsContext, schema, item.action.blockType)\n const presentation = resolveItemPresentation(item, schemaType)\n // The derived items are fresh objects owned by this memo, so in-place\n // assignment is safe (and satisfies oxc's no-map-spread).\n return Object.assign(item, {\n description: presentation.description,\n icon: presentation.icon,\n title: presentation.title,\n })\n })\n return resolveItems ? [...resolveItems(presented, itemsContext)] : presented\n }, [items, itemsContext, presets, resolveItems, schema])\n\n const hasItems = pickerItems.length > 0\n\n // Dev-mode configuration diagnostics, once per mount per category: a\n // silent picker (no context, or nothing derivable) and typo'd metadata\n // keys are the two misconfigurations schema-derived items can't surface\n // on their own.\n const warnedRef = useRef<{context?: boolean; empty?: boolean; unknown?: boolean}>({})\n useEffect(() => {\n if (process.env['NODE_ENV'] === 'production') return\n const warned = warnedRef.current\n if (!itemsContext && !warned.context) {\n warned.context = true\n console.warn(\n '[@sanity/block-insert-picker] No Portable Text member schema context found and no ' +\n '`arrayTypeName` resolved to an array type — the picker is disabled for this field.',\n )\n return\n }\n if (itemsContext && items && !warned.unknown) {\n const unknown = unknownMetadataTypes(itemsContext, items)\n if (unknown.length > 0) {\n warned.unknown = true\n console.warn(\n `[@sanity/block-insert-picker] \\`items\\` metadata references types that are not ` +\n `members of this array: ${unknown.join(', ')}`,\n )\n }\n }\n if (itemsContext && !hasItems && !warned.empty) {\n warned.empty = true\n console.warn(\n '[@sanity/block-insert-picker] No insertable items: the array has no non-text-block ' +\n 'members (and `resolveItems` added none) — the picker is disabled for this field.',\n )\n }\n }, [hasItems, items, itemsContext])\n\n const [state, dispatch] = useReducer(pickerReducer, {mode: 'closed'})\n\n // stateRef gives behavior callbacks synchronous access to the latest state\n // without needing to re-register the behavior on every state change.\n // useLayoutEffect (vs useEffect) ensures the ref is in sync before paint,\n // closing a stale-read window for chained behavior events within a tick.\n const stateRef = useRef<PickerState>(state)\n useLayoutEffect(() => {\n stateRef.current = state\n })\n\n // The shortcut flag is read through a ref for the same reason: the guard\n // consults it per keystroke, so toggling it must not re-register (and\n // re-sort) the behavior chain.\n const shortcutRef = useRef(shortcut)\n useLayoutEffect(() => {\n shortcutRef.current = shortcut\n })\n\n const open = state.mode !== 'closed'\n const query = open ? state.query : ''\n const mode = open ? state.mode : null\n\n const filterItems = filter ?? filterPickerItems\n // The filter seam receives the query without the slash-mode \"/\" prefix, so\n // a custom `filter` sees the same bare text in both modes. The raw query\n // keeps driving the empty-state label, the shortcut echo, and onInsert.\n const filterQuery = mode === 'slash' ? bareQuery(query) : query\n\n // Sections drive the rendered layout (group headers); `filtered` is the same\n // items flattened into the single index space navigation and selection share.\n const sections = useMemo(\n () => groupPickerItems(filterItems(pickerItems, filterQuery)),\n [filterItems, filterQuery, pickerItems],\n )\n const filtered = useMemo(() => flattenSections(sections), [sections])\n // Rows resolve their flat index positionally (section offset + row index),\n // never by item id: a resolveItems-appended item may reuse a derived id,\n // and an id-keyed map would point both rows at one index.\n const sectionOffsets = useMemo(() => {\n const offsets: number[] = []\n let total = 0\n for (const section of sections) {\n offsets.push(total)\n total += section.items.length\n }\n return offsets\n }, [sections])\n // A lone section carries no useful category label (e.g. a curated `items`\n // prop, or a filter that matched a single group) — skip the header chrome.\n const showGroupHeaders = sections.length > 1\n\n // Guards the async select path: a second select arriving while a slow\n // initial-value resolution is in flight must not double-insert.\n const insertInFlightRef = useRef(false)\n\n // Plain functions below (no useCallback): the React Compiler memoizes\n // them, and its lint rule rejects hand-written dependency arrays here.\n // Core selection logic: given a resolved item index into the filtered list for\n // `current` state, perform the insertion. Extracted so both keyboard-Enter\n // (via handleIntent) and mouse-click (via selectItemAtIndex) share the same\n // path without reading a potentially-stale highlightedIndex from stateRef.\n // The initial value resolves at select time (mirroring Studio's own toolbar\n // handleInsertBlock flow) so the first select in a session can't race an\n // eager cache, and resolution errors surface instead of being swallowed.\n const insertItemAtIndex = async (\n current: Exclude<PickerState, {mode: 'closed'}>,\n idx: number,\n ) => {\n if (insertInFlightRef.current) {\n // A prior select is still resolving; bail to avoid a double-insert. Still\n // close, because the user may have reopened the picker mid-flight and a\n // stuck-open menu that swallows this Enter looks broken.\n dispatch({type: 'close'})\n return\n }\n insertInFlightRef.current = true\n try {\n // Index into the grouped display order (not the raw rank-flat order)\n // so the row the user sees highlighted is the one that gets inserted.\n const visible = flattenSections(\n groupPickerItems(\n filterItems(\n pickerItems,\n current.mode === 'slash' ? bareQuery(current.query) : current.query,\n ),\n ),\n )\n const clamped = Math.max(0, Math.min(visible.length - 1, idx))\n const chosen = visible[clamped]\n // Close immediately for a snappy response; the insert continues from\n // the captured `current` state.\n dispatch({type: 'close'})\n if (!chosen) return\n if (chosen.action.type === 'custom') {\n // No block to insert: clean up the typed \"/query\" text (slash mode)\n // and hand the editor to the host's action.\n sendCleanupQuery(editor, {\n anchorBlockKey: current.anchorBlockKey,\n mode: current.mode,\n query: current.query,\n })\n chosen.action.onSelect({\n closePicker: () => dispatch({type: 'close'}),\n editor,\n })\n return\n }\n const blockType = chosen.action.blockType\n let initialValue: Record<string, unknown> | undefined\n const schemaType = memberTypeFor(itemsContext, schema, blockType)\n if (schemaType) {\n initialValue = (await resolveInitialValueForType(schemaType, {})) ?? undefined\n }\n // Re-take the snapshot after the await; the document may have changed.\n // A null selection is fine: the insert behavior anchors the block via\n // `at` from anchorBlockKey, so a blur during a slow resolution (or a\n // shortcut-mode open with no selection) must not abort the insert.\n const snapshot = editor.getSnapshot()\n // Confirm the anchor block still exists in the document; if it was\n // deleted while the picker was open we have nothing to anchor against.\n const anchorStillExists = snapshot.context.value.some(\n (b) => b._key === current.anchorBlockKey,\n )\n if (!anchorStillExists) {\n toast.push({\n closable: true,\n description: labels.insertAnchorRemoved,\n status: 'warning',\n title: labels.insertError,\n })\n return\n }\n insertPickerItem({\n anchorBlockKey: current.anchorBlockKey,\n blockType,\n editor,\n initialValue,\n keyGenerator: () => snapshot.context.keyGenerator(),\n mode: current.mode,\n onInsertedKey: (key) => {\n if (chosen.openOnInsert ?? openOnInsert) openBlockOnInsert(key)\n onInsert?.({\n blockKey: key,\n blockType,\n mode: current.mode,\n query: current.query,\n via: 'picker',\n })\n },\n query: current.query,\n })\n } catch (error) {\n // insertItemAtIndex is fire-and-forget (`void insertItemAtIndex(...)`),\n // so anything thrown here — initial-value resolution, a host `filter`,\n // a custom action's onSelect, a host onInsert — would otherwise become\n // an unhandled rejection with no user feedback.\n toast.push({\n closable: true,\n description: error instanceof Error ? error.message : String(error),\n status: 'error',\n title: labels.insertError,\n })\n } finally {\n insertInFlightRef.current = false\n }\n }\n\n // Rows call this from onClick with their own index rather than reading\n // highlightedIndex: the onMouseMove highlight update for the row under the\n // cursor may not have flushed yet, so passing idx avoids inserting the\n // previously-highlighted row.\n const selectItemAtIndex = (idx: number) => {\n const current = stateRef.current\n if (current.mode === 'closed') return\n void insertItemAtIndex(current, idx)\n }\n\n const handleIntent = (intent: PickerIntent) => {\n if (intent.type === 'navigate') {\n // The reducer deliberately doesn't clamp (it can't know the filtered\n // list length), so resolve the move here. Clamping the base index too\n // self-heals any stored value that has drifted out of range — an\n // unclamped store makes reversed arrow presses appear \"dead\" while a\n // hidden out-of-bounds index counts back into range.\n const current = stateRef.current\n if (current.mode === 'closed') return\n const lastIndex = filtered.length - 1\n const base = Math.max(0, Math.min(lastIndex, current.highlightedIndex))\n const next = Math.max(0, Math.min(lastIndex, base + intent.delta))\n dispatch({index: next, type: 'setHighlightedIndex'})\n return\n }\n if (intent.type !== 'select') {\n dispatch(intent)\n return\n }\n // Resolve the currently-highlighted item against the filtered list.\n const current = stateRef.current\n if (current.mode === 'closed') return\n void insertItemAtIndex(current, current.highlightedIndex)\n }\n\n // handleIntentRef lets the behavior always call the latest handleIntent\n // without needing to re-register the behavior when items changes.\n // useLayoutEffect for the same stale-read-window reason as stateRef above.\n const handleIntentRef = useRef<(intent: PickerIntent) => void>(handleIntent)\n useLayoutEffect(() => {\n handleIntentRef.current = handleIntent\n })\n\n // Register behaviors imperatively so their lifecycle follows this\n // component's — and only while there is anything to offer: with zero\n // items the picker must never open (no empty popover, no swallowed \"/\").\n // The picker behavior watches typing/keys; the insert behavior performs\n // the atomic cleanup + insert when a custom.blockInsertPicker.insert\n // event arrives; the cleanup behavior serves `custom` item actions.\n useEffect(() => {\n if (!hasItems) return undefined\n const behavior = createPickerBehavior({\n getState: () => stateRef.current,\n isShortcutEnabled: () => shortcutRef.current,\n onIntent: (intent) => handleIntentRef.current(intent),\n })\n const unregisterPicker = editor.registerBehavior({behavior})\n const unregisterInsert = editor.registerBehavior({\n behavior: createInsertBehavior(),\n })\n const unregisterCleanup = editor.registerBehavior({\n behavior: createCleanupQueryBehavior(),\n })\n return () => {\n unregisterPicker()\n unregisterInsert()\n unregisterCleanup()\n }\n }, [editor, hasItems])\n\n // If the item list empties while the picker is open (a resolveItems change,\n // a schema hot-reload), the behaviors above unregister — close the popover\n // rather than leaving a zombie that no behavior can drive.\n useEffect(() => {\n if (!hasItems && stateRef.current.mode !== 'closed') dispatch({type: 'close'})\n }, [hasItems])\n\n // --- UI ---\n\n const highlightedIndex = open\n ? Math.max(0, Math.min(filtered.length - 1, state.highlightedIndex))\n : 0\n\n // Announced to screen readers via a polite live region: the focus stays in\n // the editor, so aria-selected alone would never be read aloud. Recomputing\n // this on every highlight/filter change lets assistive tech track the list.\n const highlightedItem = open ? filtered[highlightedIndex] : undefined\n const announcement = highlightedItem\n ? [\n highlightedItem.title,\n highlightedItem.description,\n formatPosition(labels, highlightedIndex + 1, filtered.length),\n ]\n .filter(Boolean)\n .join(', ')\n : ''\n\n // Capture the caret DOMRect once when the picker opens and hand Popover a\n // virtual reference element wrapping it. The rect\n // is intentionally pinned at the opening position — re-capturing on every\n // `state` change (e.g. each keystroke that updates `query`) would make the\n // popover drift right as the caret advances through typed characters.\n // editor.dom is the supported anchoring API; a collapsed caret in an empty\n // block can yield an all-zero rect in some browsers, so fall back to the\n // block element's rect in that case.\n const [cursorRect, setCursorRect] = useState<DOMRect | null>(null)\n\n useLayoutEffect(() => {\n if (!open) {\n // oxlint-disable-next-line react/react-compiler\n setCursorRect(null)\n return\n }\n const snapshot = editor.getSnapshot()\n const rect = editor.dom.getSelectionRect(snapshot)\n if (rect && (rect.x || rect.y || rect.width || rect.height)) {\n setCursorRect(rect)\n return\n }\n const blockRect = editor.dom.getStartBlockElement(snapshot)?.getBoundingClientRect()\n if (blockRect) setCursorRect(blockRect)\n }, [editor, open])\n\n // Close on any pointerdown outside the popover (clicking into another block\n // must not leave a zombie picker that later intercepts Enter), and when\n // focus leaves the editor entirely (e.g. Tab). @sanity/ui's Popover has no\n // onClickOutside prop — that lives on Menu/Dialog — so listen manually.\n const popoverContentRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!open) return undefined\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target\n if (target instanceof Node && popoverContentRef.current?.contains(target)) return\n dispatch({type: 'close'})\n }\n // getEditorElement is typed as Element, whose addEventListener overload\n // hands the listener a plain Event; narrow to FocusEvent inside instead\n // of asserting the element type.\n const editorElement = editor.dom.getEditorElement()\n const handleFocusOut = (event: Event) => {\n const next = event instanceof FocusEvent ? event.relatedTarget : null\n if (\n next instanceof Node &&\n (editorElement?.contains(next) || popoverContentRef.current?.contains(next))\n )\n return\n dispatch({type: 'close'})\n }\n document.addEventListener('pointerdown', handlePointerDown, true)\n editorElement?.addEventListener('focusout', handleFocusOut)\n return () => {\n document.removeEventListener('pointerdown', handlePointerDown, true)\n editorElement?.removeEventListener('focusout', handleFocusOut)\n }\n }, [editor, open])\n\n // Keep the highlighted row visible inside the scrolling list.\n const highlightedRowRef = useRef<HTMLDivElement | null>(null)\n\n // Hover may only move the highlight on genuine pointer movement. When\n // keyboard navigation scrolls the list (scrollIntoView below), rows slide\n // under a stationary cursor and the browser fires mouseenter — and, in some\n // engines, a coordinate-identical mousemove — on whichever row lands there.\n // Honoring those synthetic events hijacks the keyboard highlight back to\n // wherever the mouse happens to rest. Track the last seen coordinates and\n // require them to change before hover wins; the first event only seeds.\n const lastPointerRef = useRef<null | {x: number; y: number}>(null)\n\n const highlightOnPointerMove = (idx: number, x: number, y: number) => {\n const last = lastPointerRef.current\n lastPointerRef.current = {x, y}\n if (!last || (last.x === x && last.y === y)) return\n const current = stateRef.current\n if (current.mode !== 'closed' && idx !== current.highlightedIndex) {\n dispatch({index: idx, type: 'setHighlightedIndex'})\n }\n }\n\n useEffect(() => {\n highlightedRowRef.current?.scrollIntoView({block: 'nearest'})\n }, [highlightedIndex])\n\n // Stable virtual element derived from the captured rect — keeps Popover\n // positioning stable even as `state` changes while the picker is open.\n const cursorElement = useMemo(() => {\n if (!cursorRect) return null\n // Popover types referenceElement as HTMLElement, but its positioning\n // only ever reads getBoundingClientRect — the standard virtual-element\n // escape hatch for anchoring to a caret rect.\n // oxlint-disable-next-line no-unsafe-type-assertion\n return {\n getBoundingClientRect: () => cursorRect,\n } as unknown as HTMLElement\n }, [cursorRect])\n\n if (!open) return null\n\n if (filtered.length === 0) {\n return (\n <Popover\n constrainSize\n content={\n <Card\n aria-live=\"polite\"\n onMouseDown={preventFocusSteal}\n padding={3}\n radius={2}\n ref={popoverContentRef}\n // Card renders (and refs) a div; an <output> would change the\n // element type the outside-pointerdown ref relies on.\n // oxlint-disable-next-line prefer-tag-over-role\n role=\"status\"\n >\n <Text muted size={1}>\n {formatNoMatches(labels, query)}\n </Text>\n </Card>\n }\n fallbackPlacements={['top-start']}\n open\n placement=\"bottom-start\"\n portal\n preventOverflow\n referenceElement={cursorElement}\n />\n )\n }\n\n return (\n <Popover\n constrainSize\n content={\n <Card\n onMouseDown={preventFocusSteal}\n padding={1}\n radius={2}\n ref={popoverContentRef}\n style={{\n display: 'flex',\n flexDirection: 'column',\n maxHeight: '100%',\n minWidth: 300,\n }}\n >\n {/* Focus stays in the editor, so aria-selected on rows is never read\n aloud on its own. This polite region carries the open state and\n each highlight change to assistive tech. */}\n <output aria-live=\"polite\" style={SR_ONLY}>\n {announcement}\n </output>\n <Flex align=\"center\" flex=\"none\" gap={2} padding={2}>\n <Box flex={1}>\n <Text\n muted\n size={0}\n style={{letterSpacing: '0.05em', textTransform: 'uppercase'}}\n weight=\"medium\"\n >\n {labels.title}\n </Text>\n </Box>\n {mode === 'shortcut' && query !== '' ? (\n // Shortcut-mode typing never reaches the document, so echo the\n // captured query here — otherwise keystrokes appear to vanish.\n <Text muted size={1} textOverflow=\"ellipsis\">\n {query}\n </Text>\n ) : null}\n </Flex>\n <Box\n aria-label={labels.title}\n id={listboxId}\n // A custom ARIA listbox: <select>/<datalist> cannot host rich\n // rows (icons, descriptions, hotkey chips) or grouped sections.\n // oxlint-disable-next-line prefer-tag-over-role\n role=\"listbox\"\n style={{flex: 1, maxHeight: 320, minHeight: 0, overflowY: 'auto'}}\n >\n {sections.map((section, sectionIndex) => {\n const sectionLabel = section.group ?? labels.ungroupedSection\n // Key on the raw group (namespaced), not the display label: a\n // curated group named the same as `ungroupedSection` would\n // otherwise share a React key with the null-group section.\n const sectionKey = section.group === null ? 'ungrouped' : `group:${section.group}`\n const rows = section.items.map((item, rowIndex) => {\n const idx = (sectionOffsets[sectionIndex] ?? 0) + rowIndex\n const Icon = item.icon\n const isHighlighted = idx === highlightedIndex\n return (\n <Card\n aria-selected={isHighlighted}\n id={optionId(String(idx))}\n key={`${item.id}-${idx}`}\n onClick={() => selectItemAtIndex(idx)}\n onMouseMove={(event) =>\n highlightOnPointerMove(idx, event.clientX, event.clientY)\n }\n padding={2}\n radius={1}\n ref={isHighlighted ? highlightedRowRef : undefined}\n // A native <option> only works inside <select>; these are\n // ARIA options in a custom listbox rendered from Cards.\n // oxlint-disable-next-line prefer-tag-over-role\n role=\"option\"\n style={{cursor: 'pointer'}}\n // Focusable in principle (never via Tab): DOM focus stays\n // in the editor and the live region does the announcing.\n tabIndex={-1}\n tone={isHighlighted ? 'primary' : 'default'}\n >\n <Flex align=\"center\" gap={3}>\n <Box\n style={{\n alignItems: 'center',\n display: 'flex',\n height: 22,\n justifyContent: 'center',\n width: 22,\n }}\n >\n {Icon ? <Icon /> : null}\n </Box>\n <Stack flex={1} gap={2}>\n <Text size={1} textOverflow=\"ellipsis\">\n {item.title}\n </Text>\n {item.description ? (\n <Text muted size={0} textOverflow=\"ellipsis\">\n {item.description}\n </Text>\n ) : null}\n </Stack>\n {item.badge ? (\n <Box flex=\"none\">\n <Text muted size={0}>\n {item.badge}\n </Text>\n </Box>\n ) : null}\n {item.trigger ? (\n <Box flex=\"none\">\n <Hotkeys fontSize={0} keys={[item.trigger]} />\n </Box>\n ) : null}\n </Flex>\n </Card>\n )\n })\n if (!showGroupHeaders) {\n return (\n <Stack key={sectionKey} gap={1}>\n {rows}\n </Stack>\n )\n }\n return (\n <Box\n aria-label={sectionLabel}\n key={sectionKey}\n paddingTop={sectionIndex === 0 ? 0 : 2}\n // Grouped options inside a listbox: role=\"group\" is the\n // valid ARIA structure here; the tags the rule suggests\n // (fieldset, address, …) are not permitted in a listbox.\n // oxlint-disable-next-line prefer-tag-over-role\n role=\"group\"\n >\n <Box paddingBottom={1} paddingTop={2} paddingX={2}>\n <Text\n muted\n size={0}\n style={{\n letterSpacing: '0.05em',\n textTransform: 'uppercase',\n }}\n weight=\"medium\"\n >\n {sectionLabel}\n </Text>\n </Box>\n <Stack gap={1}>{rows}</Stack>\n </Box>\n )\n })}\n </Box>\n <Card borderTop flex=\"none\" padding={2} radius={0}>\n <Flex align=\"center\" gap={3} wrap=\"wrap\">\n <FooterHint keys={['↑', '↓']} label={labels.footerNavigate} />\n <FooterHint keys={['↵']} label={labels.footerInsert} />\n <FooterHint keys={['Esc']} label={labels.footerDismiss} />\n {shortcut ? (\n <FooterHint keys={[OPEN_MODIFIER, '/']} label={labels.footerAnywhere} />\n ) : null}\n </Flex>\n </Card>\n </Card>\n }\n fallbackPlacements={['top-start']}\n open\n placement=\"bottom-start\"\n portal\n preventOverflow\n referenceElement={cursorElement}\n />\n )\n}\n\n// A single key legend in the teaching footer: the key chips plus a short verb.\nfunction FooterHint({keys, label}: {keys: string[]; label: string}) {\n return (\n <Flex align=\"center\" gap={2}>\n <Hotkeys fontSize={0} keys={keys} />\n <Text muted size={0}>\n {label}\n </Text>\n </Flex>\n )\n}\n\n// Module-level (not a component closure) so useMemo dependency arrays don't\n// need a function that the react-hooks lint flags as changing every render.\n// Member types resolve from the picker's items context first (member-level\n// config wins), then from the global type of the same name — the same\n// fallback the previous arrayTypeName-only lookup used.\nfunction memberTypeFor(\n itemsContext: PickerItemsContext | null,\n schema: {get(name: string): SchemaType | undefined},\n blockType: string,\n): SchemaType | undefined {\n const member = itemsContext?.memberTypes.find((candidate) => candidate.name === blockType)\n return member ?? schema.get(blockType)\n}\n\n// Slash-mode queries carry the leading \"/\" the writer typed; the filter seam\n// works on the bare text (see filterQuery above).\nfunction bareQuery(query: string): string {\n return query.startsWith('/') ? query.slice(1) : query\n}\n\n// Interacting with any popover surface (header, padding, the scroll\n// container's scrollbar) must not steal DOM focus from the editor: the blur\n// would trip the focusout close listener and dismiss the picker mid-use.\nfunction preventFocusSteal(event: {preventDefault: () => void}) {\n event.preventDefault()\n}\n\n// Visually hidden but present in the accessibility tree — used for the live\n// region so announcements don't disturb the popover layout.\nconst SR_ONLY: CSSProperties = {\n border: 0,\n clipPath: 'inset(50%)',\n height: 1,\n margin: -1,\n overflow: 'hidden',\n padding: 0,\n position: 'absolute',\n whiteSpace: 'nowrap',\n width: 1,\n}\n\n// The Cmd+/ shortcut symbol matches the platform: ⌘ on Apple, Ctrl elsewhere.\n// navigator.platform is deprecated but still the most reliable signal here;\n// fall back to the user agent, then to Ctrl when neither is available.\nconst IS_APPLE_PLATFORM =\n typeof navigator !== 'undefined' &&\n /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent || '')\nconst OPEN_MODIFIER = IS_APPLE_PLATFORM ? '⌘' : 'Ctrl'\n","import {useEditor} from '@portabletext/editor'\nimport {defineInputRuleBehavior} from '@portabletext/plugin-input-rule'\nimport {useEffect, useLayoutEffect, useMemo, useRef} from 'react'\n\nimport {typeNameChain} from './deriveItems'\nimport {createMarkdownInputRules, type MarkdownInputRuleConfig} from './inputRules'\nimport {usePickerItemsContext} from './memberSchemaTypes'\nimport {useOpenBlockOnInsert} from './openBlockOnInsert'\nimport type {PickerInsertEvent} from './types'\n\nexport type MarkdownInputRulesProps = {\n /**\n * Escape hatch: names the portable-text array type when Studio's\n * member-schema context is unavailable (see BlockInsertPickerProps).\n * Rules are only enabled for block types the array actually allows.\n */\n arrayTypeName?: string\n /** The markdown transforms to enable (see inputRules.ts). */\n rules: readonly MarkdownInputRuleConfig[]\n /** Notified after each successful insert, alongside open-on-insert. */\n onInsert?: (event: PickerInsertEvent) => void\n /** Whether an inserted block opens for editing (default true). */\n openOnInsert?: boolean\n}\n\n/**\n * Mounts markdown input rules on the PTE and opens each inserted block for\n * editing once its member item mounts — the same open-on-insert behavior the\n * picker uses, so a fenced code block lands ready to type into.\n */\nexport function MarkdownInputRules({\n arrayTypeName,\n onInsert,\n openOnInsert = true,\n rules,\n}: MarkdownInputRulesProps) {\n const editor = useEditor()\n const itemsContext = usePickerItemsContext(arrayTypeName)\n const openBlockOnInsert = useOpenBlockOnInsert()\n\n // Rules resolve against the array's insertable members with the same\n // precedence as picker item metadata: a rule's blockType matches a member\n // by name first, then by any name in the member's resolved type chain — so\n // wellKnownInputRules' `code` fence also serves `{type: 'code', name:\n // 'snippet'}`, with the inserted `_type` rewritten to the member name the\n // array actually accepts. Rules matching nothing are dropped here, which\n // also keeps `block` itself (and aliased text blocks) unreachable.\n const resolvedRules = useMemo(() => {\n const memberTypes = itemsContext?.memberTypes ?? []\n return rules.flatMap((rule) => {\n const member =\n memberTypes.find((candidate) => candidate.name === rule.blockType) ??\n memberTypes.find((candidate) => typeNameChain(candidate).includes(rule.blockType))\n if (!member) return []\n return [rule.blockType === member.name ? rule : {...rule, blockType: member.name}]\n })\n }, [itemsContext, rules])\n\n // The insert callbacks are routed through a ref (same pattern as\n // BlockInsertPicker's handleIntentRef) so the registration effect below\n // stays keyed on the rules/schema/editor only: re-registering a behavior\n // is not free (it tears down and re-sorts the editor's behavior chain, and\n // moves this behavior after later-registered ones), so a host passing an\n // inline onInsert must not cause per-render churn.\n const onInsertedRef = useRef<(block: {_key: string; _type: string}) => void>(() => {})\n useLayoutEffect(() => {\n onInsertedRef.current = (block) => {\n if (openOnInsert) openBlockOnInsert(block._key)\n onInsert?.({\n blockKey: block._key,\n blockType: block._type,\n via: 'inputRule',\n })\n }\n })\n\n // Register the input-rule behavior imperatively rather than through the\n // <InputRulePlugin>\n // component: the rule closures then live inside an effect and can schedule\n // the open-on-insert without hitting the React Compiler's \"no refs during\n // render\" rule. Each transform is still a single undo step (the plugin\n // applies the delete + insert as one behavior action set).\n useEffect(() => {\n const inputRules = createMarkdownInputRules({\n // resolvedRules are already narrowed to insertable members.\n allowedBlockTypes: new Set(resolvedRules.map((rule) => rule.blockType)),\n // The generator is read per insert so keys stay unique across a session.\n keyGenerator: () => editor.getSnapshot().context.keyGenerator(),\n onInserted: (block) => onInsertedRef.current(block),\n rules: resolvedRules,\n })\n if (inputRules.length === 0) return undefined\n return editor.registerBehavior({\n behavior: defineInputRuleBehavior({rules: inputRules}),\n })\n }, [editor, resolvedRules])\n\n return null\n}\n","import type {ComponentType} from 'react'\nimport type {PortableTextPluginsProps} from 'sanity'\n\nimport {BlockInsertPicker} from './blockInsertPicker'\nimport type {MarkdownInputRuleConfig} from './inputRules'\nimport type {BlockInsertPickerLabels} from './labels'\nimport {MarkdownInputRules} from './markdownInputRules'\nimport type {PickerInsertEvent, PickerItem, PickerItemMetadata, PickerItemsResolver} from './types'\n\nexport interface BlockInsertPickerConfig {\n /**\n * Per-member curation (slash trigger, alias keywords, section grouping,\n * description, badge, visibility, per-item open-on-insert) merged into the\n * items derived from the array's members; array order is the sort rank.\n * Members without an entry still get picker items, appended in schema\n * order. Entries whose `type` matches no member warn in dev mode.\n */\n items?: readonly PickerItemMetadata[]\n /**\n * Programmatic seam over the derived item list — reorder, remove, relabel,\n * or append items (including `custom`-action items) — running after schema\n * derivation, presets, and `items` metadata.\n */\n resolveItems?: PickerItemsResolver\n /**\n * Markdown-style transforms (for example from the {@link codeFenceRule} and\n * {@link blockquoteRule} factories) that replace typed text with an\n * inserted block, as one undo step. Opt-in only; rules targeting block\n * types the array does not allow are ignored.\n */\n inputRules?: readonly MarkdownInputRuleConfig[]\n /**\n * Replaces the built-in matching (case-insensitive substring over title,\n * keywords, and description, plus trigger prefixes). Receives the bare\n * query in both modes — the slash-mode \"/\" prefix is stripped.\n */\n filter?: (items: readonly PickerItem[], query: string) => readonly PickerItem[]\n /** Overrides for the picker chrome's user-facing strings. */\n labels?: Partial<BlockInsertPickerLabels>\n /**\n * Notified after each successful insert — picker selection or input rule —\n * alongside the built-in open-for-editing behavior.\n */\n onInsert?: (event: PickerInsertEvent) => void\n /**\n * Whether an inserted block opens for editing (default true). Items can\n * override per member via their metadata's `openOnInsert`.\n */\n openOnInsert?: boolean\n /** Whether Cmd/Ctrl+/ opens the picker (default true). */\n shortcut?: boolean\n /**\n * Whether well-known block types (image, file, code, table, ...) get\n * default triggers and keywords when `items` doesn't cover them\n * (default true). See {@link standardBlockPresets}.\n */\n presets?: boolean\n /**\n * Escape hatch: names the portable-text array type to resolve items\n * against when Studio's member-schema context is unavailable. Normally\n * unnecessary — the containing array and its members are detected\n * automatically from where the plugin is mounted.\n */\n arrayTypeName?: string\n}\n\n/**\n * Creates the Portable Text editor plugins component for the block-insert\n * picker: a slash-command / Cmd+/ menu of the blocks the host array allows,\n * plus optional markdown input rules. Zero-config is the intended call —\n * items derive from the array the plugin is mounted on. Attach it to the\n * array type's `components.portableText.plugins`:\n *\n * ```ts\n * defineType({\n * name: 'content',\n * type: 'array',\n * of: [{type: 'block'}, {type: 'callout'}],\n * components: {\n * portableText: {\n * plugins: blockInsertPicker(),\n * },\n * },\n * })\n * ```\n */\nexport function blockInsertPicker(\n config: BlockInsertPickerConfig = {},\n): ComponentType<PortableTextPluginsProps> {\n const {\n arrayTypeName,\n filter,\n inputRules,\n items,\n labels,\n onInsert,\n openOnInsert,\n presets,\n resolveItems,\n shortcut,\n } = config\n return function BlockInsertPickerPlugins(props: PortableTextPluginsProps) {\n return (\n <>\n {props.renderDefault(props)}\n {inputRules?.length ? (\n <MarkdownInputRules\n arrayTypeName={arrayTypeName}\n onInsert={onInsert}\n openOnInsert={openOnInsert}\n rules={inputRules}\n />\n ) : null}\n <BlockInsertPicker\n arrayTypeName={arrayTypeName}\n filter={filter}\n items={items}\n labels={labels}\n onInsert={onInsert}\n openOnInsert={openOnInsert}\n presets={presets}\n resolveItems={resolveItems}\n shortcut={shortcut}\n />\n </>\n )\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,65 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/block-insert-picker",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Slash-command block-insert picker and markdown input rules for Portable Text fields in Sanity Studio",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
"block-insert",
|
|
7
|
+
"portable-text",
|
|
8
|
+
"sanity",
|
|
9
|
+
"sanity-plugin",
|
|
10
|
+
"slash-commands"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/sanity-io/plugins/tree/main/plugins/@sanity/block-insert-picker#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/sanity-io/plugins/issues"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "Sanity.io <hello@sanity.io>",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+ssh://git@github.com/sanity-io/plugins.git",
|
|
21
|
+
"directory": "plugins/@sanity/block-insert-picker"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": "./dist/index.js",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@portabletext/plugin-input-rule": "^6.0.4",
|
|
34
|
+
"@sanity/icons": "^5.2.0",
|
|
35
|
+
"@sanity/ui": "^3.4.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@portabletext/editor": "^7.10.7",
|
|
39
|
+
"@sanity/tsconfig": "^2.2.1",
|
|
40
|
+
"@sanity/tsdown-config": "^0.19.6",
|
|
41
|
+
"@testing-library/react": "^16.3.2",
|
|
42
|
+
"@types/node": "^24.13.3",
|
|
43
|
+
"@types/react": "^19.2.17",
|
|
44
|
+
"@types/react-dom": "^19.2.3",
|
|
45
|
+
"babel-plugin-react-compiler": "^1.0.0",
|
|
46
|
+
"jsdom": "^29.1.1",
|
|
47
|
+
"react": "^19.2.7",
|
|
48
|
+
"react-dom": "^19.2.7",
|
|
49
|
+
"sanity": "^6.5.0",
|
|
50
|
+
"styled-components": "^6.4.4",
|
|
51
|
+
"tsdown": "^0.22.12"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@portabletext/editor": "^7.10.7",
|
|
55
|
+
"react": "^19.2",
|
|
56
|
+
"sanity": "^5.6 || ^6.0.0-0",
|
|
57
|
+
"styled-components": "^6.1"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=20.19 <22 || >=22.12"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "tsdown"
|
|
64
|
+
}
|
|
65
|
+
}
|