Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

@portabletext/toolkit

Package Overview
Dependencies
Maintainers
10
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@portabletext/toolkit - npm Package Compare versions

Comparing version
3.0.2
to
3.0.3-canary.0
+60
-54
dist/index.d.ts

@@ -1,7 +0,7 @@

import type {ArbitraryTypedObject} from '@portabletext/types'
import type {PortableTextBlock} from '@portabletext/types'
import type {PortableTextListItemBlock} from '@portabletext/types'
import type {PortableTextMarkDefinition} from '@portabletext/types'
import type {PortableTextSpan} from '@portabletext/types'
import type {TypedObject} from '@portabletext/types'
import type { ArbitraryTypedObject } from "@portabletext/types";
import type { PortableTextBlock } from "@portabletext/types";
import type { PortableTextListItemBlock } from "@portabletext/types";
import type { PortableTextMarkDefinition } from "@portabletext/types";
import type { PortableTextSpan } from "@portabletext/types";
import type { TypedObject } from "@portabletext/types";

@@ -43,3 +43,7 @@ /**

block: PortableTextBlock<M>,
): (ToolkitNestedPortableTextSpan<M> | ToolkitTextNode | ArbitraryTypedObject)[]
): (
| ToolkitNestedPortableTextSpan<M>
| ToolkitTextNode
| ArbitraryTypedObject
)[];

@@ -54,3 +58,3 @@ /**

node: PortableTextBlock | TypedObject,
): node is PortableTextBlock
): node is PortableTextBlock;

@@ -65,3 +69,3 @@ /**

block: PortableTextBlock | TypedObject,
): block is PortableTextListItemBlock
): block is PortableTextListItemBlock;

@@ -76,3 +80,3 @@ /**

node: ArbitraryTypedObject | PortableTextSpan,
): node is PortableTextSpan
): node is PortableTextSpan;

@@ -88,3 +92,3 @@ /**

block: TypedObject | ToolkitPortableTextList,
): block is ToolkitPortableTextList
): block is ToolkitPortableTextList;

@@ -100,3 +104,3 @@ /**

span: TypedObject | ToolkitNestedPortableTextSpan,
): span is ToolkitNestedPortableTextSpan
): span is ToolkitNestedPortableTextSpan;

@@ -112,3 +116,3 @@ /**

node: TypedObject | ToolkitTextNode,
): node is ToolkitTextNode
): node is ToolkitTextNode;

@@ -118,3 +122,3 @@ /**

*/
export declare const LIST_NEST_MODE_DIRECT = 'direct'
export declare const LIST_NEST_MODE_DIRECT = "direct";

@@ -124,3 +128,3 @@ /**

*/
export declare const LIST_NEST_MODE_HTML = 'html'
export declare const LIST_NEST_MODE_HTML = "html";

@@ -149,16 +153,16 @@ /**

*/
export declare function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(
blocks: T[],
mode: 'direct',
): (T | ToolkitPortableTextDirectList)[]
export declare function nestLists<
T extends TypedObject = PortableTextBlock | TypedObject,
>(blocks: T[], mode: "direct"): (T | ToolkitPortableTextDirectList)[];
export declare function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(
blocks: T[],
mode: 'html',
): (T | ToolkitPortableTextHtmlList)[]
export declare function nestLists<
T extends TypedObject = PortableTextBlock | TypedObject,
>(blocks: T[], mode: "html"): (T | ToolkitPortableTextHtmlList)[];
export declare function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(
export declare function nestLists<
T extends TypedObject = PortableTextBlock | TypedObject,
>(
blocks: T[],
mode: 'direct' | 'html',
): (T | ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList)[]
mode: "direct" | "html",
): (T | ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList)[];

@@ -206,3 +210,3 @@ /**

blockChildren: (PortableTextSpan | TypedObject)[],
): string[]
): string[];

@@ -219,3 +223,5 @@ /**

*/
export declare function spanToPlainText(span: ToolkitNestedPortableTextSpan): string
export declare function spanToPlainText(
span: ToolkitNestedPortableTextSpan,
): string;

@@ -225,3 +231,3 @@ /**

*/
export declare type ToolkitListNestMode = 'html' | 'direct'
export declare type ToolkitListNestMode = "html" | "direct";

@@ -238,7 +244,7 @@ /**

*/
_type: '@span'
_type: "@span";
/**
* Unique key for this span
*/
_key?: string
_key?: string;
/**

@@ -248,3 +254,3 @@ * Holds the value (definition) of the mark in the case of annotations.

*/
markDef?: M
markDef?: M;
/**

@@ -254,3 +260,3 @@ * The key of the mark definition (in the case of annotations).

*/
markKey?: string
markKey?: string;
/**

@@ -260,3 +266,3 @@ * Type of the mark. For annotations, this is the `_type` property of the value.

*/
markType: string
markType: string;
/**

@@ -268,5 +274,5 @@ * Child nodes of this span. Can be toolkit-specific text nodes, nested spans

| ToolkitTextNode
| ToolkitNestedPortableTextSpan<PortableTextMarkDefinition>
| ToolkitNestedPortableTextSpan
| ArbitraryTypedObject
)[]
)[];
}

@@ -277,3 +283,3 @@

| ToolkitPortableTextHtmlList
| ToolkitPortableTextDirectList
| ToolkitPortableTextDirectList;

@@ -288,23 +294,23 @@ /**

*/
_type: '@list'
_type: "@list";
/**
* Unique key for this list (within its parent)
*/
_key: string
_key: string;
/**
* List mode, signaling that list nodes can appear as direct children
*/
mode: 'direct'
mode: "direct";
/**
* Level/depth of this list node (starts at `1`)
*/
level: number
level: number;
/**
* Style of this list item (`bullet`, `number` are common values, but can be customized)
*/
listItem: string
listItem: string;
/**
* Child nodes of this list - either portable text list items, or another, deeper list
*/
children: (PortableTextListItemBlock | ToolkitPortableTextDirectList)[]
children: (PortableTextListItemBlock | ToolkitPortableTextDirectList)[];
}

@@ -320,23 +326,23 @@

*/
_type: '@list'
_type: "@list";
/**
* Unique key for this list (within its parent)
*/
_key: string
_key: string;
/**
* List mode, signaling that list nodes will appear as children of the _list items_
*/
mode: 'html'
mode: "html";
/**
* Level/depth of this list node (starts at `1`)
*/
level: number
level: number;
/**
* Style of this list item (`bullet`, `number` are common values, but can be customized)
*/
listItem: string
listItem: string;
/**
* Child nodes of this list - toolkit-specific list items which can themselves hold deeper lists
*/
children: ToolkitPortableTextListItem[]
children: ToolkitPortableTextListItem[];
}

@@ -351,3 +357,3 @@

| ToolkitPortableTextHtmlList
| ToolkitPortableTextDirectList
| ToolkitPortableTextDirectList;

@@ -372,7 +378,7 @@ /**

*/
_type: '@text'
_type: "@text";
/**
* The actual string value of the text node
*/
text: string
text: string;
}

@@ -393,4 +399,4 @@

block: PortableTextBlock | ArbitraryTypedObject[] | PortableTextBlock[],
): string
): string;
export {}
export {};
{
"name": "@portabletext/toolkit",
"version": "3.0.2",
"version": "3.0.3-canary.0",
"description": "Toolkit of handy utility functions for dealing with Portable Text",

@@ -28,4 +28,2 @@ "keywords": [

"source": "./src/index.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"default": "./dist/index.js"

@@ -35,4 +33,3 @@ },

},
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",

@@ -45,3 +42,2 @@ "files": [

"browserslist": "extends @sanity/browserslist-config",
"prettier": "@sanity/prettier-config",
"eslintConfig": {

@@ -57,4 +53,3 @@ "parserOptions": {

"sanity",
"sanity/typescript",
"prettier"
"sanity/typescript"
],

@@ -73,16 +68,16 @@ "ignorePatterns": [

"@sanity/pkg-utils": "^8.1.4",
"@sanity/prettier-config": "^2.0.1",
"@types/node": "^22.18.0",
"@types/node": "^24.10.0",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/coverage-v8": "^4.0.6",
"eslint": "^8.57.1",
"eslint-config-prettier": "^10.1.8",
"eslint-config-sanity": "^7.1.4",
"npm-run-all2": "^8.0.4",
"prettier": "^3.6.2",
"oxfmt": "^0.9.0",
"oxlint": "^1.25.0",
"oxlint-tsgolint": "^0.5.0",
"rimraf": "^4.4.1",
"typedoc": "^0.28.12",
"typescript": "5.9.2",
"vitest": "^3.2.4"
"vitest": "^4.0.6"
},

@@ -100,4 +95,4 @@ "engines": {

"docs:build": "typedoc",
"format": "prettier --write --cache --ignore-unknown .",
"lint": "eslint .",
"format": "oxfmt .",
"lint": "oxlint --deny-warnings --report-unused-disable-directives --type-aware",
"pkg:build": "pkg-utils build --strict",

@@ -104,0 +99,0 @@ "pkg:check": "pkg-utils --strict",

@@ -1,2 +0,2 @@

import type {PortableTextBlock, PortableTextListItemBlock, TypedObject} from '@portabletext/types'
import type { PortableTextBlock, PortableTextListItemBlock, TypedObject } from '@portabletext/types'

@@ -111,3 +111,3 @@ import {

} else {
;(currentList as ToolkitPortableTextDirectList).children.push(
; (currentList as ToolkitPortableTextDirectList).children.push(
newList as ToolkitPortableTextDirectList,

@@ -142,3 +142,3 @@ )

const matchingBranch = tree[tree.length - 1]
const match = matchingBranch && findListMatching(matchingBranch, {level: block.level || 1})
const match = matchingBranch && findListMatching(matchingBranch, { level: block.level || 1 })
if (match && match.listItem === block.listItem) {

@@ -145,0 +145,0 @@ currentList = match

@@ -109,3 +109,3 @@ import type {

PortableTextSpan | ToolkitPortableTextList
> {}
> { }

@@ -170,5 +170,5 @@ /**

| ToolkitTextNode
| ToolkitNestedPortableTextSpan<PortableTextMarkDefinition>
| ToolkitNestedPortableTextSpan
| ArbitraryTypedObject
)[]
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: !0 });
function isPortableTextSpan(node) {
return node._type === "span" && "text" in node && typeof node.text == "string" && (typeof node.marks > "u" || Array.isArray(node.marks) && node.marks.every((mark) => typeof mark == "string"));
}
function isPortableTextBlock(node) {
return (
// A block doesn't _have_ to be named 'block' - to differentiate between
// allowed child types and marks, one might name them differently
typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
(!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
"children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
node.children.every((child) => typeof child == "object" && "_type" in child)
);
}
function isPortableTextListItemBlock(block) {
return isPortableTextBlock(block) && "listItem" in block && typeof block.listItem == "string" && (typeof block.level > "u" || typeof block.level == "number");
}
function isPortableTextToolkitList(block) {
return block._type === "@list";
}
function isPortableTextToolkitSpan(span) {
return span._type === "@span";
}
function isPortableTextToolkitTextNode(node) {
return node._type === "@text";
}
const knownDecorators = ["strong", "em", "code", "underline", "strike-through"];
function sortMarksByOccurences(span, index, blockChildren) {
if (!isPortableTextSpan(span) || !span.marks)
return [];
if (!span.marks.length)
return [];
const marks = span.marks.slice(), occurences = {};
return marks.forEach((mark) => {
occurences[mark] = 1;
for (let siblingIndex = index + 1; siblingIndex < blockChildren.length; siblingIndex++) {
const sibling = blockChildren[siblingIndex];
if (sibling && isPortableTextSpan(sibling) && Array.isArray(sibling.marks) && sibling.marks.indexOf(mark) !== -1)
occurences[mark]++;
else
break;
}
}), marks.sort((markA, markB) => sortMarks(occurences, markA, markB));
}
function sortMarks(occurences, markA, markB) {
const aOccurences = occurences[markA], bOccurences = occurences[markB];
if (aOccurences !== bOccurences)
return bOccurences - aOccurences;
const aKnownPos = knownDecorators.indexOf(markA), bKnownPos = knownDecorators.indexOf(markB);
return aKnownPos !== bKnownPos ? aKnownPos - bKnownPos : markA.localeCompare(markB);
}
function buildMarksTree(block) {
const { children } = block, markDefs = block.markDefs ?? [];
if (!children || !children.length)
return [];
const sortedMarks = children.map(sortMarksByOccurences), rootNode = {
_type: "@span",
children: [],
markType: "<unknown>"
};
let nodeStack = [rootNode];
for (let i = 0; i < children.length; i++) {
const span = children[i];
if (!span)
continue;
const marksNeeded = sortedMarks[i] || [];
let pos = 1;
if (nodeStack.length > 1)
for (pos; pos < nodeStack.length; pos++) {
const mark = nodeStack[pos]?.markKey || "", index = marksNeeded.indexOf(mark);
if (index === -1)
break;
marksNeeded.splice(index, 1);
}
nodeStack = nodeStack.slice(0, pos);
let currentNode = nodeStack[nodeStack.length - 1];
if (currentNode) {
for (const markKey of marksNeeded) {
const markDef = markDefs?.find((def) => def._key === markKey), markType = markDef ? markDef._type : markKey, node = {
_type: "@span",
_key: span._key,
children: [],
markDef,
markType,
markKey
};
currentNode.children.push(node), nodeStack.push(node), currentNode = node;
}
if (isPortableTextSpan(span)) {
const lines = span.text.split(`
`);
for (let line = lines.length; line-- > 1; )
lines.splice(line, 0, `
`);
currentNode.children = currentNode.children.concat(
lines.map((text) => ({ _type: "@text", text }))
);
} else
currentNode.children = currentNode.children.concat(span);
}
}
return rootNode.children;
}
function nestLists(blocks, mode) {
const tree = [];
let currentList;
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i];
if (block) {
if (!isPortableTextListItemBlock(block)) {
tree.push(block), currentList = void 0;
continue;
}
if (!currentList) {
currentList = listFromBlock(block, i, mode), tree.push(currentList);
continue;
}
if (blockMatchesList(block, currentList)) {
currentList.children.push(block);
continue;
}
if ((block.level || 1) > currentList.level) {
const newList = listFromBlock(block, i, mode);
if (mode === "html") {
const lastListItem = currentList.children[currentList.children.length - 1], newLastChild = {
...lastListItem,
children: [...lastListItem.children, newList]
};
currentList.children[currentList.children.length - 1] = newLastChild;
} else
currentList.children.push(
newList
);
currentList = newList;
continue;
}
if ((block.level || 1) < currentList.level) {
const matchingBranch = tree[tree.length - 1], match = matchingBranch && findListMatching(matchingBranch, block);
if (match) {
currentList = match, currentList.children.push(block);
continue;
}
currentList = listFromBlock(block, i, mode), tree.push(currentList);
continue;
}
if (block.listItem !== currentList.listItem) {
const matchingBranch = tree[tree.length - 1], match = matchingBranch && findListMatching(matchingBranch, { level: block.level || 1 });
if (match && match.listItem === block.listItem) {
currentList = match, currentList.children.push(block);
continue;
} else {
currentList = listFromBlock(block, i, mode), tree.push(currentList);
continue;
}
}
console.warn("Unknown state encountered for block", block), tree.push(block);
}
}
return tree;
}
function blockMatchesList(block, list) {
return (block.level || 1) === list.level && block.listItem === list.listItem;
}
function listFromBlock(block, index, mode) {
return {
_type: "@list",
_key: `${block._key || `${index}`}-parent`,
mode,
level: block.level || 1,
listItem: block.listItem,
children: [block]
};
}
function findListMatching(rootNode, matching) {
const level = matching.level || 1, style = matching.listItem || "normal", filterOnType = typeof matching.listItem == "string";
if (isPortableTextToolkitList(rootNode) && (rootNode.level || 1) === level && filterOnType && (rootNode.listItem || "normal") === style)
return rootNode;
if (!("children" in rootNode))
return;
const node = rootNode.children[rootNode.children.length - 1];
return node && !isPortableTextSpan(node) ? findListMatching(node, matching) : void 0;
}
function spanToPlainText(span) {
let text = "";
return span.children.forEach((current) => {
isPortableTextToolkitTextNode(current) ? text += current.text : isPortableTextToolkitSpan(current) && (text += spanToPlainText(current));
}), text;
}
const leadingSpace = /^\s/, trailingSpace = /\s$/;
function toPlainText(block) {
const blocks = Array.isArray(block) ? block : [block];
let text = "";
return blocks.forEach((current, index) => {
if (!isPortableTextBlock(current))
return;
let pad = !1;
current.children.forEach((span) => {
isPortableTextSpan(span) ? (text += pad && text && !trailingSpace.test(text) && !leadingSpace.test(span.text) ? " " : "", text += span.text, pad = !1) : pad = !0;
}), index !== blocks.length - 1 && (text += `
`);
}), text;
}
const LIST_NEST_MODE_HTML = "html", LIST_NEST_MODE_DIRECT = "direct";
exports.LIST_NEST_MODE_DIRECT = LIST_NEST_MODE_DIRECT;
exports.LIST_NEST_MODE_HTML = LIST_NEST_MODE_HTML;
exports.buildMarksTree = buildMarksTree;
exports.isPortableTextBlock = isPortableTextBlock;
exports.isPortableTextListItemBlock = isPortableTextListItemBlock;
exports.isPortableTextSpan = isPortableTextSpan;
exports.isPortableTextToolkitList = isPortableTextToolkitList;
exports.isPortableTextToolkitSpan = isPortableTextToolkitSpan;
exports.isPortableTextToolkitTextNode = isPortableTextToolkitTextNode;
exports.nestLists = nestLists;
exports.sortMarksByOccurences = sortMarksByOccurences;
exports.spanToPlainText = spanToPlainText;
exports.toPlainText = toPlainText;
//# sourceMappingURL=index.cjs.map
{"version":3,"file":"index.cjs","sources":["../src/asserters.ts","../src/sortMarksByOccurences.ts","../src/buildMarksTree.ts","../src/nestLists.ts","../src/spanToPlainText.ts","../src/toPlainText.ts","../src/types.ts"],"sourcesContent":["import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n PortableTextListItemBlock,\n PortableTextSpan,\n TypedObject,\n} from '@portabletext/types'\n\nimport type {ToolkitNestedPortableTextSpan, ToolkitPortableTextList, ToolkitTextNode} from './types'\n\n/**\n * Strict check to determine if node is a correctly formatted Portable Text span.\n *\n * @param node - Node to check\n * @returns True if valid Portable Text span, otherwise false\n */\nexport function isPortableTextSpan(\n node: ArbitraryTypedObject | PortableTextSpan,\n): node is PortableTextSpan {\n return (\n node._type === 'span' &&\n 'text' in node &&\n typeof node.text === 'string' &&\n (typeof node.marks === 'undefined' ||\n (Array.isArray(node.marks) && node.marks.every((mark) => typeof mark === 'string')))\n )\n}\n\n/**\n * Strict check to determine if node is a correctly formatted Portable Text block.\n *\n * @param node - Node to check\n * @returns True if valid Portable Text block, otherwise false\n */\nexport function isPortableTextBlock(\n node: PortableTextBlock | TypedObject,\n): node is PortableTextBlock {\n return (\n // A block doesn't _have_ to be named 'block' - to differentiate between\n // allowed child types and marks, one might name them differently\n typeof node._type === 'string' &&\n // Toolkit-types like nested spans are @-prefixed\n node._type[0] !== '@' &&\n // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array\n (!('markDefs' in node) ||\n !node.markDefs ||\n (Array.isArray(node.markDefs) &&\n // Every mark definition needs to have an `_key` to be mappable in child spans\n node.markDefs.every((def) => typeof def._key === 'string'))) &&\n // `children` is required and needs to be an array\n 'children' in node &&\n Array.isArray(node.children) &&\n // All children are objects with `_type` (usually spans, but can contain other stuff)\n node.children.every((child) => typeof child === 'object' && '_type' in child)\n )\n}\n\n/**\n * Strict check to determine if node is a correctly formatted portable list item block.\n *\n * @param block - Block to check\n * @returns True if valid Portable Text list item block, otherwise false\n */\nexport function isPortableTextListItemBlock(\n block: PortableTextBlock | TypedObject,\n): block is PortableTextListItemBlock {\n return (\n isPortableTextBlock(block) &&\n 'listItem' in block &&\n typeof block.listItem === 'string' &&\n (typeof block.level === 'undefined' || typeof block.level === 'number')\n )\n}\n\n/**\n * Loose check to determine if block is a toolkit list node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param block - Block to check\n * @returns True if toolkit list, otherwise false\n */\nexport function isPortableTextToolkitList(\n block: TypedObject | ToolkitPortableTextList,\n): block is ToolkitPortableTextList {\n return block._type === '@list'\n}\n\n/**\n * Loose check to determine if span is a toolkit span node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param span - Span to check\n * @returns True if toolkit span, otherwise false\n */\nexport function isPortableTextToolkitSpan(\n span: TypedObject | ToolkitNestedPortableTextSpan,\n): span is ToolkitNestedPortableTextSpan {\n return span._type === '@span'\n}\n\n/**\n * Loose check to determine if node is a toolkit text node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param node - Node to check\n * @returns True if toolkit text node, otherwise false\n */\nexport function isPortableTextToolkitTextNode(\n node: TypedObject | ToolkitTextNode,\n): node is ToolkitTextNode {\n return node._type === '@text'\n}\n","import type {PortableTextSpan, TypedObject} from '@portabletext/types'\n\nimport {isPortableTextSpan} from './asserters'\n\nconst knownDecorators = ['strong', 'em', 'code', 'underline', 'strike-through']\n\n/**\n * Figures out the optimal order of marks, in order to minimize the amount of\n * nesting/repeated elements in environments such as HTML. For instance, a naive\n * implementation might render something like:\n *\n * ```html\n * <strong>This block contains </strong>\n * <strong><a href=\"https://some.url/\">a link</a></strong>\n * <strong> and some bolded text</strong>\n * ```\n *\n * ...whereas an optimal order would be:\n *\n * ```html\n * <strong>\n * This block contains <a href=\"https://some.url/\">a link</a> and some bolded text\n * </strong>\n * ```\n *\n * This is particularly necessary for cases like links, where you don't want multiple\n * individual links for different segments of the link text, even if parts of it are\n * bolded/italicized.\n *\n * This function is meant to be used like: `block.children.map(sortMarksByOccurences)`,\n * and is used internally in {@link buildMarksTree | `buildMarksTree()`}.\n *\n * The marks are sorted in the following order:\n *\n * 1. Marks that are shared amongst the most adjacent siblings\n * 2. Non-default marks (links, custom metadata)\n * 3. Decorators (bold, emphasis, code etc), in a predefined, preferred order\n *\n * @param span - The current span to sort\n * @param index - The index of the current span within the block\n * @param blockChildren - All children of the block being sorted\n * @returns Array of decorators and annotations, sorted by \"most adjacent siblings\"\n */\nexport function sortMarksByOccurences(\n span: PortableTextSpan | TypedObject,\n index: number,\n blockChildren: (PortableTextSpan | TypedObject)[],\n): string[] {\n if (!isPortableTextSpan(span) || !span.marks) {\n return []\n }\n\n if (!span.marks.length) {\n return []\n }\n\n // Slicing because we'll be sorting with `sort()`, which mutates\n const marks = span.marks.slice()\n const occurences: Record<string, number> = {}\n marks.forEach((mark) => {\n occurences[mark] = 1\n\n for (let siblingIndex = index + 1; siblingIndex < blockChildren.length; siblingIndex++) {\n const sibling = blockChildren[siblingIndex]\n\n if (\n sibling &&\n isPortableTextSpan(sibling) &&\n Array.isArray(sibling.marks) &&\n sibling.marks.indexOf(mark) !== -1\n ) {\n occurences[mark]++\n } else {\n break\n }\n }\n })\n\n return marks.sort((markA, markB) => sortMarks(occurences, markA, markB))\n}\n\nfunction sortMarks<U extends string, T extends Record<U, number>>(\n occurences: T,\n markA: U,\n markB: U,\n): number {\n const aOccurences = occurences[markA]\n const bOccurences = occurences[markB]\n\n if (aOccurences !== bOccurences) {\n return bOccurences - aOccurences\n }\n\n const aKnownPos = knownDecorators.indexOf(markA)\n const bKnownPos = knownDecorators.indexOf(markB)\n\n // Sort known decorators last\n if (aKnownPos !== bKnownPos) {\n return aKnownPos - bKnownPos\n }\n\n // Sort other marks simply by key\n return markA.localeCompare(markB)\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n PortableTextMarkDefinition,\n} from '@portabletext/types'\n\nimport {isPortableTextSpan} from './asserters'\nimport {sortMarksByOccurences} from './sortMarksByOccurences'\nimport type {ToolkitNestedPortableTextSpan, ToolkitTextNode} from './types'\n\n/**\n * Takes a Portable Text block and returns a nested tree of nodes optimized for rendering\n * in HTML-like environments where you want marks/annotations to be nested inside of eachother.\n * For instance, a naive span-by-span rendering might yield:\n *\n * ```html\n * <strong>This block contains </strong>\n * <strong><a href=\"https://some.url/\">a link</a></strong>\n * <strong> and some bolded and </strong>\n * <em><strong>italicized text</strong></em>\n * ```\n *\n * ...whereas an optimal order would be:\n *\n * ```html\n * <strong>\n * This block contains <a href=\"https://some.url/\">a link</a>\n * and some bolded and <em>italicized text</em>\n * </strong>\n * ```\n *\n * Note that since \"native\" Portable Text spans cannot be nested,\n * this function returns an array of \"toolkit specific\" types:\n * {@link ToolkitTextNode | `@text`} and {@link ToolkitNestedPortableTextSpan | `@span` }.\n *\n * The toolkit-specific type can hold both types, as well as any arbitrary inline objects,\n * creating an actual tree.\n *\n * @param block - The Portable Text block to create a tree of nodes from\n * @returns Array of (potentially) nested spans, text nodes and/or arbitrary inline objects\n */\nexport function buildMarksTree<M extends PortableTextMarkDefinition = PortableTextMarkDefinition>(\n block: PortableTextBlock<M>,\n): (ToolkitNestedPortableTextSpan<M> | ToolkitTextNode | ArbitraryTypedObject)[] {\n const {children} = block\n const markDefs = block.markDefs ?? []\n if (!children || !children.length) {\n return []\n }\n\n const sortedMarks = children.map(sortMarksByOccurences)\n\n const rootNode: ToolkitNestedPortableTextSpan<M> = {\n _type: '@span',\n children: [],\n markType: '<unknown>',\n }\n\n let nodeStack: ToolkitNestedPortableTextSpan<M>[] = [rootNode]\n\n for (let i = 0; i < children.length; i++) {\n const span = children[i]\n if (!span) {\n continue\n }\n\n const marksNeeded = sortedMarks[i] || []\n let pos = 1\n\n // Start at position one. Root is always plain and should never be removed\n if (nodeStack.length > 1) {\n for (pos; pos < nodeStack.length; pos++) {\n const mark = nodeStack[pos]?.markKey || ''\n const index = marksNeeded.indexOf(mark)\n\n if (index === -1) {\n break\n }\n\n marksNeeded.splice(index, 1)\n }\n }\n\n // Keep from beginning to first miss\n nodeStack = nodeStack.slice(0, pos)\n\n // Add needed nodes\n let currentNode = nodeStack[nodeStack.length - 1]\n if (!currentNode) {\n continue\n }\n\n for (const markKey of marksNeeded) {\n const markDef = markDefs?.find((def) => def._key === markKey)\n const markType = markDef ? markDef._type : markKey\n const node: ToolkitNestedPortableTextSpan<M> = {\n _type: '@span',\n _key: span._key,\n children: [],\n markDef,\n markType,\n markKey,\n }\n\n currentNode.children.push(node)\n nodeStack.push(node)\n currentNode = node\n }\n\n // Split at newlines to make individual line chunks, but keep newline\n // characters as individual elements in the array. We use these characters\n // in the span serializer to trigger hard-break rendering\n if (isPortableTextSpan(span)) {\n const lines = span.text.split('\\n')\n for (let line = lines.length; line-- > 1; ) {\n lines.splice(line, 0, '\\n')\n }\n\n currentNode.children = currentNode.children.concat(\n lines.map((text) => ({_type: '@text', text})),\n )\n } else {\n // This is some other inline object, not a text span\n currentNode.children = currentNode.children.concat(span)\n }\n }\n\n return rootNode.children\n}\n","import type {PortableTextBlock, PortableTextListItemBlock, TypedObject} from '@portabletext/types'\n\nimport {\n isPortableTextListItemBlock,\n isPortableTextSpan,\n isPortableTextToolkitList,\n} from './asserters'\nimport type {\n ToolkitListNestMode,\n ToolkitPortableTextDirectList,\n ToolkitPortableTextHtmlList,\n ToolkitPortableTextList,\n ToolkitPortableTextListItem,\n} from './types'\n\nexport type ToolkitNestListsOutputNode<T> =\n | T\n | ToolkitPortableTextHtmlList\n | ToolkitPortableTextDirectList\n\n/**\n * Takes an array of blocks and returns an array of nodes optimized for rendering in HTML-like\n * environment, where lists are nested inside of eachother instead of appearing \"flat\" as in\n * native Portable Text data structures.\n *\n * Note that the list node is not a native Portable Text node type, and thus is represented\n * using the {@link ToolkitPortableTextList | `@list`} type name (`{_type: '@list'}`).\n *\n * The nesting can be configured in two modes:\n *\n * - `direct`: deeper list nodes will appear as a direct child of the parent list\n * - `html`, deeper list nodes will appear as a child of the last _list item_ in the parent list\n *\n * When using `direct`, all list nodes will be of type {@link ToolkitPortableTextDirectList},\n * while with `html` they will be of type {@link ToolkitPortableTextHtmlList}\n *\n * These modes are available as {@link LIST_NEST_MODE_HTML} and {@link LIST_NEST_MODE_DIRECT}.\n *\n * @param blocks - Array of Portable Text blocks and other arbitrary types\n * @param mode - Mode to use for nesting, `direct` or `html`\n * @returns Array of potentially nested nodes optimized for rendering\n */\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'direct',\n): (T | ToolkitPortableTextDirectList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'html',\n): (T | ToolkitPortableTextHtmlList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'direct' | 'html',\n): (T | ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: ToolkitListNestMode,\n): ToolkitNestListsOutputNode<T>[] {\n const tree: ToolkitNestListsOutputNode<T>[] = []\n let currentList: ToolkitPortableTextList | undefined\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n if (!block) {\n continue\n }\n\n if (!isPortableTextListItemBlock(block)) {\n tree.push(block)\n currentList = undefined\n continue\n }\n\n // Start of a new list?\n if (!currentList) {\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n\n // New list item within same list?\n if (blockMatchesList(block, currentList)) {\n currentList.children.push(block)\n continue\n }\n\n // Different list props, are we going deeper?\n if ((block.level || 1) > currentList.level) {\n const newList = listFromBlock(block, i, mode)\n\n if (mode === 'html') {\n // Because HTML is kinda weird, nested lists needs to be nested within list items.\n // So while you would think that we could populate the parent list with a new sub-list,\n // we actually have to target the last list element (child) of the parent.\n // However, at this point we need to be very careful - simply pushing to the list of children\n // will mutate the input, and we don't want to blindly clone the entire tree.\n\n // Clone the last child while adding our new list as the last child of it\n const lastListItem = currentList.children[\n currentList.children.length - 1\n ] as ToolkitPortableTextListItem\n\n const newLastChild: ToolkitPortableTextListItem = {\n ...lastListItem,\n children: [...lastListItem.children, newList],\n }\n\n // Swap the last child\n currentList.children[currentList.children.length - 1] = newLastChild\n } else {\n ;(currentList as ToolkitPortableTextDirectList).children.push(\n newList as ToolkitPortableTextDirectList,\n )\n }\n\n // Set the newly created, deeper list as the current\n currentList = newList\n continue\n }\n\n // Different list props, are we going back up the tree?\n if ((block.level || 1) < currentList.level) {\n // Current list has ended, and we need to hook up with a parent of the same level and type\n const matchingBranch = tree[tree.length - 1]\n const match = matchingBranch && findListMatching(matchingBranch, block)\n if (match) {\n currentList = match\n currentList.children.push(block)\n continue\n }\n\n // Similar parent can't be found, assume new list\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n\n // Different list props, different list style?\n if (block.listItem !== currentList.listItem) {\n const matchingBranch = tree[tree.length - 1]\n const match = matchingBranch && findListMatching(matchingBranch, {level: block.level || 1})\n if (match && match.listItem === block.listItem) {\n currentList = match\n currentList.children.push(block)\n continue\n } else {\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n }\n\n // eslint-disable-next-line no-console\n console.warn('Unknown state encountered for block', block)\n tree.push(block)\n }\n\n return tree\n}\n\nfunction blockMatchesList(block: PortableTextBlock, list: ToolkitPortableTextList) {\n return (block.level || 1) === list.level && block.listItem === list.listItem\n}\n\nfunction listFromBlock(\n block: PortableTextListItemBlock,\n index: number,\n mode: ToolkitListNestMode,\n): ToolkitPortableTextList {\n return {\n _type: '@list',\n _key: `${block._key || `${index}`}-parent`,\n mode,\n level: block.level || 1,\n listItem: block.listItem,\n children: [block],\n }\n}\n\nfunction findListMatching<T extends TypedObject | PortableTextBlock>(\n rootNode: T,\n matching: Partial<PortableTextListItemBlock>,\n): ToolkitPortableTextList | undefined {\n const level = matching.level || 1\n const style = matching.listItem || 'normal'\n const filterOnType = typeof matching.listItem === 'string'\n if (\n isPortableTextToolkitList(rootNode) &&\n (rootNode.level || 1) === level &&\n filterOnType &&\n (rootNode.listItem || 'normal') === style\n ) {\n return rootNode\n }\n\n if (!('children' in rootNode)) {\n return undefined\n }\n\n const node = rootNode.children[rootNode.children.length - 1]\n return node && !isPortableTextSpan(node) ? findListMatching(node, matching) : undefined\n}\n","import {isPortableTextToolkitSpan, isPortableTextToolkitTextNode} from './asserters'\nimport type {ToolkitNestedPortableTextSpan} from './types'\n\n/**\n * Returns the plain-text representation of a\n * {@link ToolkitNestedPortableTextSpan | toolkit-specific Portable Text span}.\n *\n * Useful if you have a subset of nested nodes and want the text from just those,\n * instead of for the entire Portable Text block.\n *\n * @param span - Span node to get text from (Portable Text toolkit specific type)\n * @returns The plain-text version of the span\n */\nexport function spanToPlainText(span: ToolkitNestedPortableTextSpan): string {\n let text = ''\n span.children.forEach((current) => {\n if (isPortableTextToolkitTextNode(current)) {\n text += current.text\n } else if (isPortableTextToolkitSpan(current)) {\n text += spanToPlainText(current)\n }\n })\n return text\n}\n","import type {ArbitraryTypedObject, PortableTextBlock} from '@portabletext/types'\n\nimport {isPortableTextBlock, isPortableTextSpan} from './asserters'\n\nconst leadingSpace = /^\\s/\nconst trailingSpace = /\\s$/\n\n/**\n * Takes a Portable Text block (or an array of them) and returns the text value\n * of all the Portable Text span nodes. Adds whitespace when encountering inline,\n * non-span nodes to ensure text flow is optimal.\n *\n * Note that this only accounts for regular Portable Text blocks - any text inside\n * custom content types are not included in the output.\n *\n * @param block - Single block or an array of blocks to extract text from\n * @returns The plain-text content of the blocks\n */\nexport function toPlainText(\n block: PortableTextBlock | ArbitraryTypedObject[] | PortableTextBlock[],\n): string {\n const blocks = Array.isArray(block) ? block : [block]\n let text = ''\n\n blocks.forEach((current, index) => {\n if (!isPortableTextBlock(current)) {\n return\n }\n\n let pad = false\n current.children.forEach((span) => {\n if (isPortableTextSpan(span)) {\n // If the previous element was a non-span, and we have no natural whitespace\n // between the previous and the next span, insert it to give the spans some\n // room to breathe. However, don't do so if this is the first span.\n text += pad && text && !trailingSpace.test(text) && !leadingSpace.test(span.text) ? ' ' : ''\n text += span.text\n pad = false\n } else {\n pad = true\n }\n })\n\n if (index !== blocks.length - 1) {\n text += '\\n\\n'\n }\n })\n\n return text\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextListItemBlock,\n PortableTextMarkDefinition,\n PortableTextSpan,\n} from '@portabletext/types'\n\n/**\n * List nesting mode for HTML, see the {@link nestLists | `nestLists()` function}\n */\nexport const LIST_NEST_MODE_HTML = 'html'\n\n/**\n * List nesting mode for direct, nested lists, see the {@link nestLists | `nestLists()` function}\n */\nexport const LIST_NEST_MODE_DIRECT = 'direct'\n\n/**\n * List nesting mode, see the {@link nestLists | `nestLists()` function}\n */\nexport type ToolkitListNestMode = 'html' | 'direct'\n\n/**\n * Toolkit-specific type representing a nested list\n *\n * See the `nestLists()` function for more info\n */\nexport type ToolkitPortableTextList = ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList\n\n/**\n * Toolkit-specific type representing a nested list in HTML mode, where deeper lists are nested\n * inside of the _list items_, eg `<ul><li>Some text<ul><li>Deeper</li></ul></li></ul>`\n */\nexport interface ToolkitPortableTextHtmlList {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@list'\n\n /**\n * Unique key for this list (within its parent)\n */\n _key: string\n\n /**\n * List mode, signaling that list nodes will appear as children of the _list items_\n */\n mode: 'html'\n\n /**\n * Level/depth of this list node (starts at `1`)\n */\n level: number\n\n /**\n * Style of this list item (`bullet`, `number` are common values, but can be customized)\n */\n listItem: string\n\n /**\n * Child nodes of this list - toolkit-specific list items which can themselves hold deeper lists\n */\n children: ToolkitPortableTextListItem[]\n}\n\n/**\n * Toolkit-specific type representing a nested list in \"direct\" mode, where deeper lists are nested\n * inside of the lists children, alongside other blocks.\n */\nexport interface ToolkitPortableTextDirectList {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@list'\n\n /**\n * Unique key for this list (within its parent)\n */\n _key: string\n\n /**\n * List mode, signaling that list nodes can appear as direct children\n */\n mode: 'direct'\n\n /**\n * Level/depth of this list node (starts at `1`)\n */\n level: number\n\n /**\n * Style of this list item (`bullet`, `number` are common values, but can be customized)\n */\n listItem: string\n\n /**\n * Child nodes of this list - either portable text list items, or another, deeper list\n */\n children: (PortableTextListItemBlock | ToolkitPortableTextDirectList)[]\n}\n\n/**\n * Toolkit-specific type representing a list item block, but where the children can be another list\n */\nexport interface ToolkitPortableTextListItem\n extends PortableTextListItemBlock<\n PortableTextMarkDefinition,\n PortableTextSpan | ToolkitPortableTextList\n > {}\n\n/**\n * Toolkit-specific type representing a text node, used when nesting spans.\n *\n * See the {@link buildMarksTree | `buildMarksTree()` function}\n */\nexport interface ToolkitTextNode {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@text'\n\n /**\n * The actual string value of the text node\n */\n text: string\n}\n\n/**\n * Toolkit-specific type representing a portable text span that can hold other spans.\n * In this type, each span only has a single mark, instead of an array of them.\n */\nexport interface ToolkitNestedPortableTextSpan<\n M extends PortableTextMarkDefinition = PortableTextMarkDefinition,\n> {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@span'\n\n /**\n * Unique key for this span\n */\n _key?: string\n\n /**\n * Holds the value (definition) of the mark in the case of annotations.\n * `undefined` if the mark is a decorator (strong, em or similar).\n */\n markDef?: M\n\n /**\n * The key of the mark definition (in the case of annotations).\n * `undefined` if the mark is a decorator (strong, em or similar).\n */\n markKey?: string\n\n /**\n * Type of the mark. For annotations, this is the `_type` property of the value.\n * For decorators, it will hold the name of the decorator (strong, em or similar).\n */\n markType: string\n\n /**\n * Child nodes of this span. Can be toolkit-specific text nodes, nested spans\n * or any inline object type.\n */\n children: (\n | ToolkitTextNode\n | ToolkitNestedPortableTextSpan<PortableTextMarkDefinition>\n | ArbitraryTypedObject\n )[]\n}\n"],"names":[],"mappings":"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"}
import type {ArbitraryTypedObject} from '@portabletext/types'
import type {PortableTextBlock} from '@portabletext/types'
import type {PortableTextListItemBlock} from '@portabletext/types'
import type {PortableTextMarkDefinition} from '@portabletext/types'
import type {PortableTextSpan} from '@portabletext/types'
import type {TypedObject} from '@portabletext/types'
/**
* Takes a Portable Text block and returns a nested tree of nodes optimized for rendering
* in HTML-like environments where you want marks/annotations to be nested inside of eachother.
* For instance, a naive span-by-span rendering might yield:
*
* ```html
* <strong>This block contains </strong>
* <strong><a href="https://some.url/">a link</a></strong>
* <strong> and some bolded and </strong>
* <em><strong>italicized text</strong></em>
* ```
*
* ...whereas an optimal order would be:
*
* ```html
* <strong>
* This block contains <a href="https://some.url/">a link</a>
* and some bolded and <em>italicized text</em>
* </strong>
* ```
*
* Note that since "native" Portable Text spans cannot be nested,
* this function returns an array of "toolkit specific" types:
* {@link ToolkitTextNode | `@text`} and {@link ToolkitNestedPortableTextSpan | `@span` }.
*
* The toolkit-specific type can hold both types, as well as any arbitrary inline objects,
* creating an actual tree.
*
* @param block - The Portable Text block to create a tree of nodes from
* @returns Array of (potentially) nested spans, text nodes and/or arbitrary inline objects
*/
export declare function buildMarksTree<
M extends PortableTextMarkDefinition = PortableTextMarkDefinition,
>(
block: PortableTextBlock<M>,
): (ToolkitNestedPortableTextSpan<M> | ToolkitTextNode | ArbitraryTypedObject)[]
/**
* Strict check to determine if node is a correctly formatted Portable Text block.
*
* @param node - Node to check
* @returns True if valid Portable Text block, otherwise false
*/
export declare function isPortableTextBlock(
node: PortableTextBlock | TypedObject,
): node is PortableTextBlock
/**
* Strict check to determine if node is a correctly formatted portable list item block.
*
* @param block - Block to check
* @returns True if valid Portable Text list item block, otherwise false
*/
export declare function isPortableTextListItemBlock(
block: PortableTextBlock | TypedObject,
): block is PortableTextListItemBlock
/**
* Strict check to determine if node is a correctly formatted Portable Text span.
*
* @param node - Node to check
* @returns True if valid Portable Text span, otherwise false
*/
export declare function isPortableTextSpan(
node: ArbitraryTypedObject | PortableTextSpan,
): node is PortableTextSpan
/**
* Loose check to determine if block is a toolkit list node.
* Only checks `_type`, assumes correct structure.
*
* @param block - Block to check
* @returns True if toolkit list, otherwise false
*/
export declare function isPortableTextToolkitList(
block: TypedObject | ToolkitPortableTextList,
): block is ToolkitPortableTextList
/**
* Loose check to determine if span is a toolkit span node.
* Only checks `_type`, assumes correct structure.
*
* @param span - Span to check
* @returns True if toolkit span, otherwise false
*/
export declare function isPortableTextToolkitSpan(
span: TypedObject | ToolkitNestedPortableTextSpan,
): span is ToolkitNestedPortableTextSpan
/**
* Loose check to determine if node is a toolkit text node.
* Only checks `_type`, assumes correct structure.
*
* @param node - Node to check
* @returns True if toolkit text node, otherwise false
*/
export declare function isPortableTextToolkitTextNode(
node: TypedObject | ToolkitTextNode,
): node is ToolkitTextNode
/**
* List nesting mode for direct, nested lists, see the {@link nestLists | `nestLists()` function}
*/
export declare const LIST_NEST_MODE_DIRECT = 'direct'
/**
* List nesting mode for HTML, see the {@link nestLists | `nestLists()` function}
*/
export declare const LIST_NEST_MODE_HTML = 'html'
/**
* Takes an array of blocks and returns an array of nodes optimized for rendering in HTML-like
* environment, where lists are nested inside of eachother instead of appearing "flat" as in
* native Portable Text data structures.
*
* Note that the list node is not a native Portable Text node type, and thus is represented
* using the {@link ToolkitPortableTextList | `@list`} type name (`{_type: '@list'}`).
*
* The nesting can be configured in two modes:
*
* - `direct`: deeper list nodes will appear as a direct child of the parent list
* - `html`, deeper list nodes will appear as a child of the last _list item_ in the parent list
*
* When using `direct`, all list nodes will be of type {@link ToolkitPortableTextDirectList},
* while with `html` they will be of type {@link ToolkitPortableTextHtmlList}
*
* These modes are available as {@link LIST_NEST_MODE_HTML} and {@link LIST_NEST_MODE_DIRECT}.
*
* @param blocks - Array of Portable Text blocks and other arbitrary types
* @param mode - Mode to use for nesting, `direct` or `html`
* @returns Array of potentially nested nodes optimized for rendering
*/
export declare function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(
blocks: T[],
mode: 'direct',
): (T | ToolkitPortableTextDirectList)[]
export declare function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(
blocks: T[],
mode: 'html',
): (T | ToolkitPortableTextHtmlList)[]
export declare function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(
blocks: T[],
mode: 'direct' | 'html',
): (T | ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList)[]
/**
* Figures out the optimal order of marks, in order to minimize the amount of
* nesting/repeated elements in environments such as HTML. For instance, a naive
* implementation might render something like:
*
* ```html
* <strong>This block contains </strong>
* <strong><a href="https://some.url/">a link</a></strong>
* <strong> and some bolded text</strong>
* ```
*
* ...whereas an optimal order would be:
*
* ```html
* <strong>
* This block contains <a href="https://some.url/">a link</a> and some bolded text
* </strong>
* ```
*
* This is particularly necessary for cases like links, where you don't want multiple
* individual links for different segments of the link text, even if parts of it are
* bolded/italicized.
*
* This function is meant to be used like: `block.children.map(sortMarksByOccurences)`,
* and is used internally in {@link buildMarksTree | `buildMarksTree()`}.
*
* The marks are sorted in the following order:
*
* 1. Marks that are shared amongst the most adjacent siblings
* 2. Non-default marks (links, custom metadata)
* 3. Decorators (bold, emphasis, code etc), in a predefined, preferred order
*
* @param span - The current span to sort
* @param index - The index of the current span within the block
* @param blockChildren - All children of the block being sorted
* @returns Array of decorators and annotations, sorted by "most adjacent siblings"
*/
export declare function sortMarksByOccurences(
span: PortableTextSpan | TypedObject,
index: number,
blockChildren: (PortableTextSpan | TypedObject)[],
): string[]
/**
* Returns the plain-text representation of a
* {@link ToolkitNestedPortableTextSpan | toolkit-specific Portable Text span}.
*
* Useful if you have a subset of nested nodes and want the text from just those,
* instead of for the entire Portable Text block.
*
* @param span - Span node to get text from (Portable Text toolkit specific type)
* @returns The plain-text version of the span
*/
export declare function spanToPlainText(span: ToolkitNestedPortableTextSpan): string
/**
* List nesting mode, see the {@link nestLists | `nestLists()` function}
*/
export declare type ToolkitListNestMode = 'html' | 'direct'
/**
* Toolkit-specific type representing a portable text span that can hold other spans.
* In this type, each span only has a single mark, instead of an array of them.
*/
export declare interface ToolkitNestedPortableTextSpan<
M extends PortableTextMarkDefinition = PortableTextMarkDefinition,
> {
/**
* Type name, prefixed with `@` to signal that this is a toolkit-specific node.
*/
_type: '@span'
/**
* Unique key for this span
*/
_key?: string
/**
* Holds the value (definition) of the mark in the case of annotations.
* `undefined` if the mark is a decorator (strong, em or similar).
*/
markDef?: M
/**
* The key of the mark definition (in the case of annotations).
* `undefined` if the mark is a decorator (strong, em or similar).
*/
markKey?: string
/**
* Type of the mark. For annotations, this is the `_type` property of the value.
* For decorators, it will hold the name of the decorator (strong, em or similar).
*/
markType: string
/**
* Child nodes of this span. Can be toolkit-specific text nodes, nested spans
* or any inline object type.
*/
children: (
| ToolkitTextNode
| ToolkitNestedPortableTextSpan<PortableTextMarkDefinition>
| ArbitraryTypedObject
)[]
}
export declare type ToolkitNestListsOutputNode<T> =
| T
| ToolkitPortableTextHtmlList
| ToolkitPortableTextDirectList
/**
* Toolkit-specific type representing a nested list in "direct" mode, where deeper lists are nested
* inside of the lists children, alongside other blocks.
*/
export declare interface ToolkitPortableTextDirectList {
/**
* Type name, prefixed with `@` to signal that this is a toolkit-specific node.
*/
_type: '@list'
/**
* Unique key for this list (within its parent)
*/
_key: string
/**
* List mode, signaling that list nodes can appear as direct children
*/
mode: 'direct'
/**
* Level/depth of this list node (starts at `1`)
*/
level: number
/**
* Style of this list item (`bullet`, `number` are common values, but can be customized)
*/
listItem: string
/**
* Child nodes of this list - either portable text list items, or another, deeper list
*/
children: (PortableTextListItemBlock | ToolkitPortableTextDirectList)[]
}
/**
* Toolkit-specific type representing a nested list in HTML mode, where deeper lists are nested
* inside of the _list items_, eg `<ul><li>Some text<ul><li>Deeper</li></ul></li></ul>`
*/
export declare interface ToolkitPortableTextHtmlList {
/**
* Type name, prefixed with `@` to signal that this is a toolkit-specific node.
*/
_type: '@list'
/**
* Unique key for this list (within its parent)
*/
_key: string
/**
* List mode, signaling that list nodes will appear as children of the _list items_
*/
mode: 'html'
/**
* Level/depth of this list node (starts at `1`)
*/
level: number
/**
* Style of this list item (`bullet`, `number` are common values, but can be customized)
*/
listItem: string
/**
* Child nodes of this list - toolkit-specific list items which can themselves hold deeper lists
*/
children: ToolkitPortableTextListItem[]
}
/**
* Toolkit-specific type representing a nested list
*
* See the `nestLists()` function for more info
*/
export declare type ToolkitPortableTextList =
| ToolkitPortableTextHtmlList
| ToolkitPortableTextDirectList
/**
* Toolkit-specific type representing a list item block, but where the children can be another list
*/
export declare interface ToolkitPortableTextListItem
extends PortableTextListItemBlock<
PortableTextMarkDefinition,
PortableTextSpan | ToolkitPortableTextList
> {}
/**
* Toolkit-specific type representing a text node, used when nesting spans.
*
* See the {@link buildMarksTree | `buildMarksTree()` function}
*/
export declare interface ToolkitTextNode {
/**
* Type name, prefixed with `@` to signal that this is a toolkit-specific node.
*/
_type: '@text'
/**
* The actual string value of the text node
*/
text: string
}
/**
* Takes a Portable Text block (or an array of them) and returns the text value
* of all the Portable Text span nodes. Adds whitespace when encountering inline,
* non-span nodes to ensure text flow is optimal.
*
* Note that this only accounts for regular Portable Text blocks - any text inside
* custom content types are not included in the output.
*
* @param block - Single block or an array of blocks to extract text from
* @returns The plain-text content of the blocks
*/
export declare function toPlainText(
block: PortableTextBlock | ArbitraryTypedObject[] | PortableTextBlock[],
): string
export {}

Sorry, the diff of this file is not supported yet