@valkyrianlabs/payload-markdown 1.3.4 → 1.4.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.
Files changed (118) hide show
  1. package/README.md +64 -15
  2. package/dist/components/MarkdownRenderer/index.css +150 -0
  3. package/dist/components/MarkdownRenderer/index.scss +158 -0
  4. package/dist/core/plugins/rehypeResolveIcons.d.ts +4 -0
  5. package/dist/core/plugins/rehypeResolveIcons.js +27 -0
  6. package/dist/core/plugins/rehypeResolveIcons.js.map +1 -0
  7. package/dist/core/plugins/remarkButtonDirectives.d.ts +4 -0
  8. package/dist/core/plugins/remarkButtonDirectives.js +237 -0
  9. package/dist/core/plugins/remarkButtonDirectives.js.map +1 -0
  10. package/dist/core/plugins/remarkCompileLayouts.js +6 -5
  11. package/dist/core/plugins/remarkCompileLayouts.js.map +1 -1
  12. package/dist/core/plugins/remarkLayoutDirectives.js +17 -7
  13. package/dist/core/plugins/remarkLayoutDirectives.js.map +1 -1
  14. package/dist/core/plugins/remarkLiftLayoutDirectives.js +42 -4
  15. package/dist/core/plugins/remarkLiftLayoutDirectives.js.map +1 -1
  16. package/dist/core/renderMarkdown.js +27 -2
  17. package/dist/core/renderMarkdown.js.map +1 -1
  18. package/dist/directives/attributeDiagnostics.d.ts +2 -0
  19. package/dist/directives/attributeDiagnostics.js +35 -0
  20. package/dist/directives/attributeDiagnostics.js.map +1 -0
  21. package/dist/directives/attributes.d.ts +8 -0
  22. package/dist/directives/attributes.js +56 -5
  23. package/dist/directives/attributes.js.map +1 -1
  24. package/dist/directives/buttonSyntax.d.ts +7 -0
  25. package/dist/directives/buttonSyntax.js +26 -0
  26. package/dist/directives/buttonSyntax.js.map +1 -0
  27. package/dist/directives/closeLabels.d.ts +8 -0
  28. package/dist/directives/closeLabels.js +76 -0
  29. package/dist/directives/closeLabels.js.map +1 -0
  30. package/dist/directives/definitions/button.d.ts +15 -0
  31. package/dist/directives/definitions/button.js +96 -0
  32. package/dist/directives/definitions/button.js.map +1 -0
  33. package/dist/directives/definitions/buttons.d.ts +8 -0
  34. package/dist/directives/definitions/buttons.js +82 -0
  35. package/dist/directives/definitions/buttons.js.map +1 -0
  36. package/dist/directives/definitions/callout.js +20 -9
  37. package/dist/directives/definitions/callout.js.map +1 -1
  38. package/dist/directives/definitions/card.d.ts +4 -0
  39. package/dist/directives/definitions/card.js +90 -9
  40. package/dist/directives/definitions/card.js.map +1 -1
  41. package/dist/directives/definitions/cards.d.ts +4 -0
  42. package/dist/directives/definitions/cards.js +119 -4
  43. package/dist/directives/definitions/cards.js.map +1 -1
  44. package/dist/directives/definitions/details.js +4 -3
  45. package/dist/directives/definitions/details.js.map +1 -1
  46. package/dist/directives/definitions/tab.d.ts +1 -0
  47. package/dist/directives/definitions/tab.js +10 -3
  48. package/dist/directives/definitions/tab.js.map +1 -1
  49. package/dist/directives/definitions/tabs.js +3 -3
  50. package/dist/directives/definitions/tabs.js.map +1 -1
  51. package/dist/directives/definitions/toc.js +4 -3
  52. package/dist/directives/definitions/toc.js.map +1 -1
  53. package/dist/directives/diagnostics.js +97 -7
  54. package/dist/directives/diagnostics.js.map +1 -1
  55. package/dist/directives/iconPlaceholder.d.ts +12 -0
  56. package/dist/directives/iconPlaceholder.js +19 -0
  57. package/dist/directives/iconPlaceholder.js.map +1 -0
  58. package/dist/directives/labels.d.ts +3 -0
  59. package/dist/directives/labels.js +12 -0
  60. package/dist/directives/labels.js.map +1 -0
  61. package/dist/directives/registry.d.ts +1 -1
  62. package/dist/directives/registry.js +46 -6
  63. package/dist/directives/registry.js.map +1 -1
  64. package/dist/directives/renderData.d.ts +2 -2
  65. package/dist/directives/renderData.js.map +1 -1
  66. package/dist/directives/types.d.ts +6 -4
  67. package/dist/directives/types.js.map +1 -1
  68. package/dist/editor/MarkdownCodeMirror/Component.client.js +2 -0
  69. package/dist/editor/MarkdownCodeMirror/Component.client.js.map +1 -1
  70. package/dist/editor/directives/closeLabels.d.ts +2 -0
  71. package/dist/editor/directives/closeLabels.js +75 -0
  72. package/dist/editor/directives/closeLabels.js.map +1 -0
  73. package/dist/editor/directives/completions.js +49 -7
  74. package/dist/editor/directives/completions.js.map +1 -1
  75. package/dist/editor/themes/payload.js +197 -9
  76. package/dist/editor/themes/payload.js.map +1 -1
  77. package/dist/exports/advanced.d.ts +1 -0
  78. package/dist/exports/advanced.js +1 -0
  79. package/dist/exports/advanced.js.map +1 -1
  80. package/dist/icons/generateRegistry.d.ts +8 -0
  81. package/dist/icons/generateRegistry.js +36 -0
  82. package/dist/icons/generateRegistry.js.map +1 -0
  83. package/dist/icons/refs.d.ts +10 -0
  84. package/dist/icons/refs.js +42 -0
  85. package/dist/icons/refs.js.map +1 -0
  86. package/dist/icons/resolve.d.ts +9 -0
  87. package/dist/icons/resolve.js +95 -0
  88. package/dist/icons/resolve.js.map +1 -0
  89. package/dist/index.d.ts +1 -1
  90. package/dist/index.js.map +1 -1
  91. package/dist/runtime/index.d.ts +1 -0
  92. package/dist/runtime/index.js +8 -1
  93. package/dist/runtime/index.js.map +1 -1
  94. package/dist/types/core.d.ts +9 -0
  95. package/dist/types/core.js.map +1 -1
  96. package/dist/types/mdast.d.js.map +1 -1
  97. package/dist/types.d.ts +6 -2
  98. package/dist/types.js.map +1 -1
  99. package/package.json +3 -2
  100. package/skills/payload-markdown/claude/SKILL.md +56 -0
  101. package/skills/payload-markdown/claude/examples/docs-page.md +97 -0
  102. package/skills/payload-markdown/claude/examples/reference-page.md +75 -0
  103. package/skills/payload-markdown/claude/examples/release-notes.md +69 -0
  104. package/skills/payload-markdown/claude/reference/automated-docs-workflow.md +64 -0
  105. package/skills/payload-markdown/claude/reference/formatting.md +81 -0
  106. package/skills/payload-markdown/claude/reference/payload-markdown-directives.md +246 -0
  107. package/skills/payload-markdown/claude/reference/quality.md +48 -0
  108. package/skills/payload-markdown/claude/scripts/check_payload_markdown_doc.py +155 -0
  109. package/skills/payload-markdown/codex/SKILL.md +56 -0
  110. package/skills/payload-markdown/codex/agents/openai.yaml +4 -0
  111. package/skills/payload-markdown/codex/examples/docs-page.md +97 -0
  112. package/skills/payload-markdown/codex/examples/reference-page.md +75 -0
  113. package/skills/payload-markdown/codex/examples/release-notes.md +69 -0
  114. package/skills/payload-markdown/codex/reference/automated-docs-workflow.md +64 -0
  115. package/skills/payload-markdown/codex/reference/formatting.md +81 -0
  116. package/skills/payload-markdown/codex/reference/payload-markdown-directives.md +246 -0
  117. package/skills/payload-markdown/codex/reference/quality.md +48 -0
  118. package/skills/payload-markdown/codex/scripts/check_payload_markdown_doc.py +155 -0
@@ -11,7 +11,9 @@ import { visit } from 'unist-util-visit';
11
11
  import { resolveRenderMarkdownOptions } from './codeConfig.js';
12
12
  import { codeToHtml } from './codeToHtml.js';
13
13
  import { rehypeApplyLayoutClasses } from './plugins/rehypeApplyLayoutClasses.js';
14
+ import { rehypeResolveIcons } from './plugins/rehypeResolveIcons.js';
14
15
  import { rehypeStripAuthoredInlineStyles } from './plugins/rehypeStripAuthoredInlineStyles.js';
16
+ import { remarkButtonDirectives } from './plugins/remarkButtonDirectives.js';
15
17
  import { remarkCompileLayouts } from './plugins/remarkCompileLayouts.js';
16
18
  import { remarkHeadingAnchorsAndToc } from './plugins/remarkHeadingAnchorsAndToc.js';
17
19
  import { remarkLayoutDirectives } from './plugins/remarkLayoutDirectives.js';
@@ -69,6 +71,15 @@ const sanitizeSchema = {
69
71
  ...defaultSchema.attributes ?? {},
70
72
  a: [
71
73
  ...getAttributeDefinitions(defaultSchema.attributes?.a ?? []),
74
+ 'ariaLabel',
75
+ 'className',
76
+ 'dataButton',
77
+ 'dataDirective',
78
+ 'dataDirectiveLink',
79
+ 'dataIconPosition',
80
+ 'dataSize',
81
+ 'dataVariant',
82
+ 'dataVlLayout',
72
83
  'href',
73
84
  'target',
74
85
  'rel',
@@ -80,6 +91,9 @@ const sanitizeSchema = {
80
91
  'dataDirective',
81
92
  'dataEyebrow',
82
93
  'dataHref',
94
+ 'dataIcon',
95
+ 'dataLinkScope',
96
+ 'dataNewTab',
83
97
  'dataStepCard',
84
98
  'dataTabPanel',
85
99
  'dataTabValue',
@@ -118,18 +132,22 @@ const sanitizeSchema = {
118
132
  ],
119
133
  div: [
120
134
  ...getAttributeDefinitions(defaultSchema.attributes?.div ?? []),
135
+ 'dataAlign',
121
136
  'dataDirective',
122
137
  'dataDirectiveBody',
123
138
  'dataDirectiveTitle',
124
139
  'dataEyebrow',
125
140
  'dataHref',
141
+ 'dataGap',
126
142
  'dataCellTheme',
143
+ 'dataIcon',
127
144
  'dataTabsList',
128
145
  'dataTabPanel',
129
146
  'dataTabTrigger',
130
147
  'dataTabValue',
131
148
  'dataTheme',
132
149
  'dataTitle',
150
+ 'dataStack',
133
151
  'dataVariant',
134
152
  'dataVlLayout',
135
153
  'dataVlCellHeadingDepth',
@@ -209,8 +227,12 @@ const sanitizeSchema = {
209
227
  'dataDefault',
210
228
  'dataDisabled',
211
229
  'dataDirective',
230
+ 'dataHref',
212
231
  'dataLabel',
232
+ 'dataLinkScope',
213
233
  'dataLayout',
234
+ 'dataNewTab',
235
+ 'dataStack',
214
236
  'dataNumbered',
215
237
  'dataStepTheme',
216
238
  'dataTabTheme',
@@ -225,7 +247,10 @@ const sanitizeSchema = {
225
247
  span: [
226
248
  ...getAttributeDefinitions(defaultSchema.attributes?.span ?? []),
227
249
  'className',
250
+ 'dataPmdIcon',
251
+ 'dataPmdIconRef',
228
252
  'dataStepNumber',
253
+ 'focusable',
229
254
  'style'
230
255
  ],
231
256
  summary: [
@@ -251,9 +276,9 @@ const sanitizeSchema = {
251
276
  export async function compileMarkdown(markdown, config = {}) {
252
277
  const warnings = [];
253
278
  try {
254
- const file = await unified().use(remarkParse).use(remarkGfm).use(remarkLiftLayoutDirectives).use(remarkCompileLayouts).use(remarkLayoutDirectives).use(remarkValidateDirectiveThemes, config).use(remarkHeadingAnchorsAndToc).use(remarkRehype, {
279
+ const file = await unified().use(remarkParse).use(remarkGfm).use(remarkLiftLayoutDirectives).use(remarkButtonDirectives, config).use(remarkCompileLayouts).use(remarkLayoutDirectives).use(remarkValidateDirectiveThemes, config).use(remarkHeadingAnchorsAndToc).use(remarkRehype, {
255
280
  allowDangerousHtml: true
256
- }).use(rehypeRaw).use(rehypeStripAuthoredInlineStyles).use(rehypeShikiCodeBlocks, resolveRenderMarkdownOptions(config)).use(rehypeSanitize, sanitizeSchema).use(rehypeApplyLayoutClasses, config).use(rehypeStringify).process(markdown);
281
+ }).use(rehypeRaw).use(rehypeStripAuthoredInlineStyles).use(rehypeShikiCodeBlocks, resolveRenderMarkdownOptions(config)).use(rehypeSanitize, sanitizeSchema).use(rehypeApplyLayoutClasses, config).use(rehypeResolveIcons, config).use(rehypeStringify).process(markdown);
257
282
  return {
258
283
  html: String(file),
259
284
  warnings: file.messages.map((message)=>message.reason)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/renderMarkdown.ts"],"sourcesContent":["import type { Element, Parent, Root, RootContent } from 'hast'\nimport type { Schema } from 'hast-util-sanitize'\n\nimport { fromHtml } from 'hast-util-from-html'\nimport { toString } from 'hast-util-to-string'\nimport rehypeRaw from 'rehype-raw'\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize'\nimport rehypeStringify from 'rehype-stringify'\nimport remarkGfm from 'remark-gfm'\nimport remarkParse from 'remark-parse'\nimport remarkRehype from 'remark-rehype'\nimport { unified } from 'unified'\nimport { visit } from 'unist-util-visit'\n\nimport type { MarkdownRenderConfig, RenderMarkdownOptions, RenderMarkdownResult } from '../types/core.js'\n\nimport { resolveRenderMarkdownOptions } from './codeConfig.js'\nimport { codeToHtml } from './codeToHtml.js'\nimport { rehypeApplyLayoutClasses } from './plugins/rehypeApplyLayoutClasses.js'\nimport { rehypeStripAuthoredInlineStyles } from './plugins/rehypeStripAuthoredInlineStyles.js'\nimport { remarkCompileLayouts } from './plugins/remarkCompileLayouts.js'\nimport { remarkHeadingAnchorsAndToc } from './plugins/remarkHeadingAnchorsAndToc.js'\nimport { remarkLayoutDirectives } from './plugins/remarkLayoutDirectives.js'\nimport { remarkLiftLayoutDirectives } from './plugins/remarkLiftLayoutDirectives.js'\nimport { remarkValidateDirectiveThemes } from './plugins/remarkValidateDirectiveThemes.js'\n\nfunction extractCodeLanguage(\n className?: Array<number | string> | boolean | null | number | string ,\n): string | undefined {\n const classes =\n typeof className === 'string'\n ? className.split(/\\s+/)\n : Array.isArray(className)\n ? className\n : []\n\n return classes\n .find((c): c is string => typeof c === 'string' && c.startsWith('language-'))\n ?.slice(9)\n}\n\nfunction isElement(node: RootContent): node is Element {\n return node.type === 'element'\n}\n\nfunction isPreElement(node: RootContent): node is Element {\n return isElement(node) && node.tagName === 'pre'\n}\n\nfunction hasChildren(node: unknown): node is Parent {\n return Boolean(node && typeof node === 'object' && 'children' in node)\n}\n\nfunction findCodeChild(node: Element): Element | undefined {\n return node.children.find(\n (child): child is Element => child.type === 'element' && child.tagName === 'code',\n )\n}\n\nfunction parseHtmlFragment(html: string): RootContent[] {\n const fragment = fromHtml(html, { fragment: true })\n return fragment.children\n}\n\nfunction rehypeShikiCodeBlocks(options: RenderMarkdownOptions = {}) {\n return async function transformer(tree: Root): Promise<void> {\n const work: Array<Promise<void>> = []\n\n visit(tree, 'element', (node, index, parent) => {\n if (typeof index !== 'number' || !hasChildren(parent) || !isPreElement(node)) return\n\n const codeNode = findCodeChild(node)\n if (!codeNode) return\n\n const code = toString(codeNode)\n const lang = extractCodeLanguage(codeNode.properties?.className)\n\n work.push(\n (async () => {\n const highlighted = await codeToHtml(code, {\n ...options,\n lang\n })\n\n const replacementNodes = parseHtmlFragment(highlighted)\n parent.children.splice(index, 1, ...replacementNodes)\n })(),\n )\n })\n\n await Promise.all(work)\n }\n}\n\ntype SanitizeAttributeValue = boolean | null | number | RegExp | string | undefined\ntype SanitizeAttributeDefinition = [string, ...SanitizeAttributeValue[]] | string\n\nfunction getAttributeDefinitions(\n value: Schema['attributes'] extends infer A\n ? A extends Record<string, infer V>\n ? V\n : never\n : never,\n): SanitizeAttributeDefinition[] {\n return (value as SanitizeAttributeDefinition[] | undefined) ?? []\n}\n\nconst sanitizeSchema: Schema = {\n ...defaultSchema,\n attributes: {\n ...(defaultSchema.attributes ?? {}),\n a: [\n ...getAttributeDefinitions(defaultSchema.attributes?.a ?? []),\n 'href',\n 'target',\n 'rel',\n 'title',\n ],\n article: [\n ...getAttributeDefinitions(defaultSchema.attributes?.article ?? []),\n 'className',\n 'dataDirective',\n 'dataEyebrow',\n 'dataHref',\n 'dataStepCard',\n 'dataTabPanel',\n 'dataTabValue',\n 'dataTheme',\n 'dataTitle',\n 'dataVlLayout',\n 'hidden',\n 'id',\n 'role',\n 'tabIndex',\n ],\n button: [\n ...getAttributeDefinitions(defaultSchema.attributes?.button ?? []),\n 'ariaControls',\n 'ariaSelected',\n 'className',\n 'dataTabTrigger',\n 'dataTabValue',\n 'disabled',\n 'id',\n 'role',\n 'tabIndex',\n 'type',\n ],\n code: [...getAttributeDefinitions(defaultSchema.attributes?.code ?? []), 'className'],\n details: [\n ...getAttributeDefinitions(defaultSchema.attributes?.details ?? []),\n 'dataDirective',\n 'dataTheme',\n 'dataTitle',\n 'dataVlLayout',\n 'open',\n ],\n div: [\n ...getAttributeDefinitions(defaultSchema.attributes?.div ?? []),\n 'dataDirective',\n 'dataDirectiveBody',\n 'dataDirectiveTitle',\n 'dataEyebrow',\n 'dataHref',\n 'dataCellTheme',\n 'dataTabsList',\n 'dataTabPanel',\n 'dataTabTrigger',\n 'dataTabValue',\n 'dataTheme',\n 'dataTitle',\n 'dataVariant',\n 'dataVlLayout',\n 'dataVlCellHeadingDepth',\n 'hidden',\n 'id',\n 'role',\n 'tabIndex',\n ],\n h1: [\n ...getAttributeDefinitions(defaultSchema.attributes?.h1 ?? []),\n 'dataDirectiveTitle',\n 'dataHeadingAnchor',\n 'id',\n ],\n h2: [\n ...getAttributeDefinitions(defaultSchema.attributes?.h2 ?? []),\n 'dataDirectiveTitle',\n 'dataHeadingAnchor',\n 'id',\n ],\n h3: [\n ...getAttributeDefinitions(defaultSchema.attributes?.h3 ?? []),\n 'dataDirectiveTitle',\n 'dataHeadingAnchor',\n 'id',\n ],\n h4: [...getAttributeDefinitions(defaultSchema.attributes?.h4 ?? []), 'dataHeadingAnchor', 'id'],\n h5: [...getAttributeDefinitions(defaultSchema.attributes?.h5 ?? []), 'dataHeadingAnchor', 'id'],\n h6: [...getAttributeDefinitions(defaultSchema.attributes?.h6 ?? []), 'dataHeadingAnchor', 'id'],\n img: [\n ...getAttributeDefinitions(defaultSchema.attributes?.img ?? []),\n 'src',\n 'alt',\n 'title',\n 'width',\n 'height',\n ],\n li: [...getAttributeDefinitions(defaultSchema.attributes?.li ?? []), 'dataStep'],\n nav: [\n ...getAttributeDefinitions(defaultSchema.attributes?.nav ?? []),\n 'ariaLabel',\n 'dataDirective',\n 'dataTheme',\n 'dataTitle',\n 'dataVlLayout',\n ],\n p: [\n ...getAttributeDefinitions(defaultSchema.attributes?.p ?? []),\n 'className',\n 'dataDirectiveEyebrow',\n ],\n pre: [\n ...getAttributeDefinitions(defaultSchema.attributes?.pre ?? []),\n 'className',\n 'tabindex',\n ],\n section: [\n ...getAttributeDefinitions(defaultSchema.attributes?.section ?? []),\n 'dataColumns',\n 'dataCardTheme',\n 'dataCellTheme',\n 'dataDefault',\n 'dataDisabled',\n 'dataDirective',\n 'dataLabel',\n 'dataLayout',\n 'dataNumbered',\n 'dataStepTheme',\n 'dataTabTheme',\n 'dataTabValue',\n 'dataTheme',\n 'dataVariant',\n 'dataValue',\n 'dataVlLayout',\n 'dataVlCellHeadingDepth',\n 'role',\n ],\n span: [\n ...getAttributeDefinitions(defaultSchema.attributes?.span ?? []),\n 'className',\n 'dataStepNumber',\n 'style',\n ],\n summary: [...getAttributeDefinitions(defaultSchema.attributes?.summary ?? []), 'className'],\n },\n clobberPrefix: '',\n tagNames: [\n ...(defaultSchema.tagNames ?? []),\n 'a',\n 'article',\n 'br',\n 'button',\n 'details',\n 'img',\n 'nav',\n 'section',\n 'span',\n 'summary',\n ],\n}\n\nexport async function compileMarkdown(\n markdown: string,\n config: MarkdownRenderConfig = {},\n): Promise<RenderMarkdownResult> {\n const warnings: string[] = []\n\n try {\n const file = await unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkLiftLayoutDirectives)\n .use(remarkCompileLayouts)\n .use(remarkLayoutDirectives)\n .use(remarkValidateDirectiveThemes, config)\n .use(remarkHeadingAnchorsAndToc)\n .use(remarkRehype, { allowDangerousHtml: true })\n .use(rehypeRaw)\n .use(rehypeStripAuthoredInlineStyles)\n .use(rehypeShikiCodeBlocks, resolveRenderMarkdownOptions(config))\n .use(rehypeSanitize, sanitizeSchema)\n .use(rehypeApplyLayoutClasses, config)\n .use(rehypeStringify)\n .process(markdown)\n\n return {\n html: String(file),\n warnings: file.messages.map((message) => message.reason),\n }\n } catch (error) {\n warnings.push(error instanceof Error ? error.message : 'Failed to render markdown.')\n\n return {\n html: '<p>Failed to render markdown.</p>',\n warnings,\n }\n }\n}\n"],"names":["fromHtml","toString","rehypeRaw","rehypeSanitize","defaultSchema","rehypeStringify","remarkGfm","remarkParse","remarkRehype","unified","visit","resolveRenderMarkdownOptions","codeToHtml","rehypeApplyLayoutClasses","rehypeStripAuthoredInlineStyles","remarkCompileLayouts","remarkHeadingAnchorsAndToc","remarkLayoutDirectives","remarkLiftLayoutDirectives","remarkValidateDirectiveThemes","extractCodeLanguage","className","classes","split","Array","isArray","find","c","startsWith","slice","isElement","node","type","isPreElement","tagName","hasChildren","Boolean","findCodeChild","children","child","parseHtmlFragment","html","fragment","rehypeShikiCodeBlocks","options","transformer","tree","work","index","parent","codeNode","code","lang","properties","push","highlighted","replacementNodes","splice","Promise","all","getAttributeDefinitions","value","sanitizeSchema","attributes","a","article","button","details","div","h1","h2","h3","h4","h5","h6","img","li","nav","p","pre","section","span","summary","clobberPrefix","tagNames","compileMarkdown","markdown","config","warnings","file","use","allowDangerousHtml","process","String","messages","map","message","reason","error","Error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/core/renderMarkdown.ts"],"sourcesContent":["import type { Element, Parent, Root, RootContent } from 'hast'\nimport type { Schema } from 'hast-util-sanitize'\n\nimport { fromHtml } from 'hast-util-from-html'\nimport { toString } from 'hast-util-to-string'\nimport rehypeRaw from 'rehype-raw'\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize'\nimport rehypeStringify from 'rehype-stringify'\nimport remarkGfm from 'remark-gfm'\nimport remarkParse from 'remark-parse'\nimport remarkRehype from 'remark-rehype'\nimport { unified } from 'unified'\nimport { visit } from 'unist-util-visit'\n\nimport type { MarkdownRenderConfig, RenderMarkdownOptions, RenderMarkdownResult } from '../types/core.js'\n\nimport { resolveRenderMarkdownOptions } from './codeConfig.js'\nimport { codeToHtml } from './codeToHtml.js'\nimport { rehypeApplyLayoutClasses } from './plugins/rehypeApplyLayoutClasses.js'\nimport { rehypeResolveIcons } from './plugins/rehypeResolveIcons.js'\nimport { rehypeStripAuthoredInlineStyles } from './plugins/rehypeStripAuthoredInlineStyles.js'\nimport { remarkButtonDirectives } from './plugins/remarkButtonDirectives.js'\nimport { remarkCompileLayouts } from './plugins/remarkCompileLayouts.js'\nimport { remarkHeadingAnchorsAndToc } from './plugins/remarkHeadingAnchorsAndToc.js'\nimport { remarkLayoutDirectives } from './plugins/remarkLayoutDirectives.js'\nimport { remarkLiftLayoutDirectives } from './plugins/remarkLiftLayoutDirectives.js'\nimport { remarkValidateDirectiveThemes } from './plugins/remarkValidateDirectiveThemes.js'\n\nfunction extractCodeLanguage(\n className?: Array<number | string> | boolean | null | number | string ,\n): string | undefined {\n const classes =\n typeof className === 'string'\n ? className.split(/\\s+/)\n : Array.isArray(className)\n ? className\n : []\n\n return classes\n .find((c): c is string => typeof c === 'string' && c.startsWith('language-'))\n ?.slice(9)\n}\n\nfunction isElement(node: RootContent): node is Element {\n return node.type === 'element'\n}\n\nfunction isPreElement(node: RootContent): node is Element {\n return isElement(node) && node.tagName === 'pre'\n}\n\nfunction hasChildren(node: unknown): node is Parent {\n return Boolean(node && typeof node === 'object' && 'children' in node)\n}\n\nfunction findCodeChild(node: Element): Element | undefined {\n return node.children.find(\n (child): child is Element => child.type === 'element' && child.tagName === 'code',\n )\n}\n\nfunction parseHtmlFragment(html: string): RootContent[] {\n const fragment = fromHtml(html, { fragment: true })\n return fragment.children\n}\n\nfunction rehypeShikiCodeBlocks(options: RenderMarkdownOptions = {}) {\n return async function transformer(tree: Root): Promise<void> {\n const work: Array<Promise<void>> = []\n\n visit(tree, 'element', (node, index, parent) => {\n if (typeof index !== 'number' || !hasChildren(parent) || !isPreElement(node)) return\n\n const codeNode = findCodeChild(node)\n if (!codeNode) return\n\n const code = toString(codeNode)\n const lang = extractCodeLanguage(codeNode.properties?.className)\n\n work.push(\n (async () => {\n const highlighted = await codeToHtml(code, {\n ...options,\n lang\n })\n\n const replacementNodes = parseHtmlFragment(highlighted)\n parent.children.splice(index, 1, ...replacementNodes)\n })(),\n )\n })\n\n await Promise.all(work)\n }\n}\n\ntype SanitizeAttributeValue = boolean | null | number | RegExp | string | undefined\ntype SanitizeAttributeDefinition = [string, ...SanitizeAttributeValue[]] | string\n\nfunction getAttributeDefinitions(\n value: Schema['attributes'] extends infer A\n ? A extends Record<string, infer V>\n ? V\n : never\n : never,\n): SanitizeAttributeDefinition[] {\n return (value as SanitizeAttributeDefinition[] | undefined) ?? []\n}\n\nconst sanitizeSchema: Schema = {\n ...defaultSchema,\n attributes: {\n ...(defaultSchema.attributes ?? {}),\n a: [\n ...getAttributeDefinitions(defaultSchema.attributes?.a ?? []),\n 'ariaLabel',\n 'className',\n 'dataButton',\n 'dataDirective',\n 'dataDirectiveLink',\n 'dataIconPosition',\n 'dataSize',\n 'dataVariant',\n 'dataVlLayout',\n 'href',\n 'target',\n 'rel',\n 'title',\n ],\n article: [\n ...getAttributeDefinitions(defaultSchema.attributes?.article ?? []),\n 'className',\n 'dataDirective',\n 'dataEyebrow',\n 'dataHref',\n 'dataIcon',\n 'dataLinkScope',\n 'dataNewTab',\n 'dataStepCard',\n 'dataTabPanel',\n 'dataTabValue',\n 'dataTheme',\n 'dataTitle',\n 'dataVlLayout',\n 'hidden',\n 'id',\n 'role',\n 'tabIndex',\n ],\n button: [\n ...getAttributeDefinitions(defaultSchema.attributes?.button ?? []),\n 'ariaControls',\n 'ariaSelected',\n 'className',\n 'dataTabTrigger',\n 'dataTabValue',\n 'disabled',\n 'id',\n 'role',\n 'tabIndex',\n 'type',\n ],\n code: [...getAttributeDefinitions(defaultSchema.attributes?.code ?? []), 'className'],\n details: [\n ...getAttributeDefinitions(defaultSchema.attributes?.details ?? []),\n 'dataDirective',\n 'dataTheme',\n 'dataTitle',\n 'dataVlLayout',\n 'open',\n ],\n div: [\n ...getAttributeDefinitions(defaultSchema.attributes?.div ?? []),\n 'dataAlign',\n 'dataDirective',\n 'dataDirectiveBody',\n 'dataDirectiveTitle',\n 'dataEyebrow',\n 'dataHref',\n 'dataGap',\n 'dataCellTheme',\n 'dataIcon',\n 'dataTabsList',\n 'dataTabPanel',\n 'dataTabTrigger',\n 'dataTabValue',\n 'dataTheme',\n 'dataTitle',\n 'dataStack',\n 'dataVariant',\n 'dataVlLayout',\n 'dataVlCellHeadingDepth',\n 'hidden',\n 'id',\n 'role',\n 'tabIndex',\n ],\n h1: [\n ...getAttributeDefinitions(defaultSchema.attributes?.h1 ?? []),\n 'dataDirectiveTitle',\n 'dataHeadingAnchor',\n 'id',\n ],\n h2: [\n ...getAttributeDefinitions(defaultSchema.attributes?.h2 ?? []),\n 'dataDirectiveTitle',\n 'dataHeadingAnchor',\n 'id',\n ],\n h3: [\n ...getAttributeDefinitions(defaultSchema.attributes?.h3 ?? []),\n 'dataDirectiveTitle',\n 'dataHeadingAnchor',\n 'id',\n ],\n h4: [...getAttributeDefinitions(defaultSchema.attributes?.h4 ?? []), 'dataHeadingAnchor', 'id'],\n h5: [...getAttributeDefinitions(defaultSchema.attributes?.h5 ?? []), 'dataHeadingAnchor', 'id'],\n h6: [...getAttributeDefinitions(defaultSchema.attributes?.h6 ?? []), 'dataHeadingAnchor', 'id'],\n img: [\n ...getAttributeDefinitions(defaultSchema.attributes?.img ?? []),\n 'src',\n 'alt',\n 'title',\n 'width',\n 'height',\n ],\n li: [...getAttributeDefinitions(defaultSchema.attributes?.li ?? []), 'dataStep'],\n nav: [\n ...getAttributeDefinitions(defaultSchema.attributes?.nav ?? []),\n 'ariaLabel',\n 'dataDirective',\n 'dataTheme',\n 'dataTitle',\n 'dataVlLayout',\n ],\n p: [\n ...getAttributeDefinitions(defaultSchema.attributes?.p ?? []),\n 'className',\n 'dataDirectiveEyebrow',\n ],\n pre: [\n ...getAttributeDefinitions(defaultSchema.attributes?.pre ?? []),\n 'className',\n 'tabindex',\n ],\n section: [\n ...getAttributeDefinitions(defaultSchema.attributes?.section ?? []),\n 'dataColumns',\n 'dataCardTheme',\n 'dataCellTheme',\n 'dataDefault',\n 'dataDisabled',\n 'dataDirective',\n 'dataHref',\n 'dataLabel',\n 'dataLinkScope',\n 'dataLayout',\n 'dataNewTab',\n 'dataStack',\n 'dataNumbered',\n 'dataStepTheme',\n 'dataTabTheme',\n 'dataTabValue',\n 'dataTheme',\n 'dataVariant',\n 'dataValue',\n 'dataVlLayout',\n 'dataVlCellHeadingDepth',\n 'role',\n ],\n span: [\n ...getAttributeDefinitions(defaultSchema.attributes?.span ?? []),\n 'className',\n 'dataPmdIcon',\n 'dataPmdIconRef',\n 'dataStepNumber',\n 'focusable',\n 'style',\n ],\n summary: [...getAttributeDefinitions(defaultSchema.attributes?.summary ?? []), 'className'],\n },\n clobberPrefix: '',\n tagNames: [\n ...(defaultSchema.tagNames ?? []),\n 'a',\n 'article',\n 'br',\n 'button',\n 'details',\n 'img',\n 'nav',\n 'section',\n 'span',\n 'summary',\n ],\n}\n\nexport async function compileMarkdown(\n markdown: string,\n config: MarkdownRenderConfig = {},\n): Promise<RenderMarkdownResult> {\n const warnings: string[] = []\n\n try {\n const file = await unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkLiftLayoutDirectives)\n .use(remarkButtonDirectives, config)\n .use(remarkCompileLayouts)\n .use(remarkLayoutDirectives)\n .use(remarkValidateDirectiveThemes, config)\n .use(remarkHeadingAnchorsAndToc)\n .use(remarkRehype, { allowDangerousHtml: true })\n .use(rehypeRaw)\n .use(rehypeStripAuthoredInlineStyles)\n .use(rehypeShikiCodeBlocks, resolveRenderMarkdownOptions(config))\n .use(rehypeSanitize, sanitizeSchema)\n .use(rehypeApplyLayoutClasses, config)\n .use(rehypeResolveIcons, config)\n .use(rehypeStringify)\n .process(markdown)\n\n return {\n html: String(file),\n warnings: file.messages.map((message) => message.reason),\n }\n } catch (error) {\n warnings.push(error instanceof Error ? error.message : 'Failed to render markdown.')\n\n return {\n html: '<p>Failed to render markdown.</p>',\n warnings,\n }\n }\n}\n"],"names":["fromHtml","toString","rehypeRaw","rehypeSanitize","defaultSchema","rehypeStringify","remarkGfm","remarkParse","remarkRehype","unified","visit","resolveRenderMarkdownOptions","codeToHtml","rehypeApplyLayoutClasses","rehypeResolveIcons","rehypeStripAuthoredInlineStyles","remarkButtonDirectives","remarkCompileLayouts","remarkHeadingAnchorsAndToc","remarkLayoutDirectives","remarkLiftLayoutDirectives","remarkValidateDirectiveThemes","extractCodeLanguage","className","classes","split","Array","isArray","find","c","startsWith","slice","isElement","node","type","isPreElement","tagName","hasChildren","Boolean","findCodeChild","children","child","parseHtmlFragment","html","fragment","rehypeShikiCodeBlocks","options","transformer","tree","work","index","parent","codeNode","code","lang","properties","push","highlighted","replacementNodes","splice","Promise","all","getAttributeDefinitions","value","sanitizeSchema","attributes","a","article","button","details","div","h1","h2","h3","h4","h5","h6","img","li","nav","p","pre","section","span","summary","clobberPrefix","tagNames","compileMarkdown","markdown","config","warnings","file","use","allowDangerousHtml","process","String","messages","map","message","reason","error","Error"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { DirectiveAttributes } from './attributes.js';
2
+ export declare function getUnknownAttributeWarnings(directiveName: string, allowedAttributes: readonly string[] | undefined, attributes: DirectiveAttributes): string[];
@@ -0,0 +1,35 @@
1
+ function getEditDistance(left, right) {
2
+ const columns = right.length + 1;
3
+ const distances = Array.from({
4
+ length: (left.length + 1) * columns
5
+ }, ()=>0);
6
+ for(let row = 0; row <= left.length; ++row)distances[row * columns] = row;
7
+ for(let column = 0; column <= right.length; ++column)distances[column] = column;
8
+ for(let row = 1; row <= left.length; ++row){
9
+ for(let column = 1; column <= right.length; ++column){
10
+ const cost = left[row - 1] === right[column - 1] ? 0 : 1;
11
+ distances[row * columns + column] = Math.min(distances[(row - 1) * columns + column] + 1, distances[row * columns + column - 1] + 1, distances[(row - 1) * columns + column - 1] + cost);
12
+ }
13
+ }
14
+ return distances[left.length * columns + right.length];
15
+ }
16
+ function findClosestAttribute(attribute, allowedAttributes) {
17
+ let closest;
18
+ let closestDistance = Number.POSITIVE_INFINITY;
19
+ for (const allowedAttribute of allowedAttributes){
20
+ const distance = getEditDistance(attribute.toLowerCase(), allowedAttribute.toLowerCase());
21
+ if (distance >= closestDistance) continue;
22
+ closest = allowedAttribute;
23
+ closestDistance = distance;
24
+ }
25
+ return closest && closestDistance <= 2 ? closest : undefined;
26
+ }
27
+ export function getUnknownAttributeWarnings(directiveName, allowedAttributes, attributes) {
28
+ if (!allowedAttributes) return [];
29
+ return Object.keys(attributes).filter((attribute)=>!allowedAttributes.includes(attribute)).map((attribute)=>{
30
+ const suggestion = findClosestAttribute(attribute, allowedAttributes);
31
+ return suggestion ? `Unknown attribute "${attribute}" on "${directiveName}". Did you mean "${suggestion}"?` : `Unknown attribute "${attribute}" on "${directiveName}".`;
32
+ });
33
+ }
34
+
35
+ //# sourceMappingURL=attributeDiagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/directives/attributeDiagnostics.ts"],"sourcesContent":["import type { DirectiveAttributes } from './attributes.js'\n\nfunction getEditDistance(left: string, right: string): number {\n const columns = right.length + 1\n const distances = Array.from({ length: (left.length + 1) * columns }, () => 0)\n\n for (let row = 0; row <= left.length; ++row) distances[row * columns] = row\n for (let column = 0; column <= right.length; ++column) distances[column] = column\n\n for (let row = 1; row <= left.length; ++row) {\n for (let column = 1; column <= right.length; ++column) {\n const cost = left[row - 1] === right[column - 1] ? 0 : 1\n distances[row * columns + column] = Math.min(\n distances[(row - 1) * columns + column] + 1,\n distances[row * columns + column - 1] + 1,\n distances[(row - 1) * columns + column - 1] + cost,\n )\n }\n }\n\n return distances[left.length * columns + right.length]\n}\n\nfunction findClosestAttribute(attribute: string, allowedAttributes: readonly string[]): string | undefined {\n let closest: string | undefined\n let closestDistance = Number.POSITIVE_INFINITY\n\n for (const allowedAttribute of allowedAttributes) {\n const distance = getEditDistance(attribute.toLowerCase(), allowedAttribute.toLowerCase())\n\n if (distance >= closestDistance) continue\n\n closest = allowedAttribute\n closestDistance = distance\n }\n\n return closest && closestDistance <= 2 ? closest : undefined\n}\n\nexport function getUnknownAttributeWarnings(\n directiveName: string,\n allowedAttributes: readonly string[] | undefined,\n attributes: DirectiveAttributes,\n): string[] {\n if (!allowedAttributes) return []\n\n return Object.keys(attributes)\n .filter((attribute) => !allowedAttributes.includes(attribute))\n .map((attribute) => {\n const suggestion = findClosestAttribute(attribute, allowedAttributes)\n\n return suggestion\n ? `Unknown attribute \"${attribute}\" on \"${directiveName}\". Did you mean \"${suggestion}\"?`\n : `Unknown attribute \"${attribute}\" on \"${directiveName}\".`\n })\n}\n"],"names":["getEditDistance","left","right","columns","length","distances","Array","from","row","column","cost","Math","min","findClosestAttribute","attribute","allowedAttributes","closest","closestDistance","Number","POSITIVE_INFINITY","allowedAttribute","distance","toLowerCase","undefined","getUnknownAttributeWarnings","directiveName","attributes","Object","keys","filter","includes","map","suggestion"],"mappings":"AAEA,SAASA,gBAAgBC,IAAY,EAAEC,KAAa;IAClD,MAAMC,UAAUD,MAAME,MAAM,GAAG;IAC/B,MAAMC,YAAYC,MAAMC,IAAI,CAAC;QAAEH,QAAQ,AAACH,CAAAA,KAAKG,MAAM,GAAG,CAAA,IAAKD;IAAQ,GAAG,IAAM;IAE5E,IAAK,IAAIK,MAAM,GAAGA,OAAOP,KAAKG,MAAM,EAAE,EAAEI,IAAKH,SAAS,CAACG,MAAML,QAAQ,GAAGK;IACxE,IAAK,IAAIC,SAAS,GAAGA,UAAUP,MAAME,MAAM,EAAE,EAAEK,OAAQJ,SAAS,CAACI,OAAO,GAAGA;IAE3E,IAAK,IAAID,MAAM,GAAGA,OAAOP,KAAKG,MAAM,EAAE,EAAEI,IAAK;QAC3C,IAAK,IAAIC,SAAS,GAAGA,UAAUP,MAAME,MAAM,EAAE,EAAEK,OAAQ;YACrD,MAAMC,OAAOT,IAAI,CAACO,MAAM,EAAE,KAAKN,KAAK,CAACO,SAAS,EAAE,GAAG,IAAI;YACvDJ,SAAS,CAACG,MAAML,UAAUM,OAAO,GAAGE,KAAKC,GAAG,CAC1CP,SAAS,CAAC,AAACG,CAAAA,MAAM,CAAA,IAAKL,UAAUM,OAAO,GAAG,GAC1CJ,SAAS,CAACG,MAAML,UAAUM,SAAS,EAAE,GAAG,GACxCJ,SAAS,CAAC,AAACG,CAAAA,MAAM,CAAA,IAAKL,UAAUM,SAAS,EAAE,GAAGC;QAElD;IACF;IAEA,OAAOL,SAAS,CAACJ,KAAKG,MAAM,GAAGD,UAAUD,MAAME,MAAM,CAAC;AACxD;AAEA,SAASS,qBAAqBC,SAAiB,EAAEC,iBAAoC;IACnF,IAAIC;IACJ,IAAIC,kBAAkBC,OAAOC,iBAAiB;IAE9C,KAAK,MAAMC,oBAAoBL,kBAAmB;QAChD,MAAMM,WAAWrB,gBAAgBc,UAAUQ,WAAW,IAAIF,iBAAiBE,WAAW;QAEtF,IAAID,YAAYJ,iBAAiB;QAEjCD,UAAUI;QACVH,kBAAkBI;IACpB;IAEA,OAAOL,WAAWC,mBAAmB,IAAID,UAAUO;AACrD;AAEA,OAAO,SAASC,4BACdC,aAAqB,EACrBV,iBAAgD,EAChDW,UAA+B;IAE/B,IAAI,CAACX,mBAAmB,OAAO,EAAE;IAEjC,OAAOY,OAAOC,IAAI,CAACF,YAChBG,MAAM,CAAC,CAACf,YAAc,CAACC,kBAAkBe,QAAQ,CAAChB,YAClDiB,GAAG,CAAC,CAACjB;QACJ,MAAMkB,aAAanB,qBAAqBC,WAAWC;QAEnD,OAAOiB,aACH,CAAC,mBAAmB,EAAElB,UAAU,MAAM,EAAEW,cAAc,iBAAiB,EAAEO,WAAW,EAAE,CAAC,GACvF,CAAC,mBAAmB,EAAElB,UAAU,MAAM,EAAEW,cAAc,EAAE,CAAC;IAC/D;AACJ"}
@@ -2,13 +2,21 @@ export type DirectiveAttributeValue = boolean | string;
2
2
  export type DirectiveAttributes = Record<string, DirectiveAttributeValue>;
3
3
  export type ParsedDirectiveLine = {
4
4
  attributes: DirectiveAttributes;
5
+ label?: string;
5
6
  name: string;
6
7
  rawAttributes?: string;
7
8
  warnings: string[];
8
9
  };
10
+ type BraceState = {
11
+ depth: number;
12
+ hasBrace: boolean;
13
+ };
14
+ export declare function getDirectiveAttributeBraceState(value: string): BraceState;
15
+ export declare function hasUnclosedDirectiveAttributeBlock(value: string): boolean;
9
16
  export declare function parseDirectiveAttributesDetailed(value?: string): {
10
17
  attributes: DirectiveAttributes;
11
18
  warnings: string[];
12
19
  };
13
20
  export declare function parseDirectiveAttributes(value?: string): DirectiveAttributes;
14
21
  export declare function parseDirectiveLine(text: string): null | ParsedDirectiveLine;
22
+ export {};
@@ -60,6 +60,48 @@ function appendClassName(attributes, className) {
60
60
  className
61
61
  ].filter(Boolean).join(' ');
62
62
  }
63
+ export function getDirectiveAttributeBraceState(value) {
64
+ let depth = 0;
65
+ let escaped = false;
66
+ let hasBrace = false;
67
+ let quote = null;
68
+ for (const char of value){
69
+ if (escaped) {
70
+ escaped = false;
71
+ continue;
72
+ }
73
+ if (char === '\\' && quote) {
74
+ escaped = true;
75
+ continue;
76
+ }
77
+ if ((char === '"' || char === "'") && quote === null) {
78
+ quote = char;
79
+ continue;
80
+ }
81
+ if (char === quote) {
82
+ quote = null;
83
+ continue;
84
+ }
85
+ if (quote) continue;
86
+ if (char === '{') {
87
+ hasBrace = true;
88
+ depth += 1;
89
+ continue;
90
+ }
91
+ if (char === '}') {
92
+ hasBrace = true;
93
+ depth = Math.max(0, depth - 1);
94
+ }
95
+ }
96
+ return {
97
+ depth,
98
+ hasBrace
99
+ };
100
+ }
101
+ export function hasUnclosedDirectiveAttributeBlock(value) {
102
+ const state = getDirectiveAttributeBraceState(value);
103
+ return state.hasBrace && state.depth > 0;
104
+ }
63
105
  export function parseDirectiveAttributesDetailed(value = '') {
64
106
  const stripped = stripEnclosingBraces(value);
65
107
  const warnings = [
@@ -103,16 +145,25 @@ export function parseDirectiveAttributes(value = '') {
103
145
  export function parseDirectiveLine(text) {
104
146
  const trimmed = text.trim();
105
147
  if (!trimmed.startsWith(':::')) return null;
106
- const body = trimmed.slice(3);
148
+ let body = trimmed.slice(3);
107
149
  if (!body) return null;
108
- const firstWhitespaceIndex = body.search(/\s/);
109
- const name = firstWhitespaceIndex < 0 ? body : body.slice(0, firstWhitespaceIndex);
110
- if (!/^[\w-]+$/.test(name)) return null;
111
- const rawAttributes = firstWhitespaceIndex < 0 ? undefined : body.slice(firstWhitespaceIndex).trim();
150
+ const nameMatch = body.match(/^([\w-]+)/);
151
+ const name = nameMatch?.[1];
152
+ if (!name) return null;
153
+ body = body.slice(name.length).trimStart();
154
+ let label;
155
+ if (body.startsWith('[')) {
156
+ const labelEnd = body.indexOf(']');
157
+ if (labelEnd < 0) return null;
158
+ label = body.slice(1, labelEnd);
159
+ body = body.slice(labelEnd + 1).trimStart();
160
+ }
161
+ const rawAttributes = body ? body : undefined;
112
162
  const attributes = parseDirectiveAttributesDetailed(rawAttributes);
113
163
  return {
114
164
  name,
115
165
  attributes: attributes.attributes,
166
+ label,
116
167
  rawAttributes,
117
168
  warnings: attributes.warnings
118
169
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/directives/attributes.ts"],"sourcesContent":["export type DirectiveAttributeValue = boolean | string\n\nexport type DirectiveAttributes = Record<string, DirectiveAttributeValue>\n\nexport type ParsedDirectiveLine = {\n attributes: DirectiveAttributes\n name: string\n rawAttributes?: string\n warnings: string[]\n}\n\ntype TokenizeAttributesResult = {\n tokens: string[]\n warnings: string[]\n}\n\nfunction stripEnclosingBraces(value: string): { value: string; warnings: string[] } {\n const trimmed = value.trim()\n\n if (!trimmed) return { value: '', warnings: [] }\n\n if (trimmed.startsWith('{') && trimmed.endsWith('}'))\n return { value: trimmed.slice(1, -1).trim(), warnings: [] }\n\n if (trimmed.startsWith('{') || trimmed.endsWith('}'))\n return {\n value: trimmed.replace(/^\\{/, '').replace(/\\}$/, '').trim(),\n warnings: ['Malformed directive attributes: braces must be balanced.'],\n }\n\n return { value: trimmed, warnings: [] }\n}\n\nfunction stripQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n )\n return value.slice(1, -1)\n\n return value\n}\n\nfunction tokenizeAttributes(value: string): TokenizeAttributesResult {\n const tokens: string[] = []\n const warnings: string[] = []\n let current = ''\n let quote: \"'\" | '\"' | null = null\n\n for (const char of value) {\n if ((char === '\"' || char === \"'\") && quote === null) {\n quote = char\n current += char\n continue\n }\n\n if (char === quote) {\n quote = null\n current += char\n continue\n }\n\n if (/\\s/.test(char) && quote === null) {\n if (current) tokens.push(current)\n current = ''\n continue\n }\n\n current += char\n }\n\n if (current) tokens.push(current)\n if (quote) warnings.push('Malformed directive attributes: quoted value is not closed.')\n\n return { tokens, warnings }\n}\n\nfunction appendClassName(attributes: DirectiveAttributes, className: string) {\n const existing = typeof attributes.class === 'string' ? attributes.class : ''\n attributes.class = [existing, className].filter(Boolean).join(' ')\n}\n\nexport function parseDirectiveAttributesDetailed(value = ''): {\n attributes: DirectiveAttributes\n warnings: string[]\n} {\n const stripped = stripEnclosingBraces(value)\n const warnings = [...stripped.warnings]\n\n if (!stripped.value)\n return {\n attributes: {},\n warnings,\n }\n\n const attributes: DirectiveAttributes = {}\n const tokenized = tokenizeAttributes(stripped.value)\n warnings.push(...tokenized.warnings)\n\n for (const token of tokenized.tokens) {\n if (token.startsWith('#') && token.length > 1) {\n attributes.id = token.slice(1)\n continue\n }\n\n if (token.startsWith('.') && token.length > 1) {\n appendClassName(attributes, token.slice(1))\n continue\n }\n\n const equalIndex = token.indexOf('=')\n\n if (equalIndex < 0) {\n attributes[token] = true\n continue\n }\n\n const key = token.slice(0, equalIndex)\n const rawValue = token.slice(equalIndex + 1)\n\n if (!key) continue\n\n if (key === 'class') appendClassName(attributes, stripQuotes(rawValue))\n else attributes[key] = stripQuotes(rawValue)\n }\n\n return {\n attributes,\n warnings,\n }\n}\n\nexport function parseDirectiveAttributes(value = ''): DirectiveAttributes {\n return parseDirectiveAttributesDetailed(value).attributes\n}\n\nexport function parseDirectiveLine(text: string): null | ParsedDirectiveLine {\n const trimmed = text.trim()\n\n if (!trimmed.startsWith(':::')) return null\n\n const body = trimmed.slice(3)\n if (!body) return null\n\n const firstWhitespaceIndex = body.search(/\\s/)\n const name = firstWhitespaceIndex < 0 ? body : body.slice(0, firstWhitespaceIndex)\n\n if (!/^[\\w-]+$/.test(name)) return null\n\n const rawAttributes =\n firstWhitespaceIndex < 0 ? undefined : body.slice(firstWhitespaceIndex).trim()\n\n const attributes = parseDirectiveAttributesDetailed(rawAttributes)\n\n return {\n name,\n attributes: attributes.attributes,\n rawAttributes,\n warnings: attributes.warnings,\n }\n}\n"],"names":["stripEnclosingBraces","value","trimmed","trim","warnings","startsWith","endsWith","slice","replace","stripQuotes","tokenizeAttributes","tokens","current","quote","char","test","push","appendClassName","attributes","className","existing","class","filter","Boolean","join","parseDirectiveAttributesDetailed","stripped","tokenized","token","length","id","equalIndex","indexOf","key","rawValue","parseDirectiveAttributes","parseDirectiveLine","text","body","firstWhitespaceIndex","search","name","rawAttributes","undefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/directives/attributes.ts"],"sourcesContent":["export type DirectiveAttributeValue = boolean | string\n\nexport type DirectiveAttributes = Record<string, DirectiveAttributeValue>\n\nexport type ParsedDirectiveLine = {\n attributes: DirectiveAttributes\n label?: string\n name: string\n rawAttributes?: string\n warnings: string[]\n}\n\ntype TokenizeAttributesResult = {\n tokens: string[]\n warnings: string[]\n}\n\ntype BraceState = {\n depth: number\n hasBrace: boolean\n}\n\nfunction stripEnclosingBraces(value: string): { value: string; warnings: string[] } {\n const trimmed = value.trim()\n\n if (!trimmed) return { value: '', warnings: [] }\n\n if (trimmed.startsWith('{') && trimmed.endsWith('}'))\n return { value: trimmed.slice(1, -1).trim(), warnings: [] }\n\n if (trimmed.startsWith('{') || trimmed.endsWith('}'))\n return {\n value: trimmed.replace(/^\\{/, '').replace(/\\}$/, '').trim(),\n warnings: ['Malformed directive attributes: braces must be balanced.'],\n }\n\n return { value: trimmed, warnings: [] }\n}\n\nfunction stripQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n )\n return value.slice(1, -1)\n\n return value\n}\n\nfunction tokenizeAttributes(value: string): TokenizeAttributesResult {\n const tokens: string[] = []\n const warnings: string[] = []\n let current = ''\n let quote: \"'\" | '\"' | null = null\n\n for (const char of value) {\n if ((char === '\"' || char === \"'\") && quote === null) {\n quote = char\n current += char\n continue\n }\n\n if (char === quote) {\n quote = null\n current += char\n continue\n }\n\n if (/\\s/.test(char) && quote === null) {\n if (current) tokens.push(current)\n current = ''\n continue\n }\n\n current += char\n }\n\n if (current) tokens.push(current)\n if (quote) warnings.push('Malformed directive attributes: quoted value is not closed.')\n\n return { tokens, warnings }\n}\n\nfunction appendClassName(attributes: DirectiveAttributes, className: string) {\n const existing = typeof attributes.class === 'string' ? attributes.class : ''\n attributes.class = [existing, className].filter(Boolean).join(' ')\n}\n\nexport function getDirectiveAttributeBraceState(value: string): BraceState {\n let depth = 0\n let escaped = false\n let hasBrace = false\n let quote: \"'\" | '\"' | null = null\n\n for (const char of value) {\n if (escaped) {\n escaped = false\n continue\n }\n\n if (char === '\\\\' && quote) {\n escaped = true\n continue\n }\n\n if ((char === '\"' || char === \"'\") && quote === null) {\n quote = char\n continue\n }\n\n if (char === quote) {\n quote = null\n continue\n }\n\n if (quote) continue\n\n if (char === '{') {\n hasBrace = true\n depth += 1\n continue\n }\n\n if (char === '}') {\n hasBrace = true\n depth = Math.max(0, depth - 1)\n }\n }\n\n return {\n depth,\n hasBrace,\n }\n}\n\nexport function hasUnclosedDirectiveAttributeBlock(value: string): boolean {\n const state = getDirectiveAttributeBraceState(value)\n\n return state.hasBrace && state.depth > 0\n}\n\nexport function parseDirectiveAttributesDetailed(value = ''): {\n attributes: DirectiveAttributes\n warnings: string[]\n} {\n const stripped = stripEnclosingBraces(value)\n const warnings = [...stripped.warnings]\n\n if (!stripped.value)\n return {\n attributes: {},\n warnings,\n }\n\n const attributes: DirectiveAttributes = {}\n const tokenized = tokenizeAttributes(stripped.value)\n warnings.push(...tokenized.warnings)\n\n for (const token of tokenized.tokens) {\n if (token.startsWith('#') && token.length > 1) {\n attributes.id = token.slice(1)\n continue\n }\n\n if (token.startsWith('.') && token.length > 1) {\n appendClassName(attributes, token.slice(1))\n continue\n }\n\n const equalIndex = token.indexOf('=')\n\n if (equalIndex < 0) {\n attributes[token] = true\n continue\n }\n\n const key = token.slice(0, equalIndex)\n const rawValue = token.slice(equalIndex + 1)\n\n if (!key) continue\n\n if (key === 'class') appendClassName(attributes, stripQuotes(rawValue))\n else attributes[key] = stripQuotes(rawValue)\n }\n\n return {\n attributes,\n warnings,\n }\n}\n\nexport function parseDirectiveAttributes(value = ''): DirectiveAttributes {\n return parseDirectiveAttributesDetailed(value).attributes\n}\n\nexport function parseDirectiveLine(text: string): null | ParsedDirectiveLine {\n const trimmed = text.trim()\n\n if (!trimmed.startsWith(':::')) return null\n\n let body = trimmed.slice(3)\n if (!body) return null\n\n const nameMatch = body.match(/^([\\w-]+)/)\n const name = nameMatch?.[1]\n\n if (!name) return null\n\n body = body.slice(name.length).trimStart()\n\n let label: string | undefined\n\n if (body.startsWith('[')) {\n const labelEnd = body.indexOf(']')\n if (labelEnd < 0) return null\n\n label = body.slice(1, labelEnd)\n body = body.slice(labelEnd + 1).trimStart()\n }\n\n const rawAttributes = body ? body : undefined\n\n const attributes = parseDirectiveAttributesDetailed(rawAttributes)\n\n return {\n name,\n attributes: attributes.attributes,\n label,\n rawAttributes,\n warnings: attributes.warnings,\n }\n}\n"],"names":["stripEnclosingBraces","value","trimmed","trim","warnings","startsWith","endsWith","slice","replace","stripQuotes","tokenizeAttributes","tokens","current","quote","char","test","push","appendClassName","attributes","className","existing","class","filter","Boolean","join","getDirectiveAttributeBraceState","depth","escaped","hasBrace","Math","max","hasUnclosedDirectiveAttributeBlock","state","parseDirectiveAttributesDetailed","stripped","tokenized","token","length","id","equalIndex","indexOf","key","rawValue","parseDirectiveAttributes","parseDirectiveLine","text","body","nameMatch","match","name","trimStart","label","labelEnd","rawAttributes","undefined"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { DirectiveAttributes } from './attributes.js';
2
+ export type ParsedButtonDirectiveLine = {
3
+ attributes: DirectiveAttributes;
4
+ label: string;
5
+ warnings: string[];
6
+ };
7
+ export declare function parseButtonDirectiveLine(text: string): null | ParsedButtonDirectiveLine;
@@ -0,0 +1,26 @@
1
+ import { parseDirectiveAttributesDetailed } from './attributes.js';
2
+ const BUTTON_LEAF_MARKER = '::button';
3
+ export function parseButtonDirectiveLine(text) {
4
+ const trimmed = text.trim();
5
+ if (!trimmed.startsWith(BUTTON_LEAF_MARKER)) return null;
6
+ let rest = trimmed.slice(BUTTON_LEAF_MARKER.length);
7
+ if (rest && !/^[\s[{]/.test(rest)) return null;
8
+ rest = rest.trimStart();
9
+ let label = '';
10
+ if (rest.startsWith('[')) {
11
+ const labelEnd = rest.indexOf(']');
12
+ if (labelEnd < 0) return null;
13
+ label = rest.slice(1, labelEnd);
14
+ rest = rest.slice(labelEnd + 1).trimStart();
15
+ }
16
+ const rawAttributes = rest;
17
+ if (rawAttributes && (!rawAttributes.startsWith('{') || !rawAttributes.endsWith('}'))) return null;
18
+ const parsedAttributes = parseDirectiveAttributesDetailed(rawAttributes);
19
+ return {
20
+ attributes: parsedAttributes.attributes,
21
+ label,
22
+ warnings: parsedAttributes.warnings
23
+ };
24
+ }
25
+
26
+ //# sourceMappingURL=buttonSyntax.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/directives/buttonSyntax.ts"],"sourcesContent":["import type { DirectiveAttributes } from './attributes.js'\n\nimport { parseDirectiveAttributesDetailed } from './attributes.js'\n\nexport type ParsedButtonDirectiveLine = {\n attributes: DirectiveAttributes\n label: string\n warnings: string[]\n}\n\nconst BUTTON_LEAF_MARKER = '::button'\n\nexport function parseButtonDirectiveLine(text: string): null | ParsedButtonDirectiveLine {\n const trimmed = text.trim()\n if (!trimmed.startsWith(BUTTON_LEAF_MARKER)) return null\n\n let rest = trimmed.slice(BUTTON_LEAF_MARKER.length)\n if (rest && !/^[\\s[{]/.test(rest)) return null\n\n rest = rest.trimStart()\n let label = ''\n\n if (rest.startsWith('[')) {\n const labelEnd = rest.indexOf(']')\n if (labelEnd < 0) return null\n\n label = rest.slice(1, labelEnd)\n rest = rest.slice(labelEnd + 1).trimStart()\n }\n\n const rawAttributes = rest\n if (rawAttributes && (!rawAttributes.startsWith('{') || !rawAttributes.endsWith('}')))\n return null\n\n const parsedAttributes = parseDirectiveAttributesDetailed(rawAttributes)\n\n return {\n attributes: parsedAttributes.attributes,\n label,\n warnings: parsedAttributes.warnings,\n }\n}\n"],"names":["parseDirectiveAttributesDetailed","BUTTON_LEAF_MARKER","parseButtonDirectiveLine","text","trimmed","trim","startsWith","rest","slice","length","test","trimStart","label","labelEnd","indexOf","rawAttributes","endsWith","parsedAttributes","attributes","warnings"],"mappings":"AAEA,SAASA,gCAAgC,QAAQ,kBAAiB;AAQlE,MAAMC,qBAAqB;AAE3B,OAAO,SAASC,yBAAyBC,IAAY;IACnD,MAAMC,UAAUD,KAAKE,IAAI;IACzB,IAAI,CAACD,QAAQE,UAAU,CAACL,qBAAqB,OAAO;IAEpD,IAAIM,OAAOH,QAAQI,KAAK,CAACP,mBAAmBQ,MAAM;IAClD,IAAIF,QAAQ,CAAC,UAAUG,IAAI,CAACH,OAAO,OAAO;IAE1CA,OAAOA,KAAKI,SAAS;IACrB,IAAIC,QAAQ;IAEZ,IAAIL,KAAKD,UAAU,CAAC,MAAM;QACxB,MAAMO,WAAWN,KAAKO,OAAO,CAAC;QAC9B,IAAID,WAAW,GAAG,OAAO;QAEzBD,QAAQL,KAAKC,KAAK,CAAC,GAAGK;QACtBN,OAAOA,KAAKC,KAAK,CAACK,WAAW,GAAGF,SAAS;IAC3C;IAEA,MAAMI,gBAAgBR;IACtB,IAAIQ,iBAAkB,CAAA,CAACA,cAAcT,UAAU,CAAC,QAAQ,CAACS,cAAcC,QAAQ,CAAC,IAAG,GACjF,OAAO;IAET,MAAMC,mBAAmBjB,iCAAiCe;IAE1D,OAAO;QACLG,YAAYD,iBAAiBC,UAAU;QACvCN;QACAO,UAAUF,iBAAiBE,QAAQ;IACrC;AACF"}
@@ -0,0 +1,8 @@
1
+ export type DirectiveCloseLabel = {
2
+ from: number;
3
+ kind: 'suffix' | 'widget';
4
+ label: string;
5
+ line: number;
6
+ to: number;
7
+ };
8
+ export declare function getDirectiveCloseLabels(markdown: string): DirectiveCloseLabel[];
@@ -0,0 +1,76 @@
1
+ import { layoutDirectiveRegistry } from './registry.js';
2
+ function isFenceLine(trimmed) {
3
+ return trimmed.startsWith('```') || trimmed.startsWith('~~~');
4
+ }
5
+ function findNearestFrameIndex(stack, predicate) {
6
+ for(let index = stack.length - 1; index >= 0; --index){
7
+ const frame = stack[index];
8
+ if (predicate(frame)) return index;
9
+ }
10
+ return -1;
11
+ }
12
+ function getCloseLabel(name) {
13
+ return layoutDirectiveRegistry.isGridName(name) ? 'endcol' : `end${name}`;
14
+ }
15
+ function makeExplicitLabel(label, line, markerFrom, markerTo) {
16
+ return {
17
+ from: markerFrom + 3,
18
+ kind: 'suffix',
19
+ label,
20
+ line,
21
+ to: markerTo
22
+ };
23
+ }
24
+ function makeWidgetLabel(label, line, markerFrom) {
25
+ return {
26
+ from: markerFrom + 3,
27
+ kind: 'widget',
28
+ label,
29
+ line,
30
+ to: markerFrom + 3
31
+ };
32
+ }
33
+ export function getDirectiveCloseLabels(markdown) {
34
+ const labels = [];
35
+ const stack = [];
36
+ const lines = markdown.split(/\r?\n/);
37
+ let offset = 0;
38
+ let inFence = false;
39
+ for(let index = 0; index < lines.length; ++index){
40
+ const line = lines[index];
41
+ const trimmed = line.trim();
42
+ const lineStart = offset;
43
+ const markerStart = line.indexOf(':::');
44
+ const markerFrom = markerStart >= 0 ? lineStart + markerStart : lineStart;
45
+ const markerTo = markerFrom + trimmed.length;
46
+ if (isFenceLine(trimmed)) {
47
+ inFence = !inFence;
48
+ offset += line.length + 1;
49
+ continue;
50
+ }
51
+ if (!inFence && trimmed.startsWith(':::')) {
52
+ const token = layoutDirectiveRegistry.parseMarkdownLineDetailed(trimmed).token;
53
+ if (token?.action === 'open') stack.push({
54
+ name: token.name
55
+ });
56
+ if (token?.action === 'close') {
57
+ const frame = stack.pop();
58
+ if (frame) labels.push(makeWidgetLabel(getCloseLabel(frame.name), index + 1, markerFrom));
59
+ }
60
+ if (token?.action === 'closeGrid') {
61
+ const frameIndex = findNearestFrameIndex(stack, (frame)=>layoutDirectiveRegistry.isGridName(frame.name));
62
+ if (frameIndex >= 0) stack.splice(frameIndex);
63
+ labels.push(makeExplicitLabel('endcol', index + 1, markerFrom, markerTo));
64
+ }
65
+ if (token?.action === 'closeSection') {
66
+ const frameIndex = findNearestFrameIndex(stack, (frame)=>frame.name === 'section');
67
+ if (frameIndex >= 0) stack.splice(frameIndex);
68
+ labels.push(makeExplicitLabel(trimmed.slice(3) || 'endsection', index + 1, markerFrom, markerTo));
69
+ }
70
+ }
71
+ offset += line.length + 1;
72
+ }
73
+ return labels;
74
+ }
75
+
76
+ //# sourceMappingURL=closeLabels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/directives/closeLabels.ts"],"sourcesContent":["import type { LayoutName } from './types.js'\n\nimport { layoutDirectiveRegistry } from './registry.js'\n\nexport type DirectiveCloseLabel = {\n from: number\n kind: 'suffix' | 'widget'\n label: string\n line: number\n to: number\n}\n\ntype OpenFrame = {\n name: LayoutName\n}\n\nfunction isFenceLine(trimmed: string): boolean {\n return trimmed.startsWith('```') || trimmed.startsWith('~~~')\n}\n\nfunction findNearestFrameIndex(stack: OpenFrame[], predicate: (frame: OpenFrame) => boolean) {\n for (let index = stack.length - 1; index >= 0; --index) {\n const frame = stack[index]\n if (predicate(frame)) return index\n }\n\n return -1\n}\n\nfunction getCloseLabel(name: LayoutName): string {\n return layoutDirectiveRegistry.isGridName(name) ? 'endcol' : `end${name}`\n}\n\nfunction makeExplicitLabel(\n label: string,\n line: number,\n markerFrom: number,\n markerTo: number,\n): DirectiveCloseLabel {\n return {\n from: markerFrom + 3,\n kind: 'suffix',\n label,\n line,\n to: markerTo,\n }\n}\n\nfunction makeWidgetLabel(\n label: string,\n line: number,\n markerFrom: number,\n): DirectiveCloseLabel {\n return {\n from: markerFrom + 3,\n kind: 'widget',\n label,\n line,\n to: markerFrom + 3,\n }\n}\n\nexport function getDirectiveCloseLabels(markdown: string): DirectiveCloseLabel[] {\n const labels: DirectiveCloseLabel[] = []\n const stack: OpenFrame[] = []\n const lines = markdown.split(/\\r?\\n/)\n let offset = 0\n let inFence = false\n\n for (let index = 0; index < lines.length; ++index) {\n const line = lines[index]\n const trimmed = line.trim()\n const lineStart = offset\n const markerStart = line.indexOf(':::')\n const markerFrom = markerStart >= 0 ? lineStart + markerStart : lineStart\n const markerTo = markerFrom + trimmed.length\n\n if (isFenceLine(trimmed)) {\n inFence = !inFence\n offset += line.length + 1\n continue\n }\n\n if (!inFence && trimmed.startsWith(':::')) {\n const token = layoutDirectiveRegistry.parseMarkdownLineDetailed(trimmed).token\n\n if (token?.action === 'open') stack.push({ name: token.name })\n\n if (token?.action === 'close') {\n const frame = stack.pop()\n if (frame) labels.push(makeWidgetLabel(getCloseLabel(frame.name), index + 1, markerFrom))\n }\n\n if (token?.action === 'closeGrid') {\n const frameIndex = findNearestFrameIndex(stack, (frame) =>\n layoutDirectiveRegistry.isGridName(frame.name),\n )\n\n if (frameIndex >= 0) stack.splice(frameIndex)\n labels.push(makeExplicitLabel('endcol', index + 1, markerFrom, markerTo))\n }\n\n if (token?.action === 'closeSection') {\n const frameIndex = findNearestFrameIndex(stack, (frame) => frame.name === 'section')\n\n if (frameIndex >= 0) stack.splice(frameIndex)\n labels.push(\n makeExplicitLabel(trimmed.slice(3) || 'endsection', index + 1, markerFrom, markerTo),\n )\n }\n }\n\n offset += line.length + 1\n }\n\n return labels\n}\n"],"names":["layoutDirectiveRegistry","isFenceLine","trimmed","startsWith","findNearestFrameIndex","stack","predicate","index","length","frame","getCloseLabel","name","isGridName","makeExplicitLabel","label","line","markerFrom","markerTo","from","kind","to","makeWidgetLabel","getDirectiveCloseLabels","markdown","labels","lines","split","offset","inFence","trim","lineStart","markerStart","indexOf","token","parseMarkdownLineDetailed","action","push","pop","frameIndex","splice","slice"],"mappings":"AAEA,SAASA,uBAAuB,QAAQ,gBAAe;AAcvD,SAASC,YAAYC,OAAe;IAClC,OAAOA,QAAQC,UAAU,CAAC,UAAUD,QAAQC,UAAU,CAAC;AACzD;AAEA,SAASC,sBAAsBC,KAAkB,EAAEC,SAAwC;IACzF,IAAK,IAAIC,QAAQF,MAAMG,MAAM,GAAG,GAAGD,SAAS,GAAG,EAAEA,MAAO;QACtD,MAAME,QAAQJ,KAAK,CAACE,MAAM;QAC1B,IAAID,UAAUG,QAAQ,OAAOF;IAC/B;IAEA,OAAO,CAAC;AACV;AAEA,SAASG,cAAcC,IAAgB;IACrC,OAAOX,wBAAwBY,UAAU,CAACD,QAAQ,WAAW,CAAC,GAAG,EAAEA,MAAM;AAC3E;AAEA,SAASE,kBACPC,KAAa,EACbC,IAAY,EACZC,UAAkB,EAClBC,QAAgB;IAEhB,OAAO;QACLC,MAAMF,aAAa;QACnBG,MAAM;QACNL;QACAC;QACAK,IAAIH;IACN;AACF;AAEA,SAASI,gBACPP,KAAa,EACbC,IAAY,EACZC,UAAkB;IAElB,OAAO;QACLE,MAAMF,aAAa;QACnBG,MAAM;QACNL;QACAC;QACAK,IAAIJ,aAAa;IACnB;AACF;AAEA,OAAO,SAASM,wBAAwBC,QAAgB;IACtD,MAAMC,SAAgC,EAAE;IACxC,MAAMnB,QAAqB,EAAE;IAC7B,MAAMoB,QAAQF,SAASG,KAAK,CAAC;IAC7B,IAAIC,SAAS;IACb,IAAIC,UAAU;IAEd,IAAK,IAAIrB,QAAQ,GAAGA,QAAQkB,MAAMjB,MAAM,EAAE,EAAED,MAAO;QACjD,MAAMQ,OAAOU,KAAK,CAAClB,MAAM;QACzB,MAAML,UAAUa,KAAKc,IAAI;QACzB,MAAMC,YAAYH;QAClB,MAAMI,cAAchB,KAAKiB,OAAO,CAAC;QACjC,MAAMhB,aAAae,eAAe,IAAID,YAAYC,cAAcD;QAChE,MAAMb,WAAWD,aAAad,QAAQM,MAAM;QAE5C,IAAIP,YAAYC,UAAU;YACxB0B,UAAU,CAACA;YACXD,UAAUZ,KAAKP,MAAM,GAAG;YACxB;QACF;QAEA,IAAI,CAACoB,WAAW1B,QAAQC,UAAU,CAAC,QAAQ;YACzC,MAAM8B,QAAQjC,wBAAwBkC,yBAAyB,CAAChC,SAAS+B,KAAK;YAE9E,IAAIA,OAAOE,WAAW,QAAQ9B,MAAM+B,IAAI,CAAC;gBAAEzB,MAAMsB,MAAMtB,IAAI;YAAC;YAE5D,IAAIsB,OAAOE,WAAW,SAAS;gBAC7B,MAAM1B,QAAQJ,MAAMgC,GAAG;gBACvB,IAAI5B,OAAOe,OAAOY,IAAI,CAACf,gBAAgBX,cAAcD,MAAME,IAAI,GAAGJ,QAAQ,GAAGS;YAC/E;YAEA,IAAIiB,OAAOE,WAAW,aAAa;gBACjC,MAAMG,aAAalC,sBAAsBC,OAAO,CAACI,QAC/CT,wBAAwBY,UAAU,CAACH,MAAME,IAAI;gBAG/C,IAAI2B,cAAc,GAAGjC,MAAMkC,MAAM,CAACD;gBAClCd,OAAOY,IAAI,CAACvB,kBAAkB,UAAUN,QAAQ,GAAGS,YAAYC;YACjE;YAEA,IAAIgB,OAAOE,WAAW,gBAAgB;gBACpC,MAAMG,aAAalC,sBAAsBC,OAAO,CAACI,QAAUA,MAAME,IAAI,KAAK;gBAE1E,IAAI2B,cAAc,GAAGjC,MAAMkC,MAAM,CAACD;gBAClCd,OAAOY,IAAI,CACTvB,kBAAkBX,QAAQsC,KAAK,CAAC,MAAM,cAAcjC,QAAQ,GAAGS,YAAYC;YAE/E;QACF;QAEAU,UAAUZ,KAAKP,MAAM,GAAG;IAC1B;IAEA,OAAOgB;AACT"}
@@ -0,0 +1,15 @@
1
+ import type { LayoutDirectiveDefinition } from '../types.js';
2
+ export declare const BUTTON_VARIANTS: readonly ["primary", "secondary", "outline", "ghost", "link"];
3
+ export declare const BUTTON_SIZES: readonly ["sm", "md", "lg"];
4
+ export declare const BUTTON_ICON_POSITIONS: readonly ["left", "right"];
5
+ export declare const BUTTON_ALLOWED_ATTRIBUTES: readonly ["ariaLabel", "href", "icon", "iconPosition", "newTab", "size", "variant"];
6
+ export declare const DEFAULT_BUTTON_VARIANT = "primary";
7
+ export declare const DEFAULT_BUTTON_SIZE = "md";
8
+ export declare const DEFAULT_BUTTON_ICON_POSITION = "left";
9
+ export type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
10
+ export type ButtonSize = (typeof BUTTON_SIZES)[number];
11
+ export type ButtonIconPosition = (typeof BUTTON_ICON_POSITIONS)[number];
12
+ export declare function isButtonVariant(value: unknown): value is ButtonVariant;
13
+ export declare function isButtonSize(value: unknown): value is ButtonSize;
14
+ export declare function isButtonIconPosition(value: unknown): value is ButtonIconPosition;
15
+ export declare const buttonDirective: LayoutDirectiveDefinition;