@valkyrianlabs/payload-markdown 1.3.3 → 1.4.0

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 (99) hide show
  1. package/README.md +63 -14
  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 +5 -1
  98. package/dist/types.js.map +1 -1
  99. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  import { resolveDirectiveTheme } from '../themes.js';
2
+ import { DEFAULT_CARD_LINK_SCOPE } from './card.js';
2
3
  export const CARD_GRID_COLUMNS = [
3
4
  '1',
4
5
  '2',
@@ -7,6 +8,13 @@ export const CARD_GRID_COLUMNS = [
7
8
  'auto'
8
9
  ];
9
10
  export const DEFAULT_CARD_GRID_COLUMNS = '3';
11
+ export const CARDS_LINK_SCOPES = [
12
+ 'section',
13
+ 'card',
14
+ 'title'
15
+ ];
16
+ export const DEFAULT_CARDS_LINK_SCOPE = 'section';
17
+ export const FALLBACK_CARDS_LINK_SCOPE = 'card';
10
18
  const cardGridColumnClasses = {
11
19
  '1': 'grid-cols-1',
12
20
  '2': 'grid-cols-1 md:grid-cols-2',
@@ -17,6 +25,62 @@ const cardGridColumnClasses = {
17
25
  function isCardGridColumns(value) {
18
26
  return typeof value === 'string' && CARD_GRID_COLUMNS.includes(value);
19
27
  }
28
+ function isCardsLinkScope(value) {
29
+ return typeof value === 'string' && CARDS_LINK_SCOPES.includes(value);
30
+ }
31
+ function getAttribute(node, name) {
32
+ const value = node.attributes?.[name];
33
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
34
+ }
35
+ function getBooleanAttribute(node, name) {
36
+ const attributes = node.attributes;
37
+ const value = attributes?.[name];
38
+ if (value === true) return true;
39
+ if (typeof value !== 'string') return false;
40
+ return value === 'true';
41
+ }
42
+ function hasAttribute(node, name) {
43
+ return Object.prototype.hasOwnProperty.call(node.attributes ?? {}, name);
44
+ }
45
+ function getCardsLinkScope(node) {
46
+ const value = node.attributes?.linkScope;
47
+ if (typeof value !== 'string') return DEFAULT_CARDS_LINK_SCOPE;
48
+ return isCardsLinkScope(value) ? value : FALLBACK_CARDS_LINK_SCOPE;
49
+ }
50
+ function getLinkProperties(href, newTab) {
51
+ return {
52
+ href,
53
+ ...newTab ? {
54
+ rel: 'noopener noreferrer',
55
+ target: '_blank'
56
+ } : {}
57
+ };
58
+ }
59
+ function makeSectionLink(href, newTab) {
60
+ return {
61
+ type: 'element',
62
+ children: [],
63
+ properties: {
64
+ ...getLinkProperties(href, newTab),
65
+ ariaLabel: 'Open card section',
66
+ className: [
67
+ 'absolute inset-0 z-10 rounded-[inherit] focus:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300'
68
+ ],
69
+ dataDirectiveLink: 'cards'
70
+ },
71
+ tagName: 'a'
72
+ };
73
+ }
74
+ function hasCardLinkOverride(node) {
75
+ return [
76
+ 'href',
77
+ 'linkScope',
78
+ 'newTab'
79
+ ].some((name)=>hasAttribute(node, name));
80
+ }
81
+ function isContainerDirective(node) {
82
+ return Boolean(node && typeof node === 'object' && 'type' in node && node.type === 'containerDirective');
83
+ }
20
84
  export function resolveCardGridColumns(node) {
21
85
  const columns = node.attributes?.columns;
22
86
  return isCardGridColumns(columns) ? columns : DEFAULT_CARD_GRID_COLUMNS;
@@ -26,30 +90,72 @@ export const cardsDirective = {
26
90
  allowedAttributes: [
27
91
  'cardTheme',
28
92
  'columns',
93
+ 'href',
94
+ 'linkScope',
95
+ 'newTab',
29
96
  'theme'
30
97
  ],
31
98
  applyHast (node, config, { mergeClassNames }) {
32
99
  const columns = typeof node.properties.dataColumns === 'string' ? node.properties.dataColumns : DEFAULT_CARD_GRID_COLUMNS;
100
+ const href = typeof node.properties.dataHref === 'string' ? node.properties.dataHref : undefined;
101
+ const linkScope = typeof node.properties.dataLinkScope === 'string' && isCardsLinkScope(node.properties.dataLinkScope) ? node.properties.dataLinkScope : DEFAULT_CARDS_LINK_SCOPE;
102
+ const newTab = node.properties.dataNewTab === 'true';
33
103
  const theme = resolveDirectiveTheme('cards', typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined, config.themes);
34
104
  const cardTheme = typeof node.properties.dataCardTheme === 'string' ? node.properties.dataCardTheme : undefined;
35
- for (const child of node.children)if (child.type === 'element' && child.properties?.dataVlLayout === 'card' && typeof child.properties.dataTheme !== 'string' && cardTheme) child.properties.dataTheme = cardTheme;
105
+ const childLinkScope = linkScope === 'title' ? 'title' : DEFAULT_CARD_LINK_SCOPE;
106
+ for (const child of node.children){
107
+ if (child.type !== 'element' || child.properties?.dataVlLayout !== 'card') continue;
108
+ if (typeof child.properties.dataTheme !== 'string' && cardTheme) child.properties.dataTheme = cardTheme;
109
+ if (href && linkScope === 'section') {
110
+ delete child.properties.dataHref;
111
+ delete child.properties.dataLinkScope;
112
+ delete child.properties.dataNewTab;
113
+ continue;
114
+ }
115
+ if (!href) continue;
116
+ if (typeof child.properties.dataHref !== 'string') child.properties.dataHref = href;
117
+ if (typeof child.properties.dataLinkScope !== 'string') child.properties.dataLinkScope = childLinkScope;
118
+ if (typeof child.properties.dataNewTab !== 'string') child.properties.dataNewTab = newTab ? 'true' : 'false';
119
+ }
36
120
  node.properties.dataTheme = theme.name;
37
- node.properties.className = mergeClassNames('not-prose my-8 grid gap-4', theme.hookClassName, theme.modifierClassName, theme.classes, cardGridColumnClasses[isCardGridColumns(columns) ? columns : DEFAULT_CARD_GRID_COLUMNS]);
121
+ if (href) {
122
+ node.properties.dataLinkScope = linkScope;
123
+ node.properties.dataNewTab = newTab ? 'true' : 'false';
124
+ }
125
+ node.properties.className = mergeClassNames('not-prose my-8 grid gap-4', href && linkScope === 'section' ? 'relative cursor-pointer [&_a:not([data-directive-link])]:relative [&_a:not([data-directive-link])]:z-20' : undefined, theme.hookClassName, theme.modifierClassName, theme.classes, cardGridColumnClasses[isCardGridColumns(columns) ? columns : DEFAULT_CARD_GRID_COLUMNS]);
126
+ if (href && linkScope === 'section') node.children = [
127
+ makeSectionLink(href, newTab),
128
+ ...node.children
129
+ ];
130
+ },
131
+ attributeValues: {
132
+ columns: CARD_GRID_COLUMNS,
133
+ linkScope: CARDS_LINK_SCOPES,
134
+ newTab: [
135
+ 'true',
136
+ 'false'
137
+ ]
38
138
  },
39
139
  defaultAttributes: {
40
- columns: DEFAULT_CARD_GRID_COLUMNS
140
+ columns: DEFAULT_CARD_GRID_COLUMNS,
141
+ linkScope: DEFAULT_CARDS_LINK_SCOPE,
142
+ newTab: 'false'
41
143
  },
42
144
  description: 'Responsive card grid for docs and landing-page content.',
43
145
  editor: {
44
146
  detail: 'Layout directive',
45
147
  label: 'Cards',
46
- snippet: ':::cards {columns="${3}"}\n\n:::card {title="${Title}"}\n${Content}\n:::\n\n:::card {title="${Title}"}\n${Content}\n:::\n\n:::\n${}'
148
+ snippet: ':::cards{\n columns="${3}"\n}\n\n:::card[${Title}]\n${Content}\n:::\n\n:::card[${Title}]\n${Content}\n:::\n\n:::\n${}'
47
149
  },
48
150
  getMdastRenderProperties (node) {
151
+ const href = getAttribute(node, 'href');
49
152
  return {
50
153
  dataCardTheme: typeof node.attributes?.cardTheme === 'string' ? node.attributes.cardTheme : undefined,
51
154
  dataColumns: resolveCardGridColumns(node),
52
155
  dataDirective: 'cards',
156
+ dataHref: href,
157
+ dataLinkScope: href || hasAttribute(node, 'linkScope') ? getCardsLinkScope(node) : undefined,
158
+ dataNewTab: href && hasAttribute(node, 'newTab') ? getBooleanAttribute(node, 'newTab') ? 'true' : 'false' : undefined,
53
159
  dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default'
54
160
  };
55
161
  },
@@ -65,6 +171,15 @@ export const cardsDirective = {
65
171
  validateAttributes ({ attributes }) {
66
172
  const warnings = [];
67
173
  if (typeof attributes.columns === 'string' && !isCardGridColumns(attributes.columns)) warnings.push(`Invalid cards columns "${attributes.columns}". Falling back to "${DEFAULT_CARD_GRID_COLUMNS}".`);
174
+ if (typeof attributes.linkScope === 'string' && !isCardsLinkScope(attributes.linkScope)) warnings.push(`Invalid cards linkScope "${attributes.linkScope}". Falling back to "${FALLBACK_CARDS_LINK_SCOPE}".`);
175
+ return warnings;
176
+ },
177
+ validateMdast (node) {
178
+ const warnings = [];
179
+ if (getAttribute(node, 'href') && getCardsLinkScope(node) === 'section') {
180
+ const hasOverrides = node.children.some((child)=>isContainerDirective(child) && child.name === 'card' && hasCardLinkOverride(child));
181
+ if (hasOverrides) warnings.push('Directive "cards" with linkScope="section" ignores child "card" link overrides.');
182
+ }
68
183
  return warnings;
69
184
  }
70
185
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/directives/definitions/cards.ts"],"sourcesContent":["import type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { resolveDirectiveTheme } from '../themes.js'\n\nexport const CARD_GRID_COLUMNS = ['1', '2', '3', '4', 'auto'] as const\nexport const DEFAULT_CARD_GRID_COLUMNS = '3'\n\nexport type CardGridColumns = (typeof CARD_GRID_COLUMNS)[number]\n\nconst cardGridColumnClasses: Record<CardGridColumns, string> = {\n '1': 'grid-cols-1',\n '2': 'grid-cols-1 md:grid-cols-2',\n '3': 'grid-cols-1 md:grid-cols-3',\n '4': 'grid-cols-1 sm:grid-cols-2 xl:grid-cols-4',\n auto: 'grid-cols-1 md:grid-cols-[repeat(auto-fit,minmax(16rem,1fr))]',\n}\n\nfunction isCardGridColumns(value: unknown): value is CardGridColumns {\n return typeof value === 'string' && CARD_GRID_COLUMNS.includes(value as CardGridColumns)\n}\n\nexport function resolveCardGridColumns(node: ContainerDirective): CardGridColumns {\n const columns = node.attributes?.columns\n\n return isCardGridColumns(columns) ? columns : DEFAULT_CARD_GRID_COLUMNS\n}\n\nexport const cardsDirective: LayoutDirectiveDefinition = {\n name: 'cards',\n allowedAttributes: ['cardTheme', 'columns', 'theme'],\n applyHast(node, config, { mergeClassNames }) {\n const columns =\n typeof node.properties.dataColumns === 'string'\n ? node.properties.dataColumns\n : DEFAULT_CARD_GRID_COLUMNS\n const theme = resolveDirectiveTheme(\n 'cards',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n const cardTheme =\n typeof node.properties.dataCardTheme === 'string' ? node.properties.dataCardTheme : undefined\n\n for (const child of node.children)\n if (\n child.type === 'element' &&\n child.properties?.dataVlLayout === 'card' &&\n typeof child.properties.dataTheme !== 'string' &&\n cardTheme\n )\n child.properties.dataTheme = cardTheme\n\n node.properties.dataTheme = theme.name\n node.properties.className = mergeClassNames(\n 'not-prose my-8 grid gap-4',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n cardGridColumnClasses[isCardGridColumns(columns) ? columns : DEFAULT_CARD_GRID_COLUMNS],\n )\n },\n defaultAttributes: {\n columns: DEFAULT_CARD_GRID_COLUMNS,\n },\n description: 'Responsive card grid for docs and landing-page content.',\n editor: {\n detail: 'Layout directive',\n label: 'Cards',\n snippet:\n ':::cards {columns=\"${3}\"}\\n\\n:::card {title=\"${Title}\"}\\n${Content}\\n:::\\n\\n:::card {title=\"${Title}\"}\\n${Content}\\n:::\\n\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataCardTheme: typeof node.attributes?.cardTheme === 'string' ? node.attributes.cardTheme : undefined,\n dataColumns: resolveCardGridColumns(node),\n dataDirective: 'cards',\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default',\n }\n },\n kind: 'cards',\n openMarker: ':::cards',\n public: true,\n supportsAttributes: true,\n tagName: 'section',\n themeAttributes: {\n cardTheme: 'card',\n theme: 'cards',\n },\n validateAttributes({ attributes }) {\n const warnings: string[] = []\n\n if (typeof attributes.columns === 'string' && !isCardGridColumns(attributes.columns))\n warnings.push(\n `Invalid cards columns \"${attributes.columns}\". Falling back to \"${DEFAULT_CARD_GRID_COLUMNS}\".`,\n )\n\n return warnings\n },\n}\n"],"names":["resolveDirectiveTheme","CARD_GRID_COLUMNS","DEFAULT_CARD_GRID_COLUMNS","cardGridColumnClasses","auto","isCardGridColumns","value","includes","resolveCardGridColumns","node","columns","attributes","cardsDirective","name","allowedAttributes","applyHast","config","mergeClassNames","properties","dataColumns","theme","dataTheme","undefined","themes","cardTheme","dataCardTheme","child","children","type","dataVlLayout","className","hookClassName","modifierClassName","classes","defaultAttributes","description","editor","detail","label","snippet","getMdastRenderProperties","dataDirective","kind","openMarker","public","supportsAttributes","tagName","themeAttributes","validateAttributes","warnings","push"],"mappings":"AAIA,SAASA,qBAAqB,QAAQ,eAAc;AAEpD,OAAO,MAAMC,oBAAoB;IAAC;IAAK;IAAK;IAAK;IAAK;CAAO,CAAS;AACtE,OAAO,MAAMC,4BAA4B,IAAG;AAI5C,MAAMC,wBAAyD;IAC7D,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACLC,MAAM;AACR;AAEA,SAASC,kBAAkBC,KAAc;IACvC,OAAO,OAAOA,UAAU,YAAYL,kBAAkBM,QAAQ,CAACD;AACjE;AAEA,OAAO,SAASE,uBAAuBC,IAAwB;IAC7D,MAAMC,UAAUD,KAAKE,UAAU,EAAED;IAEjC,OAAOL,kBAAkBK,WAAWA,UAAUR;AAChD;AAEA,OAAO,MAAMU,iBAA4C;IACvDC,MAAM;IACNC,mBAAmB;QAAC;QAAa;QAAW;KAAQ;IACpDC,WAAUN,IAAI,EAAEO,MAAM,EAAE,EAAEC,eAAe,EAAE;QACzC,MAAMP,UACJ,OAAOD,KAAKS,UAAU,CAACC,WAAW,KAAK,WACnCV,KAAKS,UAAU,CAACC,WAAW,GAC3BjB;QACN,MAAMkB,QAAQpB,sBACZ,SACA,OAAOS,KAAKS,UAAU,CAACG,SAAS,KAAK,WAAWZ,KAAKS,UAAU,CAACG,SAAS,GAAGC,WAC5EN,OAAOO,MAAM;QAEf,MAAMC,YACJ,OAAOf,KAAKS,UAAU,CAACO,aAAa,KAAK,WAAWhB,KAAKS,UAAU,CAACO,aAAa,GAAGH;QAEtF,KAAK,MAAMI,SAASjB,KAAKkB,QAAQ,CAC/B,IACED,MAAME,IAAI,KAAK,aACfF,MAAMR,UAAU,EAAEW,iBAAiB,UACnC,OAAOH,MAAMR,UAAU,CAACG,SAAS,KAAK,YACtCG,WAEAE,MAAMR,UAAU,CAACG,SAAS,GAAGG;QAEjCf,KAAKS,UAAU,CAACG,SAAS,GAAGD,MAAMP,IAAI;QACtCJ,KAAKS,UAAU,CAACY,SAAS,GAAGb,gBAC1B,6BACAG,MAAMW,aAAa,EACnBX,MAAMY,iBAAiB,EACvBZ,MAAMa,OAAO,EACb9B,qBAAqB,CAACE,kBAAkBK,WAAWA,UAAUR,0BAA0B;IAE3F;IACAgC,mBAAmB;QACjBxB,SAASR;IACX;IACAiC,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRC,OAAO;QACPC,SACE;IACJ;IACAC,0BAAyB/B,IAAI;QAC3B,OAAO;YACLgB,eAAe,OAAOhB,KAAKE,UAAU,EAAEa,cAAc,WAAWf,KAAKE,UAAU,CAACa,SAAS,GAAGF;YAC5FH,aAAaX,uBAAuBC;YACpCgC,eAAe;YACfpB,WAAW,OAAOZ,KAAKE,UAAU,EAAES,UAAU,WAAWX,KAAKE,UAAU,CAACS,KAAK,GAAG;QAClF;IACF;IACAsB,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBC,SAAS;IACTC,iBAAiB;QACfvB,WAAW;QACXJ,OAAO;IACT;IACA4B,oBAAmB,EAAErC,UAAU,EAAE;QAC/B,MAAMsC,WAAqB,EAAE;QAE7B,IAAI,OAAOtC,WAAWD,OAAO,KAAK,YAAY,CAACL,kBAAkBM,WAAWD,OAAO,GACjFuC,SAASC,IAAI,CACX,CAAC,uBAAuB,EAAEvC,WAAWD,OAAO,CAAC,oBAAoB,EAAER,0BAA0B,EAAE,CAAC;QAGpG,OAAO+C;IACT;AACF,EAAC"}
1
+ {"version":3,"sources":["../../../src/directives/definitions/cards.ts"],"sourcesContent":["import type { Element } from 'hast'\nimport type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { resolveDirectiveTheme } from '../themes.js'\nimport { DEFAULT_CARD_LINK_SCOPE } from './card.js'\n\nexport const CARD_GRID_COLUMNS = ['1', '2', '3', '4', 'auto'] as const\nexport const DEFAULT_CARD_GRID_COLUMNS = '3'\nexport const CARDS_LINK_SCOPES = ['section', 'card', 'title'] as const\nexport const DEFAULT_CARDS_LINK_SCOPE = 'section'\nexport const FALLBACK_CARDS_LINK_SCOPE = 'card'\n\nexport type CardGridColumns = (typeof CARD_GRID_COLUMNS)[number]\nexport type CardsLinkScope = (typeof CARDS_LINK_SCOPES)[number]\n\nconst cardGridColumnClasses: Record<CardGridColumns, string> = {\n '1': 'grid-cols-1',\n '2': 'grid-cols-1 md:grid-cols-2',\n '3': 'grid-cols-1 md:grid-cols-3',\n '4': 'grid-cols-1 sm:grid-cols-2 xl:grid-cols-4',\n auto: 'grid-cols-1 md:grid-cols-[repeat(auto-fit,minmax(16rem,1fr))]',\n}\n\nfunction isCardGridColumns(value: unknown): value is CardGridColumns {\n return typeof value === 'string' && CARD_GRID_COLUMNS.includes(value as CardGridColumns)\n}\n\nfunction isCardsLinkScope(value: unknown): value is CardsLinkScope {\n return typeof value === 'string' && CARDS_LINK_SCOPES.includes(value as CardsLinkScope)\n}\n\nfunction getAttribute(node: ContainerDirective, name: string): string | undefined {\n const value = node.attributes?.[name]\n\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction getBooleanAttribute(node: ContainerDirective, name: string): boolean {\n const attributes = node.attributes as\n | null\n | Record<string, boolean | null | string | undefined>\n | undefined\n const value = attributes?.[name]\n\n if (value === true) return true\n if (typeof value !== 'string') return false\n\n return value === 'true'\n}\n\nfunction hasAttribute(node: ContainerDirective, name: string): boolean {\n return Object.prototype.hasOwnProperty.call(node.attributes ?? {}, name)\n}\n\nfunction getCardsLinkScope(node: ContainerDirective): CardsLinkScope {\n const value = node.attributes?.linkScope\n\n if (typeof value !== 'string') return DEFAULT_CARDS_LINK_SCOPE\n\n return isCardsLinkScope(value) ? value : FALLBACK_CARDS_LINK_SCOPE\n}\n\nfunction getLinkProperties(href: string, newTab: boolean): Element['properties'] {\n return {\n href,\n ...(newTab\n ? {\n rel: 'noopener noreferrer',\n target: '_blank',\n }\n : {}),\n }\n}\n\nfunction makeSectionLink(href: string, newTab: boolean): Element {\n return {\n type: 'element',\n children: [],\n properties: {\n ...getLinkProperties(href, newTab),\n ariaLabel: 'Open card section',\n className: [\n 'absolute inset-0 z-10 rounded-[inherit] focus:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300',\n ],\n dataDirectiveLink: 'cards',\n },\n tagName: 'a',\n }\n}\n\nfunction hasCardLinkOverride(node: ContainerDirective): boolean {\n return ['href', 'linkScope', 'newTab'].some((name) => hasAttribute(node, name))\n}\n\nfunction isContainerDirective(node: unknown): node is ContainerDirective {\n return Boolean(\n node &&\n typeof node === 'object' &&\n 'type' in node &&\n (node as { type?: string }).type === 'containerDirective',\n )\n}\n\nexport function resolveCardGridColumns(node: ContainerDirective): CardGridColumns {\n const columns = node.attributes?.columns\n\n return isCardGridColumns(columns) ? columns : DEFAULT_CARD_GRID_COLUMNS\n}\n\nexport const cardsDirective: LayoutDirectiveDefinition = {\n name: 'cards',\n allowedAttributes: ['cardTheme', 'columns', 'href', 'linkScope', 'newTab', 'theme'],\n applyHast(node, config, { mergeClassNames }) {\n const columns =\n typeof node.properties.dataColumns === 'string'\n ? node.properties.dataColumns\n : DEFAULT_CARD_GRID_COLUMNS\n const href = typeof node.properties.dataHref === 'string' ? node.properties.dataHref : undefined\n const linkScope =\n typeof node.properties.dataLinkScope === 'string' && isCardsLinkScope(node.properties.dataLinkScope)\n ? node.properties.dataLinkScope\n : DEFAULT_CARDS_LINK_SCOPE\n const newTab = node.properties.dataNewTab === 'true'\n const theme = resolveDirectiveTheme(\n 'cards',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n const cardTheme =\n typeof node.properties.dataCardTheme === 'string' ? node.properties.dataCardTheme : undefined\n const childLinkScope = linkScope === 'title' ? 'title' : DEFAULT_CARD_LINK_SCOPE\n\n for (const child of node.children) {\n if (child.type !== 'element' || child.properties?.dataVlLayout !== 'card') continue\n\n if (typeof child.properties.dataTheme !== 'string' && cardTheme)\n child.properties.dataTheme = cardTheme\n\n if (href && linkScope === 'section') {\n delete child.properties.dataHref\n delete child.properties.dataLinkScope\n delete child.properties.dataNewTab\n continue\n }\n\n if (!href) continue\n\n if (typeof child.properties.dataHref !== 'string') child.properties.dataHref = href\n if (typeof child.properties.dataLinkScope !== 'string')\n child.properties.dataLinkScope = childLinkScope\n if (typeof child.properties.dataNewTab !== 'string')\n child.properties.dataNewTab = newTab ? 'true' : 'false'\n }\n\n node.properties.dataTheme = theme.name\n if (href) {\n node.properties.dataLinkScope = linkScope\n node.properties.dataNewTab = newTab ? 'true' : 'false'\n }\n node.properties.className = mergeClassNames(\n 'not-prose my-8 grid gap-4',\n href && linkScope === 'section' ? 'relative cursor-pointer [&_a:not([data-directive-link])]:relative [&_a:not([data-directive-link])]:z-20' : undefined,\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n cardGridColumnClasses[isCardGridColumns(columns) ? columns : DEFAULT_CARD_GRID_COLUMNS],\n )\n\n if (href && linkScope === 'section') node.children = [makeSectionLink(href, newTab), ...node.children]\n },\n attributeValues: {\n columns: CARD_GRID_COLUMNS,\n linkScope: CARDS_LINK_SCOPES,\n newTab: ['true', 'false'],\n },\n defaultAttributes: {\n columns: DEFAULT_CARD_GRID_COLUMNS,\n linkScope: DEFAULT_CARDS_LINK_SCOPE,\n newTab: 'false',\n },\n description: 'Responsive card grid for docs and landing-page content.',\n editor: {\n detail: 'Layout directive',\n label: 'Cards',\n snippet:\n ':::cards{\\n columns=\"${3}\"\\n}\\n\\n:::card[${Title}]\\n${Content}\\n:::\\n\\n:::card[${Title}]\\n${Content}\\n:::\\n\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n const href = getAttribute(node, 'href')\n\n return {\n dataCardTheme: typeof node.attributes?.cardTheme === 'string' ? node.attributes.cardTheme : undefined,\n dataColumns: resolveCardGridColumns(node),\n dataDirective: 'cards',\n dataHref: href,\n dataLinkScope: href || hasAttribute(node, 'linkScope') ? getCardsLinkScope(node) : undefined,\n dataNewTab: href && hasAttribute(node, 'newTab')\n ? getBooleanAttribute(node, 'newTab') ? 'true' : 'false'\n : undefined,\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default',\n }\n },\n kind: 'cards',\n openMarker: ':::cards',\n public: true,\n supportsAttributes: true,\n tagName: 'section',\n themeAttributes: {\n cardTheme: 'card',\n theme: 'cards',\n },\n validateAttributes({ attributes }) {\n const warnings: string[] = []\n\n if (typeof attributes.columns === 'string' && !isCardGridColumns(attributes.columns))\n warnings.push(\n `Invalid cards columns \"${attributes.columns}\". Falling back to \"${DEFAULT_CARD_GRID_COLUMNS}\".`,\n )\n\n if (typeof attributes.linkScope === 'string' && !isCardsLinkScope(attributes.linkScope))\n warnings.push(\n `Invalid cards linkScope \"${attributes.linkScope}\". Falling back to \"${FALLBACK_CARDS_LINK_SCOPE}\".`,\n )\n\n return warnings\n },\n validateMdast(node) {\n const warnings: string[] = []\n\n if (getAttribute(node, 'href') && getCardsLinkScope(node) === 'section') {\n const hasOverrides = node.children.some(\n (child) => isContainerDirective(child) && child.name === 'card' && hasCardLinkOverride(child),\n )\n\n if (hasOverrides)\n warnings.push(\n 'Directive \"cards\" with linkScope=\"section\" ignores child \"card\" link overrides.',\n )\n }\n\n return warnings\n },\n}\n"],"names":["resolveDirectiveTheme","DEFAULT_CARD_LINK_SCOPE","CARD_GRID_COLUMNS","DEFAULT_CARD_GRID_COLUMNS","CARDS_LINK_SCOPES","DEFAULT_CARDS_LINK_SCOPE","FALLBACK_CARDS_LINK_SCOPE","cardGridColumnClasses","auto","isCardGridColumns","value","includes","isCardsLinkScope","getAttribute","node","name","attributes","trim","undefined","getBooleanAttribute","hasAttribute","Object","prototype","hasOwnProperty","call","getCardsLinkScope","linkScope","getLinkProperties","href","newTab","rel","target","makeSectionLink","type","children","properties","ariaLabel","className","dataDirectiveLink","tagName","hasCardLinkOverride","some","isContainerDirective","Boolean","resolveCardGridColumns","columns","cardsDirective","allowedAttributes","applyHast","config","mergeClassNames","dataColumns","dataHref","dataLinkScope","dataNewTab","theme","dataTheme","themes","cardTheme","dataCardTheme","childLinkScope","child","dataVlLayout","hookClassName","modifierClassName","classes","attributeValues","defaultAttributes","description","editor","detail","label","snippet","getMdastRenderProperties","dataDirective","kind","openMarker","public","supportsAttributes","themeAttributes","validateAttributes","warnings","push","validateMdast","hasOverrides"],"mappings":"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"}
@@ -1,8 +1,9 @@
1
+ import { getDirectiveLabelOrAttribute } from '../labels.js';
1
2
  import { resolveDirectiveTheme } from '../themes.js';
2
3
  const DEFAULT_DETAILS_TITLE = 'Details';
3
4
  function getTitle(node) {
4
- const title = node.attributes?.title;
5
- return typeof title === 'string' && title.trim() ? title.trim() : DEFAULT_DETAILS_TITLE;
5
+ const title = getDirectiveLabelOrAttribute(node, 'title');
6
+ return title ?? DEFAULT_DETAILS_TITLE;
6
7
  }
7
8
  export const detailsDirective = {
8
9
  name: 'details',
@@ -53,7 +54,7 @@ export const detailsDirective = {
53
54
  editor: {
54
55
  detail: 'Static directive',
55
56
  label: 'Details',
56
- snippet: ':::details {title="${Details}"}\n${Content}\n:::\n${}'
57
+ snippet: ':::details[${Details}]\n${Content}\n:::\n${}'
57
58
  },
58
59
  getMdastRenderProperties (node) {
59
60
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/directives/definitions/details.ts"],"sourcesContent":["import type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { resolveDirectiveTheme } from '../themes.js'\n\nconst DEFAULT_DETAILS_TITLE = 'Details'\n\nfunction getTitle(node: ContainerDirective): string {\n const title = node.attributes?.title\n\n return typeof title === 'string' && title.trim() ? title.trim() : DEFAULT_DETAILS_TITLE\n}\n\nexport const detailsDirective: LayoutDirectiveDefinition = {\n name: 'details',\n allowedAttributes: ['open', 'theme', 'title'],\n applyHast(node, config, { mergeClassNames }) {\n const title = typeof node.properties.dataTitle === 'string' ? node.properties.dataTitle : DEFAULT_DETAILS_TITLE\n const theme = resolveDirectiveTheme(\n 'details',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n const children = node.children\n\n node.properties.dataTheme = theme.name\n node.properties.className = mergeClassNames(\n 'not-prose',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n )\n\n node.children = [\n {\n type: 'element',\n children: [{ type: 'text', value: title }],\n properties: {\n className: ['cursor-pointer text-sm font-semibold tracking-wide'],\n },\n tagName: 'summary',\n },\n {\n type: 'element',\n children,\n properties: {\n className: ['mt-3 space-y-3 [&>:first-child]:mt-0 [&>:last-child]:mb-0'],\n dataDirectiveBody: 'details',\n },\n tagName: 'div',\n },\n ]\n },\n defaultAttributes: {\n title: DEFAULT_DETAILS_TITLE,\n },\n description: 'Native disclosure block for optional details.',\n editor: {\n detail: 'Static directive',\n label: 'Details',\n snippet: ':::details {title=\"${Details}\"}\\n${Content}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDirective: 'details',\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default',\n dataTitle: getTitle(node),\n open: node.attributes?.open === 'true',\n }\n },\n kind: 'details',\n openMarker: ':::details',\n public: true,\n supportsAttributes: true,\n tagName: 'details',\n themeAttributes: {\n theme: 'details',\n },\n}\n"],"names":["resolveDirectiveTheme","DEFAULT_DETAILS_TITLE","getTitle","node","title","attributes","trim","detailsDirective","name","allowedAttributes","applyHast","config","mergeClassNames","properties","dataTitle","theme","dataTheme","undefined","themes","children","className","hookClassName","modifierClassName","classes","type","value","tagName","dataDirectiveBody","defaultAttributes","description","editor","detail","label","snippet","getMdastRenderProperties","dataDirective","open","kind","openMarker","public","supportsAttributes","themeAttributes"],"mappings":"AAIA,SAASA,qBAAqB,QAAQ,eAAc;AAEpD,MAAMC,wBAAwB;AAE9B,SAASC,SAASC,IAAwB;IACxC,MAAMC,QAAQD,KAAKE,UAAU,EAAED;IAE/B,OAAO,OAAOA,UAAU,YAAYA,MAAME,IAAI,KAAKF,MAAME,IAAI,KAAKL;AACpE;AAEA,OAAO,MAAMM,mBAA8C;IACzDC,MAAM;IACNC,mBAAmB;QAAC;QAAQ;QAAS;KAAQ;IAC7CC,WAAUP,IAAI,EAAEQ,MAAM,EAAE,EAAEC,eAAe,EAAE;QACzC,MAAMR,QAAQ,OAAOD,KAAKU,UAAU,CAACC,SAAS,KAAK,WAAWX,KAAKU,UAAU,CAACC,SAAS,GAAGb;QAC1F,MAAMc,QAAQf,sBACZ,WACA,OAAOG,KAAKU,UAAU,CAACG,SAAS,KAAK,WAAWb,KAAKU,UAAU,CAACG,SAAS,GAAGC,WAC5EN,OAAOO,MAAM;QAEf,MAAMC,WAAWhB,KAAKgB,QAAQ;QAE9BhB,KAAKU,UAAU,CAACG,SAAS,GAAGD,MAAMP,IAAI;QACtCL,KAAKU,UAAU,CAACO,SAAS,GAAGR,gBAC1B,aACAG,MAAMM,aAAa,EACnBN,MAAMO,iBAAiB,EACvBP,MAAMQ,OAAO;QAGfpB,KAAKgB,QAAQ,GAAG;YACd;gBACEK,MAAM;gBACNL,UAAU;oBAAC;wBAAEK,MAAM;wBAAQC,OAAOrB;oBAAM;iBAAE;gBAC1CS,YAAY;oBACVO,WAAW;wBAAC;qBAAqD;gBACnE;gBACAM,SAAS;YACX;YACA;gBACEF,MAAM;gBACNL;gBACAN,YAAY;oBACVO,WAAW;wBAAC;qBAA4D;oBACxEO,mBAAmB;gBACrB;gBACAD,SAAS;YACX;SACD;IACH;IACAE,mBAAmB;QACjBxB,OAAOH;IACT;IACA4B,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRC,OAAO;QACPC,SAAS;IACX;IACAC,0BAAyB/B,IAAI;QAC3B,OAAO;YACLgC,eAAe;YACfnB,WAAW,OAAOb,KAAKE,UAAU,EAAEU,UAAU,WAAWZ,KAAKE,UAAU,CAACU,KAAK,GAAG;YAChFD,WAAWZ,SAASC;YACpBiC,MAAMjC,KAAKE,UAAU,EAAE+B,SAAS;QAClC;IACF;IACAC,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBd,SAAS;IACTe,iBAAiB;QACf1B,OAAO;IACT;AACF,EAAC"}
1
+ {"version":3,"sources":["../../../src/directives/definitions/details.ts"],"sourcesContent":["import type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { getDirectiveLabelOrAttribute } from '../labels.js'\nimport { resolveDirectiveTheme } from '../themes.js'\n\nconst DEFAULT_DETAILS_TITLE = 'Details'\n\nfunction getTitle(node: ContainerDirective): string {\n const title = getDirectiveLabelOrAttribute(node, 'title')\n\n return title ?? DEFAULT_DETAILS_TITLE\n}\n\nexport const detailsDirective: LayoutDirectiveDefinition = {\n name: 'details',\n allowedAttributes: ['open', 'theme', 'title'],\n applyHast(node, config, { mergeClassNames }) {\n const title = typeof node.properties.dataTitle === 'string' ? node.properties.dataTitle : DEFAULT_DETAILS_TITLE\n const theme = resolveDirectiveTheme(\n 'details',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n const children = node.children\n\n node.properties.dataTheme = theme.name\n node.properties.className = mergeClassNames(\n 'not-prose',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n )\n\n node.children = [\n {\n type: 'element',\n children: [{ type: 'text', value: title }],\n properties: {\n className: ['cursor-pointer text-sm font-semibold tracking-wide'],\n },\n tagName: 'summary',\n },\n {\n type: 'element',\n children,\n properties: {\n className: ['mt-3 space-y-3 [&>:first-child]:mt-0 [&>:last-child]:mb-0'],\n dataDirectiveBody: 'details',\n },\n tagName: 'div',\n },\n ]\n },\n defaultAttributes: {\n title: DEFAULT_DETAILS_TITLE,\n },\n description: 'Native disclosure block for optional details.',\n editor: {\n detail: 'Static directive',\n label: 'Details',\n snippet: ':::details[${Details}]\\n${Content}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDirective: 'details',\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default',\n dataTitle: getTitle(node),\n open: node.attributes?.open === 'true',\n }\n },\n kind: 'details',\n openMarker: ':::details',\n public: true,\n supportsAttributes: true,\n tagName: 'details',\n themeAttributes: {\n theme: 'details',\n },\n}\n"],"names":["getDirectiveLabelOrAttribute","resolveDirectiveTheme","DEFAULT_DETAILS_TITLE","getTitle","node","title","detailsDirective","name","allowedAttributes","applyHast","config","mergeClassNames","properties","dataTitle","theme","dataTheme","undefined","themes","children","className","hookClassName","modifierClassName","classes","type","value","tagName","dataDirectiveBody","defaultAttributes","description","editor","detail","label","snippet","getMdastRenderProperties","dataDirective","attributes","open","kind","openMarker","public","supportsAttributes","themeAttributes"],"mappings":"AAIA,SAASA,4BAA4B,QAAQ,eAAc;AAC3D,SAASC,qBAAqB,QAAQ,eAAc;AAEpD,MAAMC,wBAAwB;AAE9B,SAASC,SAASC,IAAwB;IACxC,MAAMC,QAAQL,6BAA6BI,MAAM;IAEjD,OAAOC,SAASH;AAClB;AAEA,OAAO,MAAMI,mBAA8C;IACzDC,MAAM;IACNC,mBAAmB;QAAC;QAAQ;QAAS;KAAQ;IAC7CC,WAAUL,IAAI,EAAEM,MAAM,EAAE,EAAEC,eAAe,EAAE;QACzC,MAAMN,QAAQ,OAAOD,KAAKQ,UAAU,CAACC,SAAS,KAAK,WAAWT,KAAKQ,UAAU,CAACC,SAAS,GAAGX;QAC1F,MAAMY,QAAQb,sBACZ,WACA,OAAOG,KAAKQ,UAAU,CAACG,SAAS,KAAK,WAAWX,KAAKQ,UAAU,CAACG,SAAS,GAAGC,WAC5EN,OAAOO,MAAM;QAEf,MAAMC,WAAWd,KAAKc,QAAQ;QAE9Bd,KAAKQ,UAAU,CAACG,SAAS,GAAGD,MAAMP,IAAI;QACtCH,KAAKQ,UAAU,CAACO,SAAS,GAAGR,gBAC1B,aACAG,MAAMM,aAAa,EACnBN,MAAMO,iBAAiB,EACvBP,MAAMQ,OAAO;QAGflB,KAAKc,QAAQ,GAAG;YACd;gBACEK,MAAM;gBACNL,UAAU;oBAAC;wBAAEK,MAAM;wBAAQC,OAAOnB;oBAAM;iBAAE;gBAC1CO,YAAY;oBACVO,WAAW;wBAAC;qBAAqD;gBACnE;gBACAM,SAAS;YACX;YACA;gBACEF,MAAM;gBACNL;gBACAN,YAAY;oBACVO,WAAW;wBAAC;qBAA4D;oBACxEO,mBAAmB;gBACrB;gBACAD,SAAS;YACX;SACD;IACH;IACAE,mBAAmB;QACjBtB,OAAOH;IACT;IACA0B,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRC,OAAO;QACPC,SAAS;IACX;IACAC,0BAAyB7B,IAAI;QAC3B,OAAO;YACL8B,eAAe;YACfnB,WAAW,OAAOX,KAAK+B,UAAU,EAAErB,UAAU,WAAWV,KAAK+B,UAAU,CAACrB,KAAK,GAAG;YAChFD,WAAWV,SAASC;YACpBgC,MAAMhC,KAAK+B,UAAU,EAAEC,SAAS;QAClC;IACF;IACAC,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBf,SAAS;IACTgB,iBAAiB;QACf3B,OAAO;IACT;AACF,EAAC"}
@@ -3,6 +3,7 @@ import type { LayoutDirectiveDefinition } from '../types.js';
3
3
  export declare function getTabLabel(node: ContainerDirective, index: number): string;
4
4
  type TabAttributes = null | Record<string, boolean | null | string | undefined> | undefined;
5
5
  export declare function getTabValueFromAttributes(attributes: TabAttributes, index: number): string;
6
+ export declare function getTabValue(node: ContainerDirective, index: number): string;
6
7
  export declare function isTabDisabled(attributes: TabAttributes): boolean;
7
8
  export declare const tabDirective: LayoutDirectiveDefinition;
8
9
  export {};
@@ -1,10 +1,11 @@
1
+ import { getDirectiveLabel, getDirectiveLabelOrAttribute } from '../labels.js';
1
2
  import { resolveDirectiveTheme, slugThemeName } from '../themes.js';
2
3
  function getAttribute(node, name) {
3
4
  const value = node.attributes?.[name];
4
5
  return typeof value === 'string' && value.trim() ? value.trim() : undefined;
5
6
  }
6
7
  export function getTabLabel(node, index) {
7
- return getAttribute(node, 'label') ?? getAttribute(node, 'value') ?? `Tab ${index + 1}`;
8
+ return getDirectiveLabelOrAttribute(node, 'label') ?? getAttribute(node, 'value') ?? `Tab ${index + 1}`;
8
9
  }
9
10
  export function getTabValueFromAttributes(attributes, index) {
10
11
  const value = attributes?.value;
@@ -12,6 +13,12 @@ export function getTabValueFromAttributes(attributes, index) {
12
13
  const raw = typeof value === 'string' && value.trim() ? value.trim() : typeof label === 'string' && label.trim() ? label.trim() : `tab-${index + 1}`;
13
14
  return slugThemeName(raw);
14
15
  }
16
+ export function getTabValue(node, index) {
17
+ const value = node.attributes?.value;
18
+ const label = getDirectiveLabel(node) ?? getAttribute(node, 'label');
19
+ const raw = typeof value === 'string' && value.trim() ? value.trim() : typeof label === 'string' && label.trim() ? label.trim() : `tab-${index + 1}`;
20
+ return slugThemeName(raw);
21
+ }
15
22
  export function isTabDisabled(attributes) {
16
23
  const disabled = attributes?.disabled;
17
24
  if (disabled === true) return true;
@@ -35,7 +42,7 @@ export const tabDirective = {
35
42
  editor: {
36
43
  detail: 'Tabs directive',
37
44
  label: 'Tab',
38
- snippet: ':::tab {label="${Label}"}\n${Content}\n:::\n${}'
45
+ snippet: ':::tab[${Label}]\n${Content}\n:::\n${}'
39
46
  },
40
47
  getMdastRenderProperties (node) {
41
48
  return {
@@ -43,7 +50,7 @@ export const tabDirective = {
43
50
  dataDisabled: isTabDisabled(node.attributes) ? 'true' : undefined,
44
51
  dataLabel: getTabLabel(node, 0),
45
52
  dataTheme: getAttribute(node, 'theme'),
46
- dataValue: getTabValueFromAttributes(node.attributes, 0)
53
+ dataValue: getTabValue(node, 0)
47
54
  };
48
55
  },
49
56
  kind: 'tab',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/directives/definitions/tab.ts"],"sourcesContent":["import type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { resolveDirectiveTheme, slugThemeName } from '../themes.js'\n\nfunction getAttribute(node: ContainerDirective, name: string): string | undefined {\n const value = node.attributes?.[name]\n\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nexport function getTabLabel(node: ContainerDirective, index: number): string {\n return getAttribute(node, 'label') ?? getAttribute(node, 'value') ?? `Tab ${index + 1}`\n}\n\ntype TabAttributes = null | Record<string, boolean | null | string | undefined> | undefined\n\nexport function getTabValueFromAttributes(attributes: TabAttributes, index: number): string {\n const value = attributes?.value\n const label = attributes?.label\n const raw =\n typeof value === 'string' && value.trim()\n ? value.trim()\n : typeof label === 'string' && label.trim()\n ? label.trim()\n : `tab-${index + 1}`\n\n return slugThemeName(raw)\n}\n\nexport function isTabDisabled(attributes: TabAttributes): boolean {\n const disabled = attributes?.disabled\n\n if (disabled === true) return true\n if (typeof disabled !== 'string') return false\n\n return disabled !== 'false'\n}\n\nexport const tabDirective: LayoutDirectiveDefinition = {\n name: 'tab',\n allowedAttributes: ['disabled', 'label', 'theme', 'value'],\n applyHast(node, config, { mergeClassNames }) {\n const theme = resolveDirectiveTheme(\n 'tab',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n\n node.properties.dataTheme = theme.name\n node.properties.className = mergeClassNames(\n 'not-prose',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n 'vl-md-tab-panel',\n )\n },\n description: 'Single tab panel. Usually nested inside :::tabs.',\n editor: {\n detail: 'Tabs directive',\n label: 'Tab',\n snippet: ':::tab {label=\"${Label}\"}\\n${Content}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDirective: 'tab',\n dataDisabled: isTabDisabled(node.attributes) ? 'true' : undefined,\n dataLabel: getTabLabel(node, 0),\n dataTheme: getAttribute(node, 'theme'),\n dataValue: getTabValueFromAttributes(node.attributes, 0),\n }\n },\n kind: 'tab',\n openMarker: ':::tab',\n public: true,\n supportsAttributes: true,\n tagName: 'section',\n themeAttributes: {\n theme: 'tab',\n },\n}\n"],"names":["resolveDirectiveTheme","slugThemeName","getAttribute","node","name","value","attributes","trim","undefined","getTabLabel","index","getTabValueFromAttributes","label","raw","isTabDisabled","disabled","tabDirective","allowedAttributes","applyHast","config","mergeClassNames","theme","properties","dataTheme","themes","className","hookClassName","modifierClassName","classes","description","editor","detail","snippet","getMdastRenderProperties","dataDirective","dataDisabled","dataLabel","dataValue","kind","openMarker","public","supportsAttributes","tagName","themeAttributes"],"mappings":"AAIA,SAASA,qBAAqB,EAAEC,aAAa,QAAQ,eAAc;AAEnE,SAASC,aAAaC,IAAwB,EAAEC,IAAY;IAC1D,MAAMC,QAAQF,KAAKG,UAAU,EAAE,CAACF,KAAK;IAErC,OAAO,OAAOC,UAAU,YAAYA,MAAME,IAAI,KAAKF,MAAME,IAAI,KAAKC;AACpE;AAEA,OAAO,SAASC,YAAYN,IAAwB,EAAEO,KAAa;IACjE,OAAOR,aAAaC,MAAM,YAAYD,aAAaC,MAAM,YAAY,CAAC,IAAI,EAAEO,QAAQ,GAAG;AACzF;AAIA,OAAO,SAASC,0BAA0BL,UAAyB,EAAEI,KAAa;IAChF,MAAML,QAAQC,YAAYD;IAC1B,MAAMO,QAAQN,YAAYM;IAC1B,MAAMC,MACJ,OAAOR,UAAU,YAAYA,MAAME,IAAI,KACnCF,MAAME,IAAI,KACV,OAAOK,UAAU,YAAYA,MAAML,IAAI,KACrCK,MAAML,IAAI,KACV,CAAC,IAAI,EAAEG,QAAQ,GAAG;IAE1B,OAAOT,cAAcY;AACvB;AAEA,OAAO,SAASC,cAAcR,UAAyB;IACrD,MAAMS,WAAWT,YAAYS;IAE7B,IAAIA,aAAa,MAAM,OAAO;IAC9B,IAAI,OAAOA,aAAa,UAAU,OAAO;IAEzC,OAAOA,aAAa;AACtB;AAEA,OAAO,MAAMC,eAA0C;IACrDZ,MAAM;IACNa,mBAAmB;QAAC;QAAY;QAAS;QAAS;KAAQ;IAC1DC,WAAUf,IAAI,EAAEgB,MAAM,EAAE,EAAEC,eAAe,EAAE;QACzC,MAAMC,QAAQrB,sBACZ,OACA,OAAOG,KAAKmB,UAAU,CAACC,SAAS,KAAK,WAAWpB,KAAKmB,UAAU,CAACC,SAAS,GAAGf,WAC5EW,OAAOK,MAAM;QAGfrB,KAAKmB,UAAU,CAACC,SAAS,GAAGF,MAAMjB,IAAI;QACtCD,KAAKmB,UAAU,CAACG,SAAS,GAAGL,gBAC1B,aACAC,MAAMK,aAAa,EACnBL,MAAMM,iBAAiB,EACvBN,MAAMO,OAAO,EACb;IAEJ;IACAC,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRnB,OAAO;QACPoB,SAAS;IACX;IACAC,0BAAyB9B,IAAI;QAC3B,OAAO;YACL+B,eAAe;YACfC,cAAcrB,cAAcX,KAAKG,UAAU,IAAI,SAASE;YACxD4B,WAAW3B,YAAYN,MAAM;YAC7BoB,WAAWrB,aAAaC,MAAM;YAC9BkC,WAAW1B,0BAA0BR,KAAKG,UAAU,EAAE;QACxD;IACF;IACAgC,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBC,SAAS;IACTC,iBAAiB;QACftB,OAAO;IACT;AACF,EAAC"}
1
+ {"version":3,"sources":["../../../src/directives/definitions/tab.ts"],"sourcesContent":["import type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { getDirectiveLabel, getDirectiveLabelOrAttribute } from '../labels.js'\nimport { resolveDirectiveTheme, slugThemeName } from '../themes.js'\n\nfunction getAttribute(node: ContainerDirective, name: string): string | undefined {\n const value = node.attributes?.[name]\n\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nexport function getTabLabel(node: ContainerDirective, index: number): string {\n return getDirectiveLabelOrAttribute(node, 'label') ?? getAttribute(node, 'value') ?? `Tab ${index + 1}`\n}\n\ntype TabAttributes = null | Record<string, boolean | null | string | undefined> | undefined\n\nexport function getTabValueFromAttributes(attributes: TabAttributes, index: number): string {\n const value = attributes?.value\n const label = attributes?.label\n const raw =\n typeof value === 'string' && value.trim()\n ? value.trim()\n : typeof label === 'string' && label.trim()\n ? label.trim()\n : `tab-${index + 1}`\n\n return slugThemeName(raw)\n}\n\nexport function getTabValue(node: ContainerDirective, index: number): string {\n const value = node.attributes?.value\n const label = getDirectiveLabel(node) ?? getAttribute(node, 'label')\n const raw =\n typeof value === 'string' && value.trim()\n ? value.trim()\n : typeof label === 'string' && label.trim()\n ? label.trim()\n : `tab-${index + 1}`\n\n return slugThemeName(raw)\n}\n\nexport function isTabDisabled(attributes: TabAttributes): boolean {\n const disabled = attributes?.disabled\n\n if (disabled === true) return true\n if (typeof disabled !== 'string') return false\n\n return disabled !== 'false'\n}\n\nexport const tabDirective: LayoutDirectiveDefinition = {\n name: 'tab',\n allowedAttributes: ['disabled', 'label', 'theme', 'value'],\n applyHast(node, config, { mergeClassNames }) {\n const theme = resolveDirectiveTheme(\n 'tab',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n\n node.properties.dataTheme = theme.name\n node.properties.className = mergeClassNames(\n 'not-prose',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n 'vl-md-tab-panel',\n )\n },\n description: 'Single tab panel. Usually nested inside :::tabs.',\n editor: {\n detail: 'Tabs directive',\n label: 'Tab',\n snippet: ':::tab[${Label}]\\n${Content}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDirective: 'tab',\n dataDisabled: isTabDisabled(node.attributes) ? 'true' : undefined,\n dataLabel: getTabLabel(node, 0),\n dataTheme: getAttribute(node, 'theme'),\n dataValue: getTabValue(node, 0),\n }\n },\n kind: 'tab',\n openMarker: ':::tab',\n public: true,\n supportsAttributes: true,\n tagName: 'section',\n themeAttributes: {\n theme: 'tab',\n },\n}\n"],"names":["getDirectiveLabel","getDirectiveLabelOrAttribute","resolveDirectiveTheme","slugThemeName","getAttribute","node","name","value","attributes","trim","undefined","getTabLabel","index","getTabValueFromAttributes","label","raw","getTabValue","isTabDisabled","disabled","tabDirective","allowedAttributes","applyHast","config","mergeClassNames","theme","properties","dataTheme","themes","className","hookClassName","modifierClassName","classes","description","editor","detail","snippet","getMdastRenderProperties","dataDirective","dataDisabled","dataLabel","dataValue","kind","openMarker","public","supportsAttributes","tagName","themeAttributes"],"mappings":"AAIA,SAASA,iBAAiB,EAAEC,4BAA4B,QAAQ,eAAc;AAC9E,SAASC,qBAAqB,EAAEC,aAAa,QAAQ,eAAc;AAEnE,SAASC,aAAaC,IAAwB,EAAEC,IAAY;IAC1D,MAAMC,QAAQF,KAAKG,UAAU,EAAE,CAACF,KAAK;IAErC,OAAO,OAAOC,UAAU,YAAYA,MAAME,IAAI,KAAKF,MAAME,IAAI,KAAKC;AACpE;AAEA,OAAO,SAASC,YAAYN,IAAwB,EAAEO,KAAa;IACjE,OAAOX,6BAA6BI,MAAM,YAAYD,aAAaC,MAAM,YAAY,CAAC,IAAI,EAAEO,QAAQ,GAAG;AACzG;AAIA,OAAO,SAASC,0BAA0BL,UAAyB,EAAEI,KAAa;IAChF,MAAML,QAAQC,YAAYD;IAC1B,MAAMO,QAAQN,YAAYM;IAC1B,MAAMC,MACJ,OAAOR,UAAU,YAAYA,MAAME,IAAI,KACnCF,MAAME,IAAI,KACV,OAAOK,UAAU,YAAYA,MAAML,IAAI,KACrCK,MAAML,IAAI,KACV,CAAC,IAAI,EAAEG,QAAQ,GAAG;IAE1B,OAAOT,cAAcY;AACvB;AAEA,OAAO,SAASC,YAAYX,IAAwB,EAAEO,KAAa;IACjE,MAAML,QAAQF,KAAKG,UAAU,EAAED;IAC/B,MAAMO,QAAQd,kBAAkBK,SAASD,aAAaC,MAAM;IAC5D,MAAMU,MACJ,OAAOR,UAAU,YAAYA,MAAME,IAAI,KACnCF,MAAME,IAAI,KACV,OAAOK,UAAU,YAAYA,MAAML,IAAI,KACrCK,MAAML,IAAI,KACV,CAAC,IAAI,EAAEG,QAAQ,GAAG;IAE1B,OAAOT,cAAcY;AACvB;AAEA,OAAO,SAASE,cAAcT,UAAyB;IACrD,MAAMU,WAAWV,YAAYU;IAE7B,IAAIA,aAAa,MAAM,OAAO;IAC9B,IAAI,OAAOA,aAAa,UAAU,OAAO;IAEzC,OAAOA,aAAa;AACtB;AAEA,OAAO,MAAMC,eAA0C;IACrDb,MAAM;IACNc,mBAAmB;QAAC;QAAY;QAAS;QAAS;KAAQ;IAC1DC,WAAUhB,IAAI,EAAEiB,MAAM,EAAE,EAAEC,eAAe,EAAE;QACzC,MAAMC,QAAQtB,sBACZ,OACA,OAAOG,KAAKoB,UAAU,CAACC,SAAS,KAAK,WAAWrB,KAAKoB,UAAU,CAACC,SAAS,GAAGhB,WAC5EY,OAAOK,MAAM;QAGftB,KAAKoB,UAAU,CAACC,SAAS,GAAGF,MAAMlB,IAAI;QACtCD,KAAKoB,UAAU,CAACG,SAAS,GAAGL,gBAC1B,aACAC,MAAMK,aAAa,EACnBL,MAAMM,iBAAiB,EACvBN,MAAMO,OAAO,EACb;IAEJ;IACAC,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRpB,OAAO;QACPqB,SAAS;IACX;IACAC,0BAAyB/B,IAAI;QAC3B,OAAO;YACLgC,eAAe;YACfC,cAAcrB,cAAcZ,KAAKG,UAAU,IAAI,SAASE;YACxD6B,WAAW5B,YAAYN,MAAM;YAC7BqB,WAAWtB,aAAaC,MAAM;YAC9BmC,WAAWxB,YAAYX,MAAM;QAC/B;IACF;IACAoC,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBC,SAAS;IACTC,iBAAiB;QACftB,OAAO;IACT;AACF,EAAC"}
@@ -1,6 +1,6 @@
1
1
  import { DIRECTIVE_SURFACE_DIVIDER_CLASS } from '../../styles/directiveSurface.js';
2
2
  import { resolveDirectiveTheme, slugThemeName } from '../themes.js';
3
- import { getTabValueFromAttributes } from './tab.js';
3
+ import { getTabValue } from './tab.js';
4
4
  function isContainerDirective(node) {
5
5
  return Boolean(node && typeof node === 'object' && 'type' in node && node.type === 'containerDirective');
6
6
  }
@@ -157,7 +157,7 @@ export const tabsDirective = {
157
157
  editor: {
158
158
  detail: 'Tabs directive',
159
159
  label: 'Tabs',
160
- snippet: ':::tabs {default="${pnpm}"}\n\n:::tab {label="${pnpm}" value="${pnpm}"}\n```bash\npnpm add ${package-name}\n```\n:::\n\n:::tab {label="${npm}" value="${npm}"}\n```bash\nnpm install ${package-name}\n```\n:::\n\n:::\n${}'
160
+ snippet: ':::tabs{\n default="${pnpm}"\n}\n\n:::tab[${pnpm}]{\n value="${pnpm}"\n}\n```bash\npnpm add ${package-name}\n```\n:::\n\n:::tab[${npm}]{\n value="${npm}"\n}\n```bash\nnpm install ${package-name}\n```\n:::\n\n:::\n${}'
161
161
  },
162
162
  getMdastRenderProperties (node) {
163
163
  return {
@@ -182,7 +182,7 @@ export const tabsDirective = {
182
182
  const values = new Map();
183
183
  if (tabs.length === 0) warnings.push('Directive "tabs" has no child "tab" directives.');
184
184
  tabs.forEach((tab, index)=>{
185
- const value = getTabValueFromAttributes(tab.attributes, index);
185
+ const value = getTabValue(tab, index);
186
186
  values.set(value, (values.get(value) ?? 0) + 1);
187
187
  });
188
188
  for (const [value, count] of values)if (count > 1) warnings.push(`Duplicate tab value "${value}" in "tabs".`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/directives/definitions/tabs.ts"],"sourcesContent":["import type { Element, ElementContent } from 'hast'\nimport type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { DIRECTIVE_SURFACE_DIVIDER_CLASS } from '../../styles/directiveSurface.js'\nimport { resolveDirectiveTheme, slugThemeName } from '../themes.js'\nimport { getTabValueFromAttributes } from './tab.js'\n\ntype TabModel = {\n disabled: boolean\n label: string\n node: Element\n panelId: string\n themeName?: string\n triggerId: string\n value: string\n}\n\nfunction isContainerDirective(node: unknown): node is ContainerDirective {\n return Boolean(\n node &&\n typeof node === 'object' &&\n 'type' in node &&\n (node as { type?: string }).type === 'containerDirective',\n )\n}\n\nfunction isTabElement(node: ElementContent): node is Element {\n return node.type === 'element' && node.properties?.dataVlLayout === 'tab'\n}\n\nfunction getStringProperty(\n properties: Element['properties'] | undefined,\n name: string,\n): string | undefined {\n const value = properties?.[name]\n\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction getBooleanProperty(properties: Element['properties'] | undefined, name: string): boolean {\n const value = properties?.[name]\n\n return value === true || value === 'true'\n}\n\nfunction getTabLabel(node: Element, index: number): string {\n return (\n getStringProperty(node.properties, 'dataLabel') ??\n getStringProperty(node.properties, 'dataValue') ??\n `Tab ${index + 1}`\n )\n}\n\nfunction getRequestedDefault(node: Element): string | undefined {\n return getStringProperty(node.properties, 'dataDefault')\n}\n\nfunction makeUniqueValue(rawValue: string, seen: Map<string, number>): string {\n const base = slugThemeName(rawValue)\n const count = seen.get(base) ?? 0\n seen.set(base, count + 1)\n\n return count === 0 ? base : `${base}-${count}`\n}\n\nfunction collectTabs(node: Element): TabModel[] {\n const seen = new Map<string, number>()\n\n return node.children.filter(isTabElement).map((child, index) => {\n const rawValue = getStringProperty(child.properties, 'dataValue') ?? `tab-${index + 1}`\n const value = makeUniqueValue(rawValue, seen)\n\n return {\n disabled: getBooleanProperty(child.properties, 'dataDisabled'),\n label: getTabLabel(child, index),\n node: child,\n panelId: `tabs-panel-${value}`,\n themeName: getStringProperty(child.properties, 'dataTheme'),\n triggerId: `tabs-trigger-${value}`,\n value,\n }\n })\n}\n\nfunction makeTabTrigger(tab: TabModel, active: boolean): Element {\n const className = [\n 'vl-md-tabs-trigger',\n active ? 'vl-md-tabs-trigger--active' : undefined,\n 'rounded-lg px-3 py-2 text-sm font-medium text-foreground/70 transition-colors hover:text-foreground aria-selected:bg-white/10 aria-selected:text-foreground',\n ].filter((value): value is string => Boolean(value))\n\n return {\n type: 'element',\n children: [{ type: 'text', value: tab.label }],\n properties: {\n id: tab.triggerId,\n type: 'button',\n ariaControls: tab.panelId,\n ariaSelected: active ? 'true' : 'false',\n className,\n dataTabTrigger: '',\n dataTabValue: tab.value,\n disabled: tab.disabled || undefined,\n role: 'tab',\n tabIndex: active ? 0 : -1,\n },\n tagName: 'button',\n }\n}\n\nfunction makeTabPanel(\n tab: TabModel,\n active: boolean,\n config: Parameters<NonNullable<LayoutDirectiveDefinition['applyHast']>>[1],\n mergeClassNames: Parameters<NonNullable<LayoutDirectiveDefinition['applyHast']>>[2]['mergeClassNames'],\n fallbackThemeName?: string,\n): Element {\n const theme = resolveDirectiveTheme('tab', tab.themeName ?? fallbackThemeName, config.themes)\n\n return {\n type: 'element',\n children: tab.node.children,\n properties: {\n id: tab.panelId,\n ariaLabelledby: tab.triggerId,\n className: mergeClassNames(\n 'vl-md-tabs-panel',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n '[&>:first-child]:mt-0 [&>:last-child]:mb-0',\n ),\n dataTabPanel: '',\n dataTabValue: tab.value,\n dataTheme: theme.name,\n hidden: active ? undefined : true,\n role: 'tabpanel',\n tabIndex: 0,\n },\n tagName: 'div',\n }\n}\n\nfunction makeTabList(tabs: TabModel[], activeValue: string): Element {\n return {\n type: 'element',\n children: tabs.map((tab) => makeTabTrigger(tab, tab.value === activeValue)),\n properties: {\n className: [`vl-md-tabs-list flex flex-wrap gap-1 border-b ${DIRECTIVE_SURFACE_DIVIDER_CLASS} pb-2`],\n dataTabsList: '',\n role: 'tablist',\n },\n tagName: 'div',\n }\n}\n\nfunction findActiveTab(tabs: TabModel[], requestedDefault?: string): TabModel | undefined {\n const requested = requestedDefault ? slugThemeName(requestedDefault) : undefined\n const requestedMatch = requested\n ? tabs.find((tab) => tab.value === requested && !tab.disabled) ??\n tabs.find((tab) => tab.value === requested)\n : undefined\n\n return requestedMatch ?? tabs.find((tab) => !tab.disabled) ?? tabs[0]\n}\n\nfunction getDirectTabDirectives(node: ContainerDirective): ContainerDirective[] {\n return node.children.filter(\n (child): child is ContainerDirective => isContainerDirective(child) && child.name === 'tab',\n )\n}\n\nexport const tabsDirective: LayoutDirectiveDefinition = {\n name: 'tabs',\n allowedAttributes: ['default', 'tabTheme', 'theme'],\n applyHast(node, config, { mergeClassNames }) {\n const tabs = collectTabs(node)\n const activeTab = findActiveTab(tabs, getRequestedDefault(node))\n const theme = resolveDirectiveTheme(\n 'tabs',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n const tabTheme =\n typeof node.properties.dataTabTheme === 'string' ? node.properties.dataTabTheme : undefined\n\n node.properties.dataTheme = theme.name\n node.properties.dataDefault = activeTab?.value\n node.properties.className = mergeClassNames(\n 'not-prose',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n )\n\n if (!activeTab) {\n node.children = [\n {\n type: 'element',\n children: [{ type: 'text', value: 'No tabs configured.' }],\n properties: {\n className: ['text-sm text-muted-foreground'],\n },\n tagName: 'p',\n },\n ]\n return\n }\n\n node.children = [\n makeTabList(tabs, activeTab.value),\n ...tabs.map((tab) =>\n makeTabPanel(tab, tab.value === activeTab.value, config, mergeClassNames, tabTheme),\n ),\n ]\n },\n description: 'Accessible tabbed content block with server-rendered panels.',\n editor: {\n detail: 'Tabs directive',\n label: 'Tabs',\n snippet:\n ':::tabs {default=\"${pnpm}\"}\\n\\n:::tab {label=\"${pnpm}\" value=\"${pnpm}\"}\\n```bash\\npnpm add ${package-name}\\n```\\n:::\\n\\n:::tab {label=\"${npm}\" value=\"${npm}\"}\\n```bash\\nnpm install ${package-name}\\n```\\n:::\\n\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDefault:\n typeof node.attributes?.default === 'string' ? node.attributes.default : undefined,\n dataDirective: 'tabs',\n dataTabTheme:\n typeof node.attributes?.tabTheme === 'string' ? node.attributes.tabTheme : undefined,\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default',\n }\n },\n kind: 'tabs',\n openMarker: ':::tabs',\n public: true,\n supportsAttributes: true,\n tagName: 'section',\n themeAttributes: {\n tabTheme: 'tab',\n theme: 'tabs',\n },\n validateMdast(node) {\n const warnings: string[] = []\n const tabs = getDirectTabDirectives(node)\n const values = new Map<string, number>()\n\n if (tabs.length === 0) warnings.push('Directive \"tabs\" has no child \"tab\" directives.')\n\n tabs.forEach((tab, index) => {\n const value = getTabValueFromAttributes(tab.attributes, index)\n values.set(value, (values.get(value) ?? 0) + 1)\n })\n\n for (const [value, count] of values)\n if (count > 1) warnings.push(`Duplicate tab value \"${value}\" in \"tabs\".`)\n\n if (typeof node.attributes?.default === 'string') {\n const requested = slugThemeName(node.attributes.default)\n if (!values.has(requested))\n warnings.push(`Invalid tabs default \"${node.attributes.default}\". Falling back to the first tab.`)\n }\n\n return warnings\n },\n}\n"],"names":["DIRECTIVE_SURFACE_DIVIDER_CLASS","resolveDirectiveTheme","slugThemeName","getTabValueFromAttributes","isContainerDirective","node","Boolean","type","isTabElement","properties","dataVlLayout","getStringProperty","name","value","trim","undefined","getBooleanProperty","getTabLabel","index","getRequestedDefault","makeUniqueValue","rawValue","seen","base","count","get","set","collectTabs","Map","children","filter","map","child","disabled","label","panelId","themeName","triggerId","makeTabTrigger","tab","active","className","id","ariaControls","ariaSelected","dataTabTrigger","dataTabValue","role","tabIndex","tagName","makeTabPanel","config","mergeClassNames","fallbackThemeName","theme","themes","ariaLabelledby","hookClassName","modifierClassName","classes","dataTabPanel","dataTheme","hidden","makeTabList","tabs","activeValue","dataTabsList","findActiveTab","requestedDefault","requested","requestedMatch","find","getDirectTabDirectives","tabsDirective","allowedAttributes","applyHast","activeTab","tabTheme","dataTabTheme","dataDefault","description","editor","detail","snippet","getMdastRenderProperties","attributes","default","dataDirective","kind","openMarker","public","supportsAttributes","themeAttributes","validateMdast","warnings","values","length","push","forEach","has"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/directives/definitions/tabs.ts"],"sourcesContent":["import type { Element, ElementContent } from 'hast'\nimport type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { DIRECTIVE_SURFACE_DIVIDER_CLASS } from '../../styles/directiveSurface.js'\nimport { resolveDirectiveTheme, slugThemeName } from '../themes.js'\nimport { getTabValue } from './tab.js'\n\ntype TabModel = {\n disabled: boolean\n label: string\n node: Element\n panelId: string\n themeName?: string\n triggerId: string\n value: string\n}\n\nfunction isContainerDirective(node: unknown): node is ContainerDirective {\n return Boolean(\n node &&\n typeof node === 'object' &&\n 'type' in node &&\n (node as { type?: string }).type === 'containerDirective',\n )\n}\n\nfunction isTabElement(node: ElementContent): node is Element {\n return node.type === 'element' && node.properties?.dataVlLayout === 'tab'\n}\n\nfunction getStringProperty(\n properties: Element['properties'] | undefined,\n name: string,\n): string | undefined {\n const value = properties?.[name]\n\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction getBooleanProperty(properties: Element['properties'] | undefined, name: string): boolean {\n const value = properties?.[name]\n\n return value === true || value === 'true'\n}\n\nfunction getTabLabel(node: Element, index: number): string {\n return (\n getStringProperty(node.properties, 'dataLabel') ??\n getStringProperty(node.properties, 'dataValue') ??\n `Tab ${index + 1}`\n )\n}\n\nfunction getRequestedDefault(node: Element): string | undefined {\n return getStringProperty(node.properties, 'dataDefault')\n}\n\nfunction makeUniqueValue(rawValue: string, seen: Map<string, number>): string {\n const base = slugThemeName(rawValue)\n const count = seen.get(base) ?? 0\n seen.set(base, count + 1)\n\n return count === 0 ? base : `${base}-${count}`\n}\n\nfunction collectTabs(node: Element): TabModel[] {\n const seen = new Map<string, number>()\n\n return node.children.filter(isTabElement).map((child, index) => {\n const rawValue = getStringProperty(child.properties, 'dataValue') ?? `tab-${index + 1}`\n const value = makeUniqueValue(rawValue, seen)\n\n return {\n disabled: getBooleanProperty(child.properties, 'dataDisabled'),\n label: getTabLabel(child, index),\n node: child,\n panelId: `tabs-panel-${value}`,\n themeName: getStringProperty(child.properties, 'dataTheme'),\n triggerId: `tabs-trigger-${value}`,\n value,\n }\n })\n}\n\nfunction makeTabTrigger(tab: TabModel, active: boolean): Element {\n const className = [\n 'vl-md-tabs-trigger',\n active ? 'vl-md-tabs-trigger--active' : undefined,\n 'rounded-lg px-3 py-2 text-sm font-medium text-foreground/70 transition-colors hover:text-foreground aria-selected:bg-white/10 aria-selected:text-foreground',\n ].filter((value): value is string => Boolean(value))\n\n return {\n type: 'element',\n children: [{ type: 'text', value: tab.label }],\n properties: {\n id: tab.triggerId,\n type: 'button',\n ariaControls: tab.panelId,\n ariaSelected: active ? 'true' : 'false',\n className,\n dataTabTrigger: '',\n dataTabValue: tab.value,\n disabled: tab.disabled || undefined,\n role: 'tab',\n tabIndex: active ? 0 : -1,\n },\n tagName: 'button',\n }\n}\n\nfunction makeTabPanel(\n tab: TabModel,\n active: boolean,\n config: Parameters<NonNullable<LayoutDirectiveDefinition['applyHast']>>[1],\n mergeClassNames: Parameters<NonNullable<LayoutDirectiveDefinition['applyHast']>>[2]['mergeClassNames'],\n fallbackThemeName?: string,\n): Element {\n const theme = resolveDirectiveTheme('tab', tab.themeName ?? fallbackThemeName, config.themes)\n\n return {\n type: 'element',\n children: tab.node.children,\n properties: {\n id: tab.panelId,\n ariaLabelledby: tab.triggerId,\n className: mergeClassNames(\n 'vl-md-tabs-panel',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n '[&>:first-child]:mt-0 [&>:last-child]:mb-0',\n ),\n dataTabPanel: '',\n dataTabValue: tab.value,\n dataTheme: theme.name,\n hidden: active ? undefined : true,\n role: 'tabpanel',\n tabIndex: 0,\n },\n tagName: 'div',\n }\n}\n\nfunction makeTabList(tabs: TabModel[], activeValue: string): Element {\n return {\n type: 'element',\n children: tabs.map((tab) => makeTabTrigger(tab, tab.value === activeValue)),\n properties: {\n className: [`vl-md-tabs-list flex flex-wrap gap-1 border-b ${DIRECTIVE_SURFACE_DIVIDER_CLASS} pb-2`],\n dataTabsList: '',\n role: 'tablist',\n },\n tagName: 'div',\n }\n}\n\nfunction findActiveTab(tabs: TabModel[], requestedDefault?: string): TabModel | undefined {\n const requested = requestedDefault ? slugThemeName(requestedDefault) : undefined\n const requestedMatch = requested\n ? tabs.find((tab) => tab.value === requested && !tab.disabled) ??\n tabs.find((tab) => tab.value === requested)\n : undefined\n\n return requestedMatch ?? tabs.find((tab) => !tab.disabled) ?? tabs[0]\n}\n\nfunction getDirectTabDirectives(node: ContainerDirective): ContainerDirective[] {\n return node.children.filter(\n (child): child is ContainerDirective => isContainerDirective(child) && child.name === 'tab',\n )\n}\n\nexport const tabsDirective: LayoutDirectiveDefinition = {\n name: 'tabs',\n allowedAttributes: ['default', 'tabTheme', 'theme'],\n applyHast(node, config, { mergeClassNames }) {\n const tabs = collectTabs(node)\n const activeTab = findActiveTab(tabs, getRequestedDefault(node))\n const theme = resolveDirectiveTheme(\n 'tabs',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n const tabTheme =\n typeof node.properties.dataTabTheme === 'string' ? node.properties.dataTabTheme : undefined\n\n node.properties.dataTheme = theme.name\n node.properties.dataDefault = activeTab?.value\n node.properties.className = mergeClassNames(\n 'not-prose',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n )\n\n if (!activeTab) {\n node.children = [\n {\n type: 'element',\n children: [{ type: 'text', value: 'No tabs configured.' }],\n properties: {\n className: ['text-sm text-muted-foreground'],\n },\n tagName: 'p',\n },\n ]\n return\n }\n\n node.children = [\n makeTabList(tabs, activeTab.value),\n ...tabs.map((tab) =>\n makeTabPanel(tab, tab.value === activeTab.value, config, mergeClassNames, tabTheme),\n ),\n ]\n },\n description: 'Accessible tabbed content block with server-rendered panels.',\n editor: {\n detail: 'Tabs directive',\n label: 'Tabs',\n snippet:\n ':::tabs{\\n default=\"${pnpm}\"\\n}\\n\\n:::tab[${pnpm}]{\\n value=\"${pnpm}\"\\n}\\n```bash\\npnpm add ${package-name}\\n```\\n:::\\n\\n:::tab[${npm}]{\\n value=\"${npm}\"\\n}\\n```bash\\nnpm install ${package-name}\\n```\\n:::\\n\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDefault:\n typeof node.attributes?.default === 'string' ? node.attributes.default : undefined,\n dataDirective: 'tabs',\n dataTabTheme:\n typeof node.attributes?.tabTheme === 'string' ? node.attributes.tabTheme : undefined,\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default',\n }\n },\n kind: 'tabs',\n openMarker: ':::tabs',\n public: true,\n supportsAttributes: true,\n tagName: 'section',\n themeAttributes: {\n tabTheme: 'tab',\n theme: 'tabs',\n },\n validateMdast(node) {\n const warnings: string[] = []\n const tabs = getDirectTabDirectives(node)\n const values = new Map<string, number>()\n\n if (tabs.length === 0) warnings.push('Directive \"tabs\" has no child \"tab\" directives.')\n\n tabs.forEach((tab, index) => {\n const value = getTabValue(tab, index)\n values.set(value, (values.get(value) ?? 0) + 1)\n })\n\n for (const [value, count] of values)\n if (count > 1) warnings.push(`Duplicate tab value \"${value}\" in \"tabs\".`)\n\n if (typeof node.attributes?.default === 'string') {\n const requested = slugThemeName(node.attributes.default)\n if (!values.has(requested))\n warnings.push(`Invalid tabs default \"${node.attributes.default}\". Falling back to the first tab.`)\n }\n\n return warnings\n },\n}\n"],"names":["DIRECTIVE_SURFACE_DIVIDER_CLASS","resolveDirectiveTheme","slugThemeName","getTabValue","isContainerDirective","node","Boolean","type","isTabElement","properties","dataVlLayout","getStringProperty","name","value","trim","undefined","getBooleanProperty","getTabLabel","index","getRequestedDefault","makeUniqueValue","rawValue","seen","base","count","get","set","collectTabs","Map","children","filter","map","child","disabled","label","panelId","themeName","triggerId","makeTabTrigger","tab","active","className","id","ariaControls","ariaSelected","dataTabTrigger","dataTabValue","role","tabIndex","tagName","makeTabPanel","config","mergeClassNames","fallbackThemeName","theme","themes","ariaLabelledby","hookClassName","modifierClassName","classes","dataTabPanel","dataTheme","hidden","makeTabList","tabs","activeValue","dataTabsList","findActiveTab","requestedDefault","requested","requestedMatch","find","getDirectTabDirectives","tabsDirective","allowedAttributes","applyHast","activeTab","tabTheme","dataTabTheme","dataDefault","description","editor","detail","snippet","getMdastRenderProperties","attributes","default","dataDirective","kind","openMarker","public","supportsAttributes","themeAttributes","validateMdast","warnings","values","length","push","forEach","has"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { getDirectiveLabelOrAttribute } from '../labels.js';
1
2
  import { resolveDirectiveTheme } from '../themes.js';
2
3
  export const DEFAULT_TOC_DEPTH = 3;
3
4
  export const DEFAULT_TOC_TITLE = 'On this page';
@@ -7,8 +8,8 @@ export function resolveTocDepth(node) {
7
8
  return Number.isInteger(parsed) && parsed >= 1 && parsed <= 6 ? parsed : DEFAULT_TOC_DEPTH;
8
9
  }
9
10
  export function resolveTocTitle(node) {
10
- const title = node.attributes?.title;
11
- return typeof title === 'string' && title.trim() ? title.trim() : DEFAULT_TOC_TITLE;
11
+ const title = getDirectiveLabelOrAttribute(node, 'title');
12
+ return title ?? DEFAULT_TOC_TITLE;
12
13
  }
13
14
  export const tocDirective = {
14
15
  name: 'toc',
@@ -30,7 +31,7 @@ export const tocDirective = {
30
31
  editor: {
31
32
  detail: 'Docs directive',
32
33
  label: 'Table of contents',
33
- snippet: ':::toc {title="${On this page}" depth="${3}"}\n:::\n${}'
34
+ snippet: ':::toc[${On this page}]{\n depth="${3}"\n}\n:::\n${}'
34
35
  },
35
36
  getMdastRenderProperties (node) {
36
37
  const title = resolveTocTitle(node);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/directives/definitions/toc.ts"],"sourcesContent":["import type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { resolveDirectiveTheme } from '../themes.js'\n\nexport const DEFAULT_TOC_DEPTH = 3\nexport const DEFAULT_TOC_TITLE = 'On this page'\n\nexport function resolveTocDepth(node: ContainerDirective): number {\n const value = node.attributes?.depth\n const parsed = typeof value === 'string' ? Number.parseInt(value, 10) : DEFAULT_TOC_DEPTH\n\n return Number.isInteger(parsed) && parsed >= 1 && parsed <= 6 ? parsed : DEFAULT_TOC_DEPTH\n}\n\nexport function resolveTocTitle(node: ContainerDirective): string {\n const title = node.attributes?.title\n\n return typeof title === 'string' && title.trim() ? title.trim() : DEFAULT_TOC_TITLE\n}\n\nexport const tocDirective: LayoutDirectiveDefinition = {\n name: 'toc',\n allowedAttributes: ['depth', 'theme', 'title'],\n applyHast(node, config, { mergeClassNames }) {\n const theme = resolveDirectiveTheme(\n 'toc',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n\n node.properties.dataTheme = theme.name\n node.properties.className = mergeClassNames(\n 'not-prose',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n )\n },\n defaultAttributes: {\n depth: String(DEFAULT_TOC_DEPTH),\n title: DEFAULT_TOC_TITLE,\n },\n description: 'Table of contents generated from document headings.',\n editor: {\n detail: 'Docs directive',\n label: 'Table of contents',\n snippet: ':::toc {title=\"${On this page}\" depth=\"${3}\"}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n const title = resolveTocTitle(node)\n\n return {\n ariaLabel: title,\n dataDirective: 'toc',\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default',\n dataTitle: title,\n }\n },\n kind: 'toc',\n openMarker: ':::toc',\n public: true,\n supportsAttributes: true,\n tagName: 'nav',\n themeAttributes: {\n theme: 'toc',\n },\n validateAttributes({ attributes }) {\n const warnings: string[] = []\n\n if (\n typeof attributes.depth === 'string' &&\n (!Number.isInteger(Number.parseInt(attributes.depth, 10)) ||\n Number.parseInt(attributes.depth, 10) < 1 ||\n Number.parseInt(attributes.depth, 10) > 6)\n )\n warnings.push(`Invalid toc depth \"${attributes.depth}\". Falling back to \"${DEFAULT_TOC_DEPTH}\".`)\n\n return warnings\n },\n}\n"],"names":["resolveDirectiveTheme","DEFAULT_TOC_DEPTH","DEFAULT_TOC_TITLE","resolveTocDepth","node","value","attributes","depth","parsed","Number","parseInt","isInteger","resolveTocTitle","title","trim","tocDirective","name","allowedAttributes","applyHast","config","mergeClassNames","theme","properties","dataTheme","undefined","themes","className","hookClassName","modifierClassName","classes","defaultAttributes","String","description","editor","detail","label","snippet","getMdastRenderProperties","ariaLabel","dataDirective","dataTitle","kind","openMarker","public","supportsAttributes","tagName","themeAttributes","validateAttributes","warnings","push"],"mappings":"AAIA,SAASA,qBAAqB,QAAQ,eAAc;AAEpD,OAAO,MAAMC,oBAAoB,EAAC;AAClC,OAAO,MAAMC,oBAAoB,eAAc;AAE/C,OAAO,SAASC,gBAAgBC,IAAwB;IACtD,MAAMC,QAAQD,KAAKE,UAAU,EAAEC;IAC/B,MAAMC,SAAS,OAAOH,UAAU,WAAWI,OAAOC,QAAQ,CAACL,OAAO,MAAMJ;IAExE,OAAOQ,OAAOE,SAAS,CAACH,WAAWA,UAAU,KAAKA,UAAU,IAAIA,SAASP;AAC3E;AAEA,OAAO,SAASW,gBAAgBR,IAAwB;IACtD,MAAMS,QAAQT,KAAKE,UAAU,EAAEO;IAE/B,OAAO,OAAOA,UAAU,YAAYA,MAAMC,IAAI,KAAKD,MAAMC,IAAI,KAAKZ;AACpE;AAEA,OAAO,MAAMa,eAA0C;IACrDC,MAAM;IACNC,mBAAmB;QAAC;QAAS;QAAS;KAAQ;IAC9CC,WAAUd,IAAI,EAAEe,MAAM,EAAE,EAAEC,eAAe,EAAE;QACzC,MAAMC,QAAQrB,sBACZ,OACA,OAAOI,KAAKkB,UAAU,CAACC,SAAS,KAAK,WAAWnB,KAAKkB,UAAU,CAACC,SAAS,GAAGC,WAC5EL,OAAOM,MAAM;QAGfrB,KAAKkB,UAAU,CAACC,SAAS,GAAGF,MAAML,IAAI;QACtCZ,KAAKkB,UAAU,CAACI,SAAS,GAAGN,gBAC1B,aACAC,MAAMM,aAAa,EACnBN,MAAMO,iBAAiB,EACvBP,MAAMQ,OAAO;IAEjB;IACAC,mBAAmB;QACjBvB,OAAOwB,OAAO9B;QACdY,OAAOX;IACT;IACA8B,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRC,OAAO;QACPC,SAAS;IACX;IACAC,0BAAyBjC,IAAI;QAC3B,MAAMS,QAAQD,gBAAgBR;QAE9B,OAAO;YACLkC,WAAWzB;YACX0B,eAAe;YACfhB,WAAW,OAAOnB,KAAKE,UAAU,EAAEe,UAAU,WAAWjB,KAAKE,UAAU,CAACe,KAAK,GAAG;YAChFmB,WAAW3B;QACb;IACF;IACA4B,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBC,SAAS;IACTC,iBAAiB;QACfzB,OAAO;IACT;IACA0B,oBAAmB,EAAEzC,UAAU,EAAE;QAC/B,MAAM0C,WAAqB,EAAE;QAE7B,IACE,OAAO1C,WAAWC,KAAK,KAAK,YAC3B,CAAA,CAACE,OAAOE,SAAS,CAACF,OAAOC,QAAQ,CAACJ,WAAWC,KAAK,EAAE,QACnDE,OAAOC,QAAQ,CAACJ,WAAWC,KAAK,EAAE,MAAM,KACxCE,OAAOC,QAAQ,CAACJ,WAAWC,KAAK,EAAE,MAAM,CAAA,GAE1CyC,SAASC,IAAI,CAAC,CAAC,mBAAmB,EAAE3C,WAAWC,KAAK,CAAC,oBAAoB,EAAEN,kBAAkB,EAAE,CAAC;QAElG,OAAO+C;IACT;AACF,EAAC"}
1
+ {"version":3,"sources":["../../../src/directives/definitions/toc.ts"],"sourcesContent":["import type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { getDirectiveLabelOrAttribute } from '../labels.js'\nimport { resolveDirectiveTheme } from '../themes.js'\n\nexport const DEFAULT_TOC_DEPTH = 3\nexport const DEFAULT_TOC_TITLE = 'On this page'\n\nexport function resolveTocDepth(node: ContainerDirective): number {\n const value = node.attributes?.depth\n const parsed = typeof value === 'string' ? Number.parseInt(value, 10) : DEFAULT_TOC_DEPTH\n\n return Number.isInteger(parsed) && parsed >= 1 && parsed <= 6 ? parsed : DEFAULT_TOC_DEPTH\n}\n\nexport function resolveTocTitle(node: ContainerDirective): string {\n const title = getDirectiveLabelOrAttribute(node, 'title')\n\n return title ?? DEFAULT_TOC_TITLE\n}\n\nexport const tocDirective: LayoutDirectiveDefinition = {\n name: 'toc',\n allowedAttributes: ['depth', 'theme', 'title'],\n applyHast(node, config, { mergeClassNames }) {\n const theme = resolveDirectiveTheme(\n 'toc',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined,\n config.themes,\n )\n\n node.properties.dataTheme = theme.name\n node.properties.className = mergeClassNames(\n 'not-prose',\n theme.hookClassName,\n theme.modifierClassName,\n theme.classes,\n )\n },\n defaultAttributes: {\n depth: String(DEFAULT_TOC_DEPTH),\n title: DEFAULT_TOC_TITLE,\n },\n description: 'Table of contents generated from document headings.',\n editor: {\n detail: 'Docs directive',\n label: 'Table of contents',\n snippet: ':::toc[${On this page}]{\\n depth=\"${3}\"\\n}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n const title = resolveTocTitle(node)\n\n return {\n ariaLabel: title,\n dataDirective: 'toc',\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'default',\n dataTitle: title,\n }\n },\n kind: 'toc',\n openMarker: ':::toc',\n public: true,\n supportsAttributes: true,\n tagName: 'nav',\n themeAttributes: {\n theme: 'toc',\n },\n validateAttributes({ attributes }) {\n const warnings: string[] = []\n\n if (\n typeof attributes.depth === 'string' &&\n (!Number.isInteger(Number.parseInt(attributes.depth, 10)) ||\n Number.parseInt(attributes.depth, 10) < 1 ||\n Number.parseInt(attributes.depth, 10) > 6)\n )\n warnings.push(`Invalid toc depth \"${attributes.depth}\". Falling back to \"${DEFAULT_TOC_DEPTH}\".`)\n\n return warnings\n },\n}\n"],"names":["getDirectiveLabelOrAttribute","resolveDirectiveTheme","DEFAULT_TOC_DEPTH","DEFAULT_TOC_TITLE","resolveTocDepth","node","value","attributes","depth","parsed","Number","parseInt","isInteger","resolveTocTitle","title","tocDirective","name","allowedAttributes","applyHast","config","mergeClassNames","theme","properties","dataTheme","undefined","themes","className","hookClassName","modifierClassName","classes","defaultAttributes","String","description","editor","detail","label","snippet","getMdastRenderProperties","ariaLabel","dataDirective","dataTitle","kind","openMarker","public","supportsAttributes","tagName","themeAttributes","validateAttributes","warnings","push"],"mappings":"AAIA,SAASA,4BAA4B,QAAQ,eAAc;AAC3D,SAASC,qBAAqB,QAAQ,eAAc;AAEpD,OAAO,MAAMC,oBAAoB,EAAC;AAClC,OAAO,MAAMC,oBAAoB,eAAc;AAE/C,OAAO,SAASC,gBAAgBC,IAAwB;IACtD,MAAMC,QAAQD,KAAKE,UAAU,EAAEC;IAC/B,MAAMC,SAAS,OAAOH,UAAU,WAAWI,OAAOC,QAAQ,CAACL,OAAO,MAAMJ;IAExE,OAAOQ,OAAOE,SAAS,CAACH,WAAWA,UAAU,KAAKA,UAAU,IAAIA,SAASP;AAC3E;AAEA,OAAO,SAASW,gBAAgBR,IAAwB;IACtD,MAAMS,QAAQd,6BAA6BK,MAAM;IAEjD,OAAOS,SAASX;AAClB;AAEA,OAAO,MAAMY,eAA0C;IACrDC,MAAM;IACNC,mBAAmB;QAAC;QAAS;QAAS;KAAQ;IAC9CC,WAAUb,IAAI,EAAEc,MAAM,EAAE,EAAEC,eAAe,EAAE;QACzC,MAAMC,QAAQpB,sBACZ,OACA,OAAOI,KAAKiB,UAAU,CAACC,SAAS,KAAK,WAAWlB,KAAKiB,UAAU,CAACC,SAAS,GAAGC,WAC5EL,OAAOM,MAAM;QAGfpB,KAAKiB,UAAU,CAACC,SAAS,GAAGF,MAAML,IAAI;QACtCX,KAAKiB,UAAU,CAACI,SAAS,GAAGN,gBAC1B,aACAC,MAAMM,aAAa,EACnBN,MAAMO,iBAAiB,EACvBP,MAAMQ,OAAO;IAEjB;IACAC,mBAAmB;QACjBtB,OAAOuB,OAAO7B;QACdY,OAAOX;IACT;IACA6B,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRC,OAAO;QACPC,SAAS;IACX;IACAC,0BAAyBhC,IAAI;QAC3B,MAAMS,QAAQD,gBAAgBR;QAE9B,OAAO;YACLiC,WAAWxB;YACXyB,eAAe;YACfhB,WAAW,OAAOlB,KAAKE,UAAU,EAAEc,UAAU,WAAWhB,KAAKE,UAAU,CAACc,KAAK,GAAG;YAChFmB,WAAW1B;QACb;IACF;IACA2B,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBC,SAAS;IACTC,iBAAiB;QACfzB,OAAO;IACT;IACA0B,oBAAmB,EAAExC,UAAU,EAAE;QAC/B,MAAMyC,WAAqB,EAAE;QAE7B,IACE,OAAOzC,WAAWC,KAAK,KAAK,YAC3B,CAAA,CAACE,OAAOE,SAAS,CAACF,OAAOC,QAAQ,CAACJ,WAAWC,KAAK,EAAE,QACnDE,OAAOC,QAAQ,CAACJ,WAAWC,KAAK,EAAE,MAAM,KACxCE,OAAOC,QAAQ,CAACJ,WAAWC,KAAK,EAAE,MAAM,CAAA,GAE1CwC,SAASC,IAAI,CAAC,CAAC,mBAAmB,EAAE1C,WAAWC,KAAK,CAAC,oBAAoB,EAAEN,kBAAkB,EAAE,CAAC;QAElG,OAAO8C;IACT;AACF,EAAC"}