@sanity/agent-directives 0.0.14 → 0.0.15
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/dist/lib/react.d.ts.map +1 -1
- package/dist/lib/react.js +21 -0
- package/dist/lib/react.js.map +1 -1
- package/package.json +2 -1
package/dist/lib/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","names":[],"sources":["../../src/lib/react.tsx"],"mappings":";;;;KAuBK,cAAA,WAAyB,aAAA,IAAiB,iBAAA,CAAkB,CAAA;AAAA,UAEhD,SAAA;EACf,IAAA;IAAS,UAAA,GAAa,MAAA;EAAA;AAAA;AAAA,KAGZ,oBAAA,eACI,aAAA,2EAGZ,cAAA,CAAe,KAAA;EACjB,QAAA;AAAA,KACG,oBAAA,gBACC,YAAA;EAEI,WAAA,EAAa,YAAA;AAAA;AAAA,KAKX,uBAAA,eAAsC,aAAA,IAAiB,cAAA,CAAe,KAAA;EAChF,MAAA;AAAA,IACE,SAAA;AApBJ;;;;;;;;;AAIA;;;;AAJA,
|
|
1
|
+
{"version":3,"file":"react.d.ts","names":[],"sources":["../../src/lib/react.tsx"],"mappings":";;;;KAuBK,cAAA,WAAyB,aAAA,IAAiB,iBAAA,CAAkB,CAAA;AAAA,UAEhD,SAAA;EACf,IAAA;IAAS,UAAA,GAAa,MAAA;EAAA;AAAA;AAAA,KAGZ,oBAAA,eACI,aAAA,2EAGZ,cAAA,CAAe,KAAA;EACjB,QAAA;AAAA,KACG,oBAAA,gBACC,YAAA;EAEI,WAAA,EAAa,YAAA;AAAA;AAAA,KAKX,uBAAA,eAAsC,aAAA,IAAiB,cAAA,CAAe,KAAA;EAChF,MAAA;AAAA,IACE,SAAA;AApBJ;;;;;;;;;AAIA;;;;AAJA,iBAuRgB,qBAAA,CAAsB,IAAA,EAAM,SAAA,IAAS,IAAA,EA9MrC,IAAA;AAAA,UAgOC,mBAAA;EACf,cAAA,IAAkB,MAAA,yBAA+B,YAAA;EACjD,4BAAA,GAA+B,aAAA;IAAgB,IAAA,EAAM,aAAA;IAAe,MAAA;EAAA;AAAA;;;;;;;;;;;;;AAzRtE;;;;iBA4SgB,kBAAA,0BAAA,CACd,OAAA,GAAS,mBAAA,CAAoB,YAAA;kCAKb,aAAA,+CACsB,IAAA,EAE9B,KAAA,EAAK,MAAA,GACF,KAAA,EAAO,oBAAA,CAAqB,KAAA,EAAO,YAAA,EAAc,oBAAA,MAA0B,SAAA,EAAS,gBAAA,GAC3E,sBAAA,KACjB,aAAA,CAAc,uBAAA,CAAwB,KAAA;AAAA"}
|
package/dist/lib/react.js
CHANGED
|
@@ -42,6 +42,27 @@ function remarkDirectivesTransform() {
|
|
|
42
42
|
children: label ? [{ type: "text", name: "", value: label }] : []
|
|
43
43
|
}, parentNode = parent;
|
|
44
44
|
parentNode?.children && typeof index == "number" && (parentNode.children[index] = directiveNode);
|
|
45
|
+
}), visit(tree, "tableCell", (node) => {
|
|
46
|
+
const cellNode = node;
|
|
47
|
+
if (cellNode.children)
|
|
48
|
+
for (let i = 0; i < cellNode.children.length; i++) {
|
|
49
|
+
const child = cellNode.children[i];
|
|
50
|
+
if (typeof child.value != "string") continue;
|
|
51
|
+
const match = child.value.match(BLOCK_DIRECTIVE);
|
|
52
|
+
if (!match) continue;
|
|
53
|
+
const [, name, label, attrsString] = match;
|
|
54
|
+
KNOWN_DIRECTIVE_NAMES.has(name) && (cellNode.children[i] = {
|
|
55
|
+
type: "textDirective",
|
|
56
|
+
name,
|
|
57
|
+
attributes: parseDirectiveAttributes(attrsString),
|
|
58
|
+
children: label ? [{ type: "text", name: "", value: label }] : []
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}), visit(tree, "tableCell", (node) => {
|
|
62
|
+
const cellNode = node;
|
|
63
|
+
if (cellNode.children)
|
|
64
|
+
for (const child of cellNode.children)
|
|
65
|
+
child.type === "leafDirective" && (child.type = "textDirective");
|
|
45
66
|
}), visit(
|
|
46
67
|
tree,
|
|
47
68
|
"list",
|
package/dist/lib/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","sources":["../../src/lib/react.tsx"],"sourcesContent":["import { pascalCase } from 'es-toolkit'\nimport { directiveFromMarkdown, directiveToMarkdown } from 'mdast-util-directive'\nimport { directive } from 'micromark-extension-directive'\nimport type { ComponentType, ReactNode } from 'react'\nimport type { Processor } from 'unified'\nimport type { Node } from 'unist'\nimport { visit } from 'unist-util-visit'\nimport {\n BLOCK_DIRECTIVE,\n type DefineDirectiveOptions,\n DIRECTIVE_NAMES,\n DIRECTIVE_TYPES,\n type DirectiveName,\n type DirectivePropsMap,\n DirectiveSchemas,\n type DirectiveType,\n parseDirectiveAttributes,\n} from '../_internal'\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DirectiveProps<T extends DirectiveName> = DirectivePropsMap[T]\n\nexport interface NodeProps {\n node?: { properties?: Record<string, unknown> }\n}\n\nexport type DirectiveRenderProps<\n TName extends DirectiveName,\n TApplication = undefined,\n TRequiresApplication extends boolean = true,\n> = DirectiveProps<TName> & {\n isInline: boolean\n} & (TRequiresApplication extends true\n ? TApplication extends undefined\n ? {}\n : { application: TApplication }\n : {})\n\nexport type { DefineDirectiveOptions }\n\nexport type DirectiveComponentProps<TName extends DirectiveName> = DirectiveProps<TName> & {\n source?: string\n} & NodeProps\n\n// ============================================================================\n// Remark Plugin Types\n// ============================================================================\n\ninterface DirectiveNode extends Node {\n type: 'textDirective' | 'leafDirective' | 'containerDirective'\n name: string\n attributes?: Record<string, string>\n children?: DirectiveNode[]\n value?: string\n data?: {\n hName?: string\n hProperties?: Record<string, unknown>\n }\n}\n\nconst isDirectiveNode = (node: Node): node is DirectiveNode =>\n 'name' in node &&\n typeof (node as DirectiveNode).name === 'string' &&\n /^[a-zA-Z-]+$/.test((node as DirectiveNode).name) &&\n DIRECTIVE_TYPES.includes(node.type as DirectiveType)\n\nconst isListItemWithOnlyDirective = (node: Node): boolean => {\n if (node.type !== 'listItem') return false\n const children = (node as DirectiveNode).children || []\n return children.length === 1 && children[0].type === 'leafDirective'\n}\n\nconst KNOWN_DIRECTIVE_NAMES: Set<string> = new Set(Object.values(DIRECTIVE_NAMES))\n\nfunction getTextContent(node: DirectiveNode): string {\n if (typeof node.value === 'string') return node.value\n if (!node.children) return ''\n return node.children.map((child) => getTextContent(child)).join('')\n}\n\n// ============================================================================\n// Remark Plugin\n// ============================================================================\n\n/**\n * Remark plugin that transforms directive syntax into React components.\n *\n * - Validates directive names (letters and hyphens only)\n * - Rescues unparsed block directives from paragraph text (lists, trailing text, streaming junk)\n * - Extracts directives from list items\n * - Groups consecutive leaf directives into DirectivesStack wrappers\n * - Filters incomplete streaming directives\n * - Converts directive names to PascalCase component names\n */\nfunction remarkDirectivesTransform() {\n return (tree: Node) => {\n // Remove invalid directive nodes (e.g., \":02\" in \"14:02\")\n visit(\n tree,\n DIRECTIVE_TYPES,\n (node: Node, index: number | undefined, parent: Node | undefined) => {\n if (!isDirectiveNode(node)) {\n const parentNode = parent as DirectiveNode | undefined\n if (parentNode?.children && typeof index === 'number') {\n const nodeName = 'name' in node ? String((node as DirectiveNode).name) : ''\n parentNode.children[index] = {\n type: 'text' as DirectiveType,\n name: '',\n value: `:${nodeName}`,\n } as DirectiveNode\n }\n }\n },\n )\n\n // Rescue unparsed block directives from paragraph text.\n // When the LLM outputs directives inside lists, with trailing text, or when\n // the streaming preprocessor appends junk characters (e.g. closing a `_`),\n // micromark cannot parse them as leaf directives because they require their\n // own line with no surrounding content. This step finds block directive\n // patterns in paragraph text and promotes them to proper directive nodes,\n // discarding any surrounding text on the same line.\n visit(tree, 'paragraph', (node: Node, index: number | undefined, parent: Node | undefined) => {\n const paragraphNode = node as DirectiveNode\n const text = getTextContent(paragraphNode)\n const match = text.match(BLOCK_DIRECTIVE)\n if (!match) return\n\n const [, name, label, attrsString] = match\n if (!KNOWN_DIRECTIVE_NAMES.has(name)) return\n\n const directiveNode: DirectiveNode = {\n type: 'leafDirective',\n name,\n attributes: parseDirectiveAttributes(attrsString),\n children: label\n ? [{ type: 'text' as DirectiveType, name: '', value: label } as DirectiveNode]\n : [],\n }\n\n const parentNode = parent as DirectiveNode | undefined\n if (parentNode?.children && typeof index === 'number') {\n parentNode.children[index] = directiveNode\n }\n })\n\n // Extract directives from list items\n visit(\n tree,\n 'list',\n (node: Node, index: number | undefined, parent: Node | undefined): number | undefined => {\n const listNode = node as DirectiveNode\n if (!listNode.children) return undefined\n\n const transformed: DirectiveNode[] = []\n let hasTransformed = false\n\n for (const child of listNode.children) {\n if (isListItemWithOnlyDirective(child) && child.children?.[0]) {\n transformed.push(child.children[0])\n hasTransformed = true\n } else {\n transformed.push(child)\n }\n }\n\n const parentNode = parent as DirectiveNode | undefined\n if (hasTransformed && transformed.every((n) => isDirectiveNode(n))) {\n if (parentNode?.children && typeof index === 'number') {\n parentNode.children.splice(index, 1, ...transformed)\n return index + transformed.length\n }\n }\n return undefined\n },\n )\n\n // Group consecutive leaf directives into DirectivesStack\n visit(tree, (node: Node) => {\n const dirNode = node as DirectiveNode\n if (!dirNode.children?.length || dirNode.data?.hName === 'DirectivesStack') return\n\n const newChildren: DirectiveNode[] = []\n let group: DirectiveNode[] = []\n\n for (const child of dirNode.children) {\n if (isDirectiveNode(child) && child.type === 'leafDirective') {\n group.push(child)\n } else {\n if (group.length > 0) {\n newChildren.push({\n type: 'leafDirective',\n name: 'DirectivesStack',\n data: { hName: 'DirectivesStack' },\n children: group,\n })\n group = []\n }\n newChildren.push(child)\n }\n }\n\n if (group.length > 0) {\n newChildren.push({\n type: 'leafDirective',\n name: 'DirectivesStack',\n data: { hName: 'DirectivesStack' },\n children: group,\n })\n }\n\n dirNode.children = newChildren\n })\n\n // Filter incomplete streaming directives\n visit(tree, 'text', (node: Node) => {\n const textNode = node as DirectiveNode\n if (typeof textNode.value === 'string') {\n if (textNode.value.match(/::?\\w+[{[]/) && !textNode.value.match(/::?\\w+[{[].+[}\\]]/)) {\n textNode.value = ''\n }\n }\n })\n\n // Transform directives to React components\n visit(tree, DIRECTIVE_TYPES, (node: Node) => {\n if (!isDirectiveNode(node)) return\n\n node.data = node.data || {}\n node.data.hName = pascalCase(node.name)\n node.data.hProperties = {\n ...node.attributes,\n isInline: node.type === 'textDirective',\n }\n })\n }\n}\n\ninterface RemarkData {\n micromarkExtensions?: unknown[]\n fromMarkdownExtensions?: unknown[]\n toMarkdownExtensions?: unknown[]\n}\n\n/**\n * Remark plugin for agent directive support.\n * Parses and transforms directive syntax into React components.\n *\n * @example\n * ```tsx\n * import { remarkAgentDirectives } from '@sanity/agent-directives/react'\n *\n * <ReactMarkdown remarkPlugins={[remarkAgentDirectives]}>\n * {content}\n * </ReactMarkdown>\n * ```\n */\nexport function remarkAgentDirectives(this: Processor) {\n const data = this.data() as RemarkData\n\n if (!data.micromarkExtensions) data.micromarkExtensions = []\n if (!data.fromMarkdownExtensions) data.fromMarkdownExtensions = []\n if (!data.toMarkdownExtensions) data.toMarkdownExtensions = []\n\n data.micromarkExtensions.push(directive())\n data.fromMarkdownExtensions.push(directiveFromMarkdown())\n data.toMarkdownExtensions.push(directiveToMarkdown())\n\n return remarkDirectivesTransform()\n}\n\n// ============================================================================\n// Directive Kit\n// ============================================================================\n\nexport interface DirectiveKitOptions<TApplication> {\n useApplication?: (source: string | undefined) => TApplication | undefined\n renderApplicationUnavailable?: ComponentType<{ name: DirectiveName; source?: string }>\n}\n\n/**\n * Creates a directive kit with application injection.\n *\n * @example\n * ```tsx\n * // kit.ts\n * export const { defineDirective } = createDirectiveKit<Application>({\n * useApplication: (source) => useThreadApplication(source),\n * })\n *\n * // Document.tsx\n * export const DocumentDirective = defineDirective('document', ({ id, application }) => {\n * return <DocumentCard id={id} app={application} />\n * })\n * ```\n */\nexport function createDirectiveKit<TApplication = undefined>(\n options: DirectiveKitOptions<TApplication> = {},\n) {\n const { useApplication, renderApplicationUnavailable: Unavailable } = options\n\n function defineDirective<\n TName extends DirectiveName,\n TRequiresApplication extends boolean = true,\n >(\n name: TName,\n render: (props: DirectiveRenderProps<TName, TApplication, TRequiresApplication>) => ReactNode,\n directiveOptions: DefineDirectiveOptions = {},\n ): ComponentType<DirectiveComponentProps<TName>> {\n const requiresContext =\n directiveOptions.requiresContext ?? directiveOptions.requiresApplication ?? true\n\n function Directive(props: DirectiveComponentProps<TName>): ReactNode {\n const { node, source, ...rest } = props\n\n const application = useApplication?.(source)\n if (requiresContext && useApplication && !application) {\n return Unavailable ? <Unavailable name={name} source={source} /> : null\n }\n\n const merged = {\n ...(node?.properties ?? {}),\n ...rest,\n ...(source !== undefined && { source }),\n }\n\n const schema = DirectiveSchemas[name]\n const result = schema.safeParse(merged)\n if (!result.success) {\n console.error(`Directive \"${name}\" validation error:`, result.error.format())\n return null\n }\n\n const renderProps = {\n ...(result.data as DirectiveProps<TName>),\n ...(requiresContext && useApplication ? { application } : {}),\n isInline: merged.isInline === true,\n } as DirectiveRenderProps<TName, TApplication, TRequiresApplication>\n\n return render(renderProps)\n }\n\n Directive.displayName = `Directive(${name})`\n return Directive\n }\n\n return { defineDirective }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react.js","sources":["../../src/lib/react.tsx"],"sourcesContent":["import { pascalCase } from 'es-toolkit'\nimport { directiveFromMarkdown, directiveToMarkdown } from 'mdast-util-directive'\nimport { directive } from 'micromark-extension-directive'\nimport type { ComponentType, ReactNode } from 'react'\nimport type { Processor } from 'unified'\nimport type { Node } from 'unist'\nimport { visit } from 'unist-util-visit'\nimport {\n BLOCK_DIRECTIVE,\n type DefineDirectiveOptions,\n DIRECTIVE_NAMES,\n DIRECTIVE_TYPES,\n type DirectiveName,\n type DirectivePropsMap,\n DirectiveSchemas,\n type DirectiveType,\n parseDirectiveAttributes,\n} from '../_internal'\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DirectiveProps<T extends DirectiveName> = DirectivePropsMap[T]\n\nexport interface NodeProps {\n node?: { properties?: Record<string, unknown> }\n}\n\nexport type DirectiveRenderProps<\n TName extends DirectiveName,\n TApplication = undefined,\n TRequiresApplication extends boolean = true,\n> = DirectiveProps<TName> & {\n isInline: boolean\n} & (TRequiresApplication extends true\n ? TApplication extends undefined\n ? {}\n : { application: TApplication }\n : {})\n\nexport type { DefineDirectiveOptions }\n\nexport type DirectiveComponentProps<TName extends DirectiveName> = DirectiveProps<TName> & {\n source?: string\n} & NodeProps\n\n// ============================================================================\n// Remark Plugin Types\n// ============================================================================\n\ninterface DirectiveNode extends Node {\n type: 'textDirective' | 'leafDirective' | 'containerDirective'\n name: string\n attributes?: Record<string, string>\n children?: DirectiveNode[]\n value?: string\n data?: {\n hName?: string\n hProperties?: Record<string, unknown>\n }\n}\n\nconst isDirectiveNode = (node: Node): node is DirectiveNode =>\n 'name' in node &&\n typeof (node as DirectiveNode).name === 'string' &&\n /^[a-zA-Z-]+$/.test((node as DirectiveNode).name) &&\n DIRECTIVE_TYPES.includes(node.type as DirectiveType)\n\nconst isListItemWithOnlyDirective = (node: Node): boolean => {\n if (node.type !== 'listItem') return false\n const children = (node as DirectiveNode).children || []\n return children.length === 1 && children[0].type === 'leafDirective'\n}\n\nconst KNOWN_DIRECTIVE_NAMES: Set<string> = new Set(Object.values(DIRECTIVE_NAMES))\n\nfunction getTextContent(node: DirectiveNode): string {\n if (typeof node.value === 'string') return node.value\n if (!node.children) return ''\n return node.children.map((child) => getTextContent(child)).join('')\n}\n\n// ============================================================================\n// Remark Plugin\n// ============================================================================\n\n/**\n * Remark plugin that transforms directive syntax into React components.\n *\n * - Validates directive names (letters and hyphens only)\n * - Rescues unparsed block directives from paragraph text (lists, trailing text, streaming junk)\n * - Extracts directives from list items\n * - Groups consecutive leaf directives into DirectivesStack wrappers\n * - Filters incomplete streaming directives\n * - Converts directive names to PascalCase component names\n */\nfunction remarkDirectivesTransform() {\n return (tree: Node) => {\n // Remove invalid directive nodes (e.g., \":02\" in \"14:02\")\n visit(\n tree,\n DIRECTIVE_TYPES,\n (node: Node, index: number | undefined, parent: Node | undefined) => {\n if (!isDirectiveNode(node)) {\n const parentNode = parent as DirectiveNode | undefined\n if (parentNode?.children && typeof index === 'number') {\n const nodeName = 'name' in node ? String((node as DirectiveNode).name) : ''\n parentNode.children[index] = {\n type: 'text' as DirectiveType,\n name: '',\n value: `:${nodeName}`,\n } as DirectiveNode\n }\n }\n },\n )\n\n // Rescue unparsed block directives from paragraph text.\n // When the LLM outputs directives inside lists, with trailing text, or when\n // the streaming preprocessor appends junk characters (e.g. closing a `_`),\n // micromark cannot parse them as leaf directives because they require their\n // own line with no surrounding content. This step finds block directive\n // patterns in paragraph text and promotes them to proper directive nodes,\n // discarding any surrounding text on the same line.\n visit(tree, 'paragraph', (node: Node, index: number | undefined, parent: Node | undefined) => {\n const paragraphNode = node as DirectiveNode\n const text = getTextContent(paragraphNode)\n const match = text.match(BLOCK_DIRECTIVE)\n if (!match) return\n\n const [, name, label, attrsString] = match\n if (!KNOWN_DIRECTIVE_NAMES.has(name)) return\n\n const directiveNode: DirectiveNode = {\n type: 'leafDirective',\n name,\n attributes: parseDirectiveAttributes(attrsString),\n children: label\n ? [{ type: 'text' as DirectiveType, name: '', value: label } as DirectiveNode]\n : [],\n }\n\n const parentNode = parent as DirectiveNode | undefined\n if (parentNode?.children && typeof index === 'number') {\n parentNode.children[index] = directiveNode\n }\n })\n\n // Rescue unparsed block directives from table cells.\n // Leaf directives (::name{attrs}) are registered as flow content in micromark,\n // but GFM table cells only contain text (phrasing) content. This means ::\n // directives render as plain text inside tables. We rescue them here and\n // convert to textDirective (inline) so they render with isInline=true.\n visit(tree, 'tableCell', (node: Node) => {\n const cellNode = node as DirectiveNode\n if (!cellNode.children) return\n\n for (let i = 0; i < cellNode.children.length; i++) {\n const child = cellNode.children[i]\n if (typeof child.value !== 'string') continue\n\n const match = child.value.match(BLOCK_DIRECTIVE)\n if (!match) continue\n\n const [, name, label, attrsString] = match\n if (!KNOWN_DIRECTIVE_NAMES.has(name)) continue\n\n cellNode.children[i] = {\n type: 'textDirective',\n name,\n attributes: parseDirectiveAttributes(attrsString),\n children: label\n ? [{ type: 'text' as DirectiveType, name: '', value: label } as DirectiveNode]\n : [],\n }\n }\n })\n\n // Downgrade any leafDirective inside a table cell to textDirective (inline).\n // This handles cases where a directive was already parsed but as the wrong\n // type for inline context (e.g. from a prior rescue pass or future parser changes).\n visit(tree, 'tableCell', (node: Node) => {\n const cellNode = node as DirectiveNode\n if (!cellNode.children) return\n\n for (const child of cellNode.children) {\n if (child.type === 'leafDirective') {\n child.type = 'textDirective'\n }\n }\n })\n\n // Extract directives from list items\n visit(\n tree,\n 'list',\n (node: Node, index: number | undefined, parent: Node | undefined): number | undefined => {\n const listNode = node as DirectiveNode\n if (!listNode.children) return undefined\n\n const transformed: DirectiveNode[] = []\n let hasTransformed = false\n\n for (const child of listNode.children) {\n if (isListItemWithOnlyDirective(child) && child.children?.[0]) {\n transformed.push(child.children[0])\n hasTransformed = true\n } else {\n transformed.push(child)\n }\n }\n\n const parentNode = parent as DirectiveNode | undefined\n if (hasTransformed && transformed.every((n) => isDirectiveNode(n))) {\n if (parentNode?.children && typeof index === 'number') {\n parentNode.children.splice(index, 1, ...transformed)\n return index + transformed.length\n }\n }\n return undefined\n },\n )\n\n // Group consecutive leaf directives into DirectivesStack\n visit(tree, (node: Node) => {\n const dirNode = node as DirectiveNode\n if (!dirNode.children?.length || dirNode.data?.hName === 'DirectivesStack') return\n\n const newChildren: DirectiveNode[] = []\n let group: DirectiveNode[] = []\n\n for (const child of dirNode.children) {\n if (isDirectiveNode(child) && child.type === 'leafDirective') {\n group.push(child)\n } else {\n if (group.length > 0) {\n newChildren.push({\n type: 'leafDirective',\n name: 'DirectivesStack',\n data: { hName: 'DirectivesStack' },\n children: group,\n })\n group = []\n }\n newChildren.push(child)\n }\n }\n\n if (group.length > 0) {\n newChildren.push({\n type: 'leafDirective',\n name: 'DirectivesStack',\n data: { hName: 'DirectivesStack' },\n children: group,\n })\n }\n\n dirNode.children = newChildren\n })\n\n // Filter incomplete streaming directives\n visit(tree, 'text', (node: Node) => {\n const textNode = node as DirectiveNode\n if (typeof textNode.value === 'string') {\n if (textNode.value.match(/::?\\w+[{[]/) && !textNode.value.match(/::?\\w+[{[].+[}\\]]/)) {\n textNode.value = ''\n }\n }\n })\n\n // Transform directives to React components\n visit(tree, DIRECTIVE_TYPES, (node: Node) => {\n if (!isDirectiveNode(node)) return\n\n node.data = node.data || {}\n node.data.hName = pascalCase(node.name)\n node.data.hProperties = {\n ...node.attributes,\n isInline: node.type === 'textDirective',\n }\n })\n }\n}\n\ninterface RemarkData {\n micromarkExtensions?: unknown[]\n fromMarkdownExtensions?: unknown[]\n toMarkdownExtensions?: unknown[]\n}\n\n/**\n * Remark plugin for agent directive support.\n * Parses and transforms directive syntax into React components.\n *\n * @example\n * ```tsx\n * import { remarkAgentDirectives } from '@sanity/agent-directives/react'\n *\n * <ReactMarkdown remarkPlugins={[remarkAgentDirectives]}>\n * {content}\n * </ReactMarkdown>\n * ```\n */\nexport function remarkAgentDirectives(this: Processor) {\n const data = this.data() as RemarkData\n\n if (!data.micromarkExtensions) data.micromarkExtensions = []\n if (!data.fromMarkdownExtensions) data.fromMarkdownExtensions = []\n if (!data.toMarkdownExtensions) data.toMarkdownExtensions = []\n\n data.micromarkExtensions.push(directive())\n data.fromMarkdownExtensions.push(directiveFromMarkdown())\n data.toMarkdownExtensions.push(directiveToMarkdown())\n\n return remarkDirectivesTransform()\n}\n\n// ============================================================================\n// Directive Kit\n// ============================================================================\n\nexport interface DirectiveKitOptions<TApplication> {\n useApplication?: (source: string | undefined) => TApplication | undefined\n renderApplicationUnavailable?: ComponentType<{ name: DirectiveName; source?: string }>\n}\n\n/**\n * Creates a directive kit with application injection.\n *\n * @example\n * ```tsx\n * // kit.ts\n * export const { defineDirective } = createDirectiveKit<Application>({\n * useApplication: (source) => useThreadApplication(source),\n * })\n *\n * // Document.tsx\n * export const DocumentDirective = defineDirective('document', ({ id, application }) => {\n * return <DocumentCard id={id} app={application} />\n * })\n * ```\n */\nexport function createDirectiveKit<TApplication = undefined>(\n options: DirectiveKitOptions<TApplication> = {},\n) {\n const { useApplication, renderApplicationUnavailable: Unavailable } = options\n\n function defineDirective<\n TName extends DirectiveName,\n TRequiresApplication extends boolean = true,\n >(\n name: TName,\n render: (props: DirectiveRenderProps<TName, TApplication, TRequiresApplication>) => ReactNode,\n directiveOptions: DefineDirectiveOptions = {},\n ): ComponentType<DirectiveComponentProps<TName>> {\n const requiresContext =\n directiveOptions.requiresContext ?? directiveOptions.requiresApplication ?? true\n\n function Directive(props: DirectiveComponentProps<TName>): ReactNode {\n const { node, source, ...rest } = props\n\n const application = useApplication?.(source)\n if (requiresContext && useApplication && !application) {\n return Unavailable ? <Unavailable name={name} source={source} /> : null\n }\n\n const merged = {\n ...(node?.properties ?? {}),\n ...rest,\n ...(source !== undefined && { source }),\n }\n\n const schema = DirectiveSchemas[name]\n const result = schema.safeParse(merged)\n if (!result.success) {\n console.error(`Directive \"${name}\" validation error:`, result.error.format())\n return null\n }\n\n const renderProps = {\n ...(result.data as DirectiveProps<TName>),\n ...(requiresContext && useApplication ? { application } : {}),\n isInline: merged.isInline === true,\n } as DirectiveRenderProps<TName, TApplication, TRequiresApplication>\n\n return render(renderProps)\n }\n\n Directive.displayName = `Directive(${name})`\n return Directive\n }\n\n return { defineDirective }\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/agent-directives",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Shared directive system for Sanity Agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"react": "^19.0.0",
|
|
59
59
|
"react-dom": "^19.0.0",
|
|
60
60
|
"react-markdown": "^10.0.0",
|
|
61
|
+
"remark-gfm": "^4.0.1",
|
|
61
62
|
"typescript": "^5.9.3",
|
|
62
63
|
"vitest": "^4.0.18",
|
|
63
64
|
"@repo/package.config": "0.0.0",
|