@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.
- package/README.md +63 -14
- package/dist/components/MarkdownRenderer/index.css +150 -0
- package/dist/components/MarkdownRenderer/index.scss +158 -0
- package/dist/core/plugins/rehypeResolveIcons.d.ts +4 -0
- package/dist/core/plugins/rehypeResolveIcons.js +27 -0
- package/dist/core/plugins/rehypeResolveIcons.js.map +1 -0
- package/dist/core/plugins/remarkButtonDirectives.d.ts +4 -0
- package/dist/core/plugins/remarkButtonDirectives.js +237 -0
- package/dist/core/plugins/remarkButtonDirectives.js.map +1 -0
- package/dist/core/plugins/remarkCompileLayouts.js +6 -5
- package/dist/core/plugins/remarkCompileLayouts.js.map +1 -1
- package/dist/core/plugins/remarkLayoutDirectives.js +17 -7
- package/dist/core/plugins/remarkLayoutDirectives.js.map +1 -1
- package/dist/core/plugins/remarkLiftLayoutDirectives.js +42 -4
- package/dist/core/plugins/remarkLiftLayoutDirectives.js.map +1 -1
- package/dist/core/renderMarkdown.js +27 -2
- package/dist/core/renderMarkdown.js.map +1 -1
- package/dist/directives/attributeDiagnostics.d.ts +2 -0
- package/dist/directives/attributeDiagnostics.js +35 -0
- package/dist/directives/attributeDiagnostics.js.map +1 -0
- package/dist/directives/attributes.d.ts +8 -0
- package/dist/directives/attributes.js +56 -5
- package/dist/directives/attributes.js.map +1 -1
- package/dist/directives/buttonSyntax.d.ts +7 -0
- package/dist/directives/buttonSyntax.js +26 -0
- package/dist/directives/buttonSyntax.js.map +1 -0
- package/dist/directives/closeLabels.d.ts +8 -0
- package/dist/directives/closeLabels.js +76 -0
- package/dist/directives/closeLabels.js.map +1 -0
- package/dist/directives/definitions/button.d.ts +15 -0
- package/dist/directives/definitions/button.js +96 -0
- package/dist/directives/definitions/button.js.map +1 -0
- package/dist/directives/definitions/buttons.d.ts +8 -0
- package/dist/directives/definitions/buttons.js +82 -0
- package/dist/directives/definitions/buttons.js.map +1 -0
- package/dist/directives/definitions/callout.js +20 -9
- package/dist/directives/definitions/callout.js.map +1 -1
- package/dist/directives/definitions/card.d.ts +4 -0
- package/dist/directives/definitions/card.js +90 -9
- package/dist/directives/definitions/card.js.map +1 -1
- package/dist/directives/definitions/cards.d.ts +4 -0
- package/dist/directives/definitions/cards.js +119 -4
- package/dist/directives/definitions/cards.js.map +1 -1
- package/dist/directives/definitions/details.js +4 -3
- package/dist/directives/definitions/details.js.map +1 -1
- package/dist/directives/definitions/tab.d.ts +1 -0
- package/dist/directives/definitions/tab.js +10 -3
- package/dist/directives/definitions/tab.js.map +1 -1
- package/dist/directives/definitions/tabs.js +3 -3
- package/dist/directives/definitions/tabs.js.map +1 -1
- package/dist/directives/definitions/toc.js +4 -3
- package/dist/directives/definitions/toc.js.map +1 -1
- package/dist/directives/diagnostics.js +97 -7
- package/dist/directives/diagnostics.js.map +1 -1
- package/dist/directives/iconPlaceholder.d.ts +12 -0
- package/dist/directives/iconPlaceholder.js +19 -0
- package/dist/directives/iconPlaceholder.js.map +1 -0
- package/dist/directives/labels.d.ts +3 -0
- package/dist/directives/labels.js +12 -0
- package/dist/directives/labels.js.map +1 -0
- package/dist/directives/registry.d.ts +1 -1
- package/dist/directives/registry.js +46 -6
- package/dist/directives/registry.js.map +1 -1
- package/dist/directives/renderData.d.ts +2 -2
- package/dist/directives/renderData.js.map +1 -1
- package/dist/directives/types.d.ts +6 -4
- package/dist/directives/types.js.map +1 -1
- package/dist/editor/MarkdownCodeMirror/Component.client.js +2 -0
- package/dist/editor/MarkdownCodeMirror/Component.client.js.map +1 -1
- package/dist/editor/directives/closeLabels.d.ts +2 -0
- package/dist/editor/directives/closeLabels.js +75 -0
- package/dist/editor/directives/closeLabels.js.map +1 -0
- package/dist/editor/directives/completions.js +49 -7
- package/dist/editor/directives/completions.js.map +1 -1
- package/dist/editor/themes/payload.js +197 -9
- package/dist/editor/themes/payload.js.map +1 -1
- package/dist/exports/advanced.d.ts +1 -0
- package/dist/exports/advanced.js +1 -0
- package/dist/exports/advanced.js.map +1 -1
- package/dist/icons/generateRegistry.d.ts +8 -0
- package/dist/icons/generateRegistry.js +36 -0
- package/dist/icons/generateRegistry.js.map +1 -0
- package/dist/icons/refs.d.ts +10 -0
- package/dist/icons/refs.js +42 -0
- package/dist/icons/refs.js.map +1 -0
- package/dist/icons/resolve.d.ts +9 -0
- package/dist/icons/resolve.js +95 -0
- package/dist/icons/resolve.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +8 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/types/core.d.ts +9 -0
- package/dist/types/core.js.map +1 -1
- package/dist/types/mdast.d.js.map +1 -1
- package/dist/types.d.ts +5 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { getUnknownAttributeWarnings } from '../attributeDiagnostics.js';
|
|
2
|
+
export const BUTTON_VARIANTS = [
|
|
3
|
+
'primary',
|
|
4
|
+
'secondary',
|
|
5
|
+
'outline',
|
|
6
|
+
'ghost',
|
|
7
|
+
'link'
|
|
8
|
+
];
|
|
9
|
+
export const BUTTON_SIZES = [
|
|
10
|
+
'sm',
|
|
11
|
+
'md',
|
|
12
|
+
'lg'
|
|
13
|
+
];
|
|
14
|
+
export const BUTTON_ICON_POSITIONS = [
|
|
15
|
+
'left',
|
|
16
|
+
'right'
|
|
17
|
+
];
|
|
18
|
+
export const BUTTON_ALLOWED_ATTRIBUTES = [
|
|
19
|
+
'ariaLabel',
|
|
20
|
+
'href',
|
|
21
|
+
'icon',
|
|
22
|
+
'iconPosition',
|
|
23
|
+
'newTab',
|
|
24
|
+
'size',
|
|
25
|
+
'variant'
|
|
26
|
+
];
|
|
27
|
+
export const DEFAULT_BUTTON_VARIANT = 'primary';
|
|
28
|
+
export const DEFAULT_BUTTON_SIZE = 'md';
|
|
29
|
+
export const DEFAULT_BUTTON_ICON_POSITION = 'left';
|
|
30
|
+
export function isButtonVariant(value) {
|
|
31
|
+
return typeof value === 'string' && BUTTON_VARIANTS.includes(value);
|
|
32
|
+
}
|
|
33
|
+
export function isButtonSize(value) {
|
|
34
|
+
return typeof value === 'string' && BUTTON_SIZES.includes(value);
|
|
35
|
+
}
|
|
36
|
+
export function isButtonIconPosition(value) {
|
|
37
|
+
return typeof value === 'string' && BUTTON_ICON_POSITIONS.includes(value);
|
|
38
|
+
}
|
|
39
|
+
export const buttonDirective = {
|
|
40
|
+
name: 'button',
|
|
41
|
+
allowedAttributes: BUTTON_ALLOWED_ATTRIBUTES,
|
|
42
|
+
applyHast (node, _config, { mergeClassNames }) {
|
|
43
|
+
const variant = isButtonVariant(node.properties.dataVariant) ? node.properties.dataVariant : DEFAULT_BUTTON_VARIANT;
|
|
44
|
+
const size = isButtonSize(node.properties.dataSize) ? node.properties.dataSize : DEFAULT_BUTTON_SIZE;
|
|
45
|
+
node.properties.dataVariant = variant;
|
|
46
|
+
node.properties.dataSize = size;
|
|
47
|
+
node.properties.className = mergeClassNames('pmd-button', `pmd-button--${variant}`, `pmd-button--${size}`);
|
|
48
|
+
},
|
|
49
|
+
attributeValues: {
|
|
50
|
+
iconPosition: BUTTON_ICON_POSITIONS,
|
|
51
|
+
newTab: [
|
|
52
|
+
'true',
|
|
53
|
+
'false'
|
|
54
|
+
],
|
|
55
|
+
size: BUTTON_SIZES,
|
|
56
|
+
variant: BUTTON_VARIANTS
|
|
57
|
+
},
|
|
58
|
+
defaultAttributes: {
|
|
59
|
+
iconPosition: DEFAULT_BUTTON_ICON_POSITION,
|
|
60
|
+
newTab: 'false',
|
|
61
|
+
size: DEFAULT_BUTTON_SIZE,
|
|
62
|
+
variant: DEFAULT_BUTTON_VARIANT
|
|
63
|
+
},
|
|
64
|
+
description: 'Link button with optional icon, variant, size, and new-tab behavior.',
|
|
65
|
+
editor: {
|
|
66
|
+
detail: 'Button leaf directive',
|
|
67
|
+
label: '::button',
|
|
68
|
+
snippet: '::button[${Label}]{\n href="${/docs}"\n variant="${primary}"\n}\n${}',
|
|
69
|
+
snippets: [
|
|
70
|
+
{
|
|
71
|
+
detail: 'Button snippet variant; inserts canonical ::button',
|
|
72
|
+
label: '::button_icon',
|
|
73
|
+
snippet: '::button[${Label}]{\n href="${/docs}"\n variant="${primary}"\n icon="${@fa-duotone/book-open}"\n}\n${}'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
detail: 'Button snippet variant; inserts canonical ::button',
|
|
77
|
+
label: '::button_full',
|
|
78
|
+
snippet: '::button[${Label}]{\n href="${/docs}"\n variant="${primary}"\n size="${md}"\n icon="${@fa-duotone/book-open}"\n iconPosition="${left}"\n newTab=${false}\n ariaLabel="${}"\n}'
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
kind: 'button',
|
|
83
|
+
public: true,
|
|
84
|
+
supportsAttributes: true,
|
|
85
|
+
tagName: 'a',
|
|
86
|
+
validateAttributes ({ attributes }) {
|
|
87
|
+
const warnings = getUnknownAttributeWarnings('button', BUTTON_ALLOWED_ATTRIBUTES, attributes);
|
|
88
|
+
if (typeof attributes.variant === 'string' && !isButtonVariant(attributes.variant)) warnings.push(`Invalid button variant "${attributes.variant}". Falling back to "${DEFAULT_BUTTON_VARIANT}".`);
|
|
89
|
+
if (typeof attributes.size === 'string' && !isButtonSize(attributes.size)) warnings.push(`Invalid button size "${attributes.size}". Falling back to "${DEFAULT_BUTTON_SIZE}".`);
|
|
90
|
+
if (typeof attributes.iconPosition === 'string' && !isButtonIconPosition(attributes.iconPosition)) warnings.push(`Invalid button iconPosition "${attributes.iconPosition}". Falling back to "${DEFAULT_BUTTON_ICON_POSITION}".`);
|
|
91
|
+
if (typeof attributes.href !== 'string' || !attributes.href.trim()) warnings.push('Directive "button" requires an href attribute.');
|
|
92
|
+
return warnings;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
//# sourceMappingURL=button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/definitions/button.ts"],"sourcesContent":["import type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { getUnknownAttributeWarnings } from '../attributeDiagnostics.js'\n\nexport const BUTTON_VARIANTS = ['primary', 'secondary', 'outline', 'ghost', 'link'] as const\nexport const BUTTON_SIZES = ['sm', 'md', 'lg'] as const\nexport const BUTTON_ICON_POSITIONS = ['left', 'right'] as const\nexport const BUTTON_ALLOWED_ATTRIBUTES = [\n 'ariaLabel',\n 'href',\n 'icon',\n 'iconPosition',\n 'newTab',\n 'size',\n 'variant',\n] as const\n\nexport const DEFAULT_BUTTON_VARIANT = 'primary'\nexport const DEFAULT_BUTTON_SIZE = 'md'\nexport const DEFAULT_BUTTON_ICON_POSITION = 'left'\n\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number]\nexport type ButtonSize = (typeof BUTTON_SIZES)[number]\nexport type ButtonIconPosition = (typeof BUTTON_ICON_POSITIONS)[number]\n\nexport function isButtonVariant(value: unknown): value is ButtonVariant {\n return typeof value === 'string' && BUTTON_VARIANTS.includes(value as ButtonVariant)\n}\n\nexport function isButtonSize(value: unknown): value is ButtonSize {\n return typeof value === 'string' && BUTTON_SIZES.includes(value as ButtonSize)\n}\n\nexport function isButtonIconPosition(value: unknown): value is ButtonIconPosition {\n return typeof value === 'string' && BUTTON_ICON_POSITIONS.includes(value as ButtonIconPosition)\n}\n\nexport const buttonDirective: LayoutDirectiveDefinition = {\n name: 'button',\n allowedAttributes: BUTTON_ALLOWED_ATTRIBUTES,\n applyHast(node, _config, { mergeClassNames }) {\n const variant = isButtonVariant(node.properties.dataVariant)\n ? node.properties.dataVariant\n : DEFAULT_BUTTON_VARIANT\n const size = isButtonSize(node.properties.dataSize) ? node.properties.dataSize : DEFAULT_BUTTON_SIZE\n\n node.properties.dataVariant = variant\n node.properties.dataSize = size\n node.properties.className = mergeClassNames(\n 'pmd-button',\n `pmd-button--${variant}`,\n `pmd-button--${size}`,\n )\n },\n attributeValues: {\n iconPosition: BUTTON_ICON_POSITIONS,\n newTab: ['true', 'false'],\n size: BUTTON_SIZES,\n variant: BUTTON_VARIANTS,\n },\n defaultAttributes: {\n iconPosition: DEFAULT_BUTTON_ICON_POSITION,\n newTab: 'false',\n size: DEFAULT_BUTTON_SIZE,\n variant: DEFAULT_BUTTON_VARIANT,\n },\n description: 'Link button with optional icon, variant, size, and new-tab behavior.',\n editor: {\n detail: 'Button leaf directive',\n label: '::button',\n snippet: '::button[${Label}]{\\n href=\"${/docs}\"\\n variant=\"${primary}\"\\n}\\n${}',\n snippets: [\n {\n detail: 'Button snippet variant; inserts canonical ::button',\n label: '::button_icon',\n snippet:\n '::button[${Label}]{\\n href=\"${/docs}\"\\n variant=\"${primary}\"\\n icon=\"${@fa-duotone/book-open}\"\\n}\\n${}',\n },\n {\n detail: 'Button snippet variant; inserts canonical ::button',\n label: '::button_full',\n snippet:\n '::button[${Label}]{\\n href=\"${/docs}\"\\n variant=\"${primary}\"\\n size=\"${md}\"\\n icon=\"${@fa-duotone/book-open}\"\\n iconPosition=\"${left}\"\\n newTab=${false}\\n ariaLabel=\"${}\"\\n}',\n },\n ],\n },\n kind: 'button',\n public: true,\n supportsAttributes: true,\n tagName: 'a',\n validateAttributes({ attributes }) {\n const warnings: string[] = getUnknownAttributeWarnings(\n 'button',\n BUTTON_ALLOWED_ATTRIBUTES,\n attributes,\n )\n\n if (typeof attributes.variant === 'string' && !isButtonVariant(attributes.variant))\n warnings.push(\n `Invalid button variant \"${attributes.variant}\". Falling back to \"${DEFAULT_BUTTON_VARIANT}\".`,\n )\n\n if (typeof attributes.size === 'string' && !isButtonSize(attributes.size))\n warnings.push(\n `Invalid button size \"${attributes.size}\". Falling back to \"${DEFAULT_BUTTON_SIZE}\".`,\n )\n\n if (\n typeof attributes.iconPosition === 'string' &&\n !isButtonIconPosition(attributes.iconPosition)\n )\n warnings.push(\n `Invalid button iconPosition \"${attributes.iconPosition}\". Falling back to \"${DEFAULT_BUTTON_ICON_POSITION}\".`,\n )\n\n if (typeof attributes.href !== 'string' || !attributes.href.trim())\n warnings.push('Directive \"button\" requires an href attribute.')\n\n return warnings\n },\n}\n"],"names":["getUnknownAttributeWarnings","BUTTON_VARIANTS","BUTTON_SIZES","BUTTON_ICON_POSITIONS","BUTTON_ALLOWED_ATTRIBUTES","DEFAULT_BUTTON_VARIANT","DEFAULT_BUTTON_SIZE","DEFAULT_BUTTON_ICON_POSITION","isButtonVariant","value","includes","isButtonSize","isButtonIconPosition","buttonDirective","name","allowedAttributes","applyHast","node","_config","mergeClassNames","variant","properties","dataVariant","size","dataSize","className","attributeValues","iconPosition","newTab","defaultAttributes","description","editor","detail","label","snippet","snippets","kind","public","supportsAttributes","tagName","validateAttributes","attributes","warnings","push","href","trim"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LayoutDirectiveDefinition } from '../types.js';
|
|
2
|
+
export declare const BUTTONS_ALIGNS: readonly ["left", "center", "right"];
|
|
3
|
+
export declare const BUTTONS_STACKS: readonly ["mobile", "always", "never"];
|
|
4
|
+
export declare const BUTTONS_GAPS: readonly ["sm", "md", "lg"];
|
|
5
|
+
export declare const DEFAULT_BUTTONS_ALIGN = "left";
|
|
6
|
+
export declare const DEFAULT_BUTTONS_STACK = "mobile";
|
|
7
|
+
export declare const DEFAULT_BUTTONS_GAP = "md";
|
|
8
|
+
export declare const buttonsDirective: LayoutDirectiveDefinition;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export const BUTTONS_ALIGNS = [
|
|
2
|
+
'left',
|
|
3
|
+
'center',
|
|
4
|
+
'right'
|
|
5
|
+
];
|
|
6
|
+
export const BUTTONS_STACKS = [
|
|
7
|
+
'mobile',
|
|
8
|
+
'always',
|
|
9
|
+
'never'
|
|
10
|
+
];
|
|
11
|
+
export const BUTTONS_GAPS = [
|
|
12
|
+
'sm',
|
|
13
|
+
'md',
|
|
14
|
+
'lg'
|
|
15
|
+
];
|
|
16
|
+
export const DEFAULT_BUTTONS_ALIGN = 'left';
|
|
17
|
+
export const DEFAULT_BUTTONS_STACK = 'mobile';
|
|
18
|
+
export const DEFAULT_BUTTONS_GAP = 'md';
|
|
19
|
+
function isButtonsAlign(value) {
|
|
20
|
+
return typeof value === 'string' && BUTTONS_ALIGNS.includes(value);
|
|
21
|
+
}
|
|
22
|
+
function isButtonsStack(value) {
|
|
23
|
+
return typeof value === 'string' && BUTTONS_STACKS.includes(value);
|
|
24
|
+
}
|
|
25
|
+
function isButtonsGap(value) {
|
|
26
|
+
return typeof value === 'string' && BUTTONS_GAPS.includes(value);
|
|
27
|
+
}
|
|
28
|
+
export const buttonsDirective = {
|
|
29
|
+
name: 'buttons',
|
|
30
|
+
allowedAttributes: [
|
|
31
|
+
'align',
|
|
32
|
+
'gap',
|
|
33
|
+
'stack'
|
|
34
|
+
],
|
|
35
|
+
applyHast (node, _config, { mergeClassNames }) {
|
|
36
|
+
const align = typeof node.properties.dataAlign === 'string' && isButtonsAlign(node.properties.dataAlign) ? node.properties.dataAlign : DEFAULT_BUTTONS_ALIGN;
|
|
37
|
+
const stack = typeof node.properties.dataStack === 'string' && isButtonsStack(node.properties.dataStack) ? node.properties.dataStack : DEFAULT_BUTTONS_STACK;
|
|
38
|
+
const gap = typeof node.properties.dataGap === 'string' && isButtonsGap(node.properties.dataGap) ? node.properties.dataGap : DEFAULT_BUTTONS_GAP;
|
|
39
|
+
node.properties.dataAlign = align;
|
|
40
|
+
node.properties.dataStack = stack;
|
|
41
|
+
node.properties.dataGap = gap;
|
|
42
|
+
node.properties.className = mergeClassNames('not-prose', 'pmd-buttons', `pmd-buttons--align-${align}`, `pmd-buttons--stack-${stack}`, `pmd-buttons--gap-${gap}`);
|
|
43
|
+
},
|
|
44
|
+
attributeValues: {
|
|
45
|
+
align: BUTTONS_ALIGNS,
|
|
46
|
+
gap: BUTTONS_GAPS,
|
|
47
|
+
stack: BUTTONS_STACKS
|
|
48
|
+
},
|
|
49
|
+
defaultAttributes: {
|
|
50
|
+
align: DEFAULT_BUTTONS_ALIGN,
|
|
51
|
+
gap: DEFAULT_BUTTONS_GAP,
|
|
52
|
+
stack: DEFAULT_BUTTONS_STACK
|
|
53
|
+
},
|
|
54
|
+
description: 'Button group wrapper for one or more button directives.',
|
|
55
|
+
editor: {
|
|
56
|
+
detail: 'Button group directive',
|
|
57
|
+
label: 'Buttons',
|
|
58
|
+
snippet: ':::buttons{\n align="${left}"\n stack="${mobile}"\n gap="${md}"\n}\n::button[${Get started}]{\n href="${/docs}"\n variant="${primary}"\n}\n:::\n${}'
|
|
59
|
+
},
|
|
60
|
+
getMdastRenderProperties (node) {
|
|
61
|
+
return {
|
|
62
|
+
dataAlign: typeof node.attributes?.align === 'string' ? node.attributes.align : DEFAULT_BUTTONS_ALIGN,
|
|
63
|
+
dataDirective: 'buttons',
|
|
64
|
+
dataGap: typeof node.attributes?.gap === 'string' ? node.attributes.gap : DEFAULT_BUTTONS_GAP,
|
|
65
|
+
dataStack: typeof node.attributes?.stack === 'string' ? node.attributes.stack : DEFAULT_BUTTONS_STACK
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
kind: 'buttons',
|
|
69
|
+
openMarker: ':::buttons',
|
|
70
|
+
public: true,
|
|
71
|
+
supportsAttributes: true,
|
|
72
|
+
tagName: 'div',
|
|
73
|
+
validateAttributes ({ attributes }) {
|
|
74
|
+
const warnings = [];
|
|
75
|
+
if (typeof attributes.align === 'string' && !isButtonsAlign(attributes.align)) warnings.push(`Invalid buttons align "${attributes.align}". Falling back to "${DEFAULT_BUTTONS_ALIGN}".`);
|
|
76
|
+
if (typeof attributes.stack === 'string' && !isButtonsStack(attributes.stack)) warnings.push(`Invalid buttons stack "${attributes.stack}". Falling back to "${DEFAULT_BUTTONS_STACK}".`);
|
|
77
|
+
if (typeof attributes.gap === 'string' && !isButtonsGap(attributes.gap)) warnings.push(`Invalid buttons gap "${attributes.gap}". Falling back to "${DEFAULT_BUTTONS_GAP}".`);
|
|
78
|
+
return warnings;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=buttons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/definitions/buttons.ts"],"sourcesContent":["import type { LayoutDirectiveDefinition } from '../types.js'\n\nexport const BUTTONS_ALIGNS = ['left', 'center', 'right'] as const\nexport const BUTTONS_STACKS = ['mobile', 'always', 'never'] as const\nexport const BUTTONS_GAPS = ['sm', 'md', 'lg'] as const\n\nexport const DEFAULT_BUTTONS_ALIGN = 'left'\nexport const DEFAULT_BUTTONS_STACK = 'mobile'\nexport const DEFAULT_BUTTONS_GAP = 'md'\n\ntype ButtonsAlign = (typeof BUTTONS_ALIGNS)[number]\ntype ButtonsStack = (typeof BUTTONS_STACKS)[number]\ntype ButtonsGap = (typeof BUTTONS_GAPS)[number]\n\nfunction isButtonsAlign(value: unknown): value is ButtonsAlign {\n return typeof value === 'string' && BUTTONS_ALIGNS.includes(value as ButtonsAlign)\n}\n\nfunction isButtonsStack(value: unknown): value is ButtonsStack {\n return typeof value === 'string' && BUTTONS_STACKS.includes(value as ButtonsStack)\n}\n\nfunction isButtonsGap(value: unknown): value is ButtonsGap {\n return typeof value === 'string' && BUTTONS_GAPS.includes(value as ButtonsGap)\n}\n\nexport const buttonsDirective: LayoutDirectiveDefinition = {\n name: 'buttons',\n allowedAttributes: ['align', 'gap', 'stack'],\n applyHast(node, _config, { mergeClassNames }) {\n const align =\n typeof node.properties.dataAlign === 'string' && isButtonsAlign(node.properties.dataAlign)\n ? node.properties.dataAlign\n : DEFAULT_BUTTONS_ALIGN\n const stack =\n typeof node.properties.dataStack === 'string' && isButtonsStack(node.properties.dataStack)\n ? node.properties.dataStack\n : DEFAULT_BUTTONS_STACK\n const gap =\n typeof node.properties.dataGap === 'string' && isButtonsGap(node.properties.dataGap)\n ? node.properties.dataGap\n : DEFAULT_BUTTONS_GAP\n\n node.properties.dataAlign = align\n node.properties.dataStack = stack\n node.properties.dataGap = gap\n node.properties.className = mergeClassNames(\n 'not-prose',\n 'pmd-buttons',\n `pmd-buttons--align-${align}`,\n `pmd-buttons--stack-${stack}`,\n `pmd-buttons--gap-${gap}`,\n )\n },\n attributeValues: {\n align: BUTTONS_ALIGNS,\n gap: BUTTONS_GAPS,\n stack: BUTTONS_STACKS,\n },\n defaultAttributes: {\n align: DEFAULT_BUTTONS_ALIGN,\n gap: DEFAULT_BUTTONS_GAP,\n stack: DEFAULT_BUTTONS_STACK,\n },\n description: 'Button group wrapper for one or more button directives.',\n editor: {\n detail: 'Button group directive',\n label: 'Buttons',\n snippet:\n ':::buttons{\\n align=\"${left}\"\\n stack=\"${mobile}\"\\n gap=\"${md}\"\\n}\\n::button[${Get started}]{\\n href=\"${/docs}\"\\n variant=\"${primary}\"\\n}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataAlign: typeof node.attributes?.align === 'string' ? node.attributes.align : DEFAULT_BUTTONS_ALIGN,\n dataDirective: 'buttons',\n dataGap: typeof node.attributes?.gap === 'string' ? node.attributes.gap : DEFAULT_BUTTONS_GAP,\n dataStack: typeof node.attributes?.stack === 'string' ? node.attributes.stack : DEFAULT_BUTTONS_STACK,\n }\n },\n kind: 'buttons',\n openMarker: ':::buttons',\n public: true,\n supportsAttributes: true,\n tagName: 'div',\n validateAttributes({ attributes }) {\n const warnings: string[] = []\n\n if (typeof attributes.align === 'string' && !isButtonsAlign(attributes.align))\n warnings.push(\n `Invalid buttons align \"${attributes.align}\". Falling back to \"${DEFAULT_BUTTONS_ALIGN}\".`,\n )\n\n if (typeof attributes.stack === 'string' && !isButtonsStack(attributes.stack))\n warnings.push(\n `Invalid buttons stack \"${attributes.stack}\". Falling back to \"${DEFAULT_BUTTONS_STACK}\".`,\n )\n\n if (typeof attributes.gap === 'string' && !isButtonsGap(attributes.gap))\n warnings.push(\n `Invalid buttons gap \"${attributes.gap}\". Falling back to \"${DEFAULT_BUTTONS_GAP}\".`,\n )\n\n return warnings\n },\n}\n"],"names":["BUTTONS_ALIGNS","BUTTONS_STACKS","BUTTONS_GAPS","DEFAULT_BUTTONS_ALIGN","DEFAULT_BUTTONS_STACK","DEFAULT_BUTTONS_GAP","isButtonsAlign","value","includes","isButtonsStack","isButtonsGap","buttonsDirective","name","allowedAttributes","applyHast","node","_config","mergeClassNames","align","properties","dataAlign","stack","dataStack","gap","dataGap","className","attributeValues","defaultAttributes","description","editor","detail","label","snippet","getMdastRenderProperties","attributes","dataDirective","kind","openMarker","public","supportsAttributes","tagName","validateAttributes","warnings","push"],"mappings":"AAEA,OAAO,MAAMA,iBAAiB;IAAC;IAAQ;IAAU;CAAQ,CAAS;AAClE,OAAO,MAAMC,iBAAiB;IAAC;IAAU;IAAU;CAAQ,CAAS;AACpE,OAAO,MAAMC,eAAe;IAAC;IAAM;IAAM;CAAK,CAAS;AAEvD,OAAO,MAAMC,wBAAwB,OAAM;AAC3C,OAAO,MAAMC,wBAAwB,SAAQ;AAC7C,OAAO,MAAMC,sBAAsB,KAAI;AAMvC,SAASC,eAAeC,KAAc;IACpC,OAAO,OAAOA,UAAU,YAAYP,eAAeQ,QAAQ,CAACD;AAC9D;AAEA,SAASE,eAAeF,KAAc;IACpC,OAAO,OAAOA,UAAU,YAAYN,eAAeO,QAAQ,CAACD;AAC9D;AAEA,SAASG,aAAaH,KAAc;IAClC,OAAO,OAAOA,UAAU,YAAYL,aAAaM,QAAQ,CAACD;AAC5D;AAEA,OAAO,MAAMI,mBAA8C;IACzDC,MAAM;IACNC,mBAAmB;QAAC;QAAS;QAAO;KAAQ;IAC5CC,WAAUC,IAAI,EAAEC,OAAO,EAAE,EAAEC,eAAe,EAAE;QAC1C,MAAMC,QACJ,OAAOH,KAAKI,UAAU,CAACC,SAAS,KAAK,YAAYd,eAAeS,KAAKI,UAAU,CAACC,SAAS,IACrFL,KAAKI,UAAU,CAACC,SAAS,GACzBjB;QACN,MAAMkB,QACJ,OAAON,KAAKI,UAAU,CAACG,SAAS,KAAK,YAAYb,eAAeM,KAAKI,UAAU,CAACG,SAAS,IACrFP,KAAKI,UAAU,CAACG,SAAS,GACzBlB;QACN,MAAMmB,MACJ,OAAOR,KAAKI,UAAU,CAACK,OAAO,KAAK,YAAYd,aAAaK,KAAKI,UAAU,CAACK,OAAO,IAC/ET,KAAKI,UAAU,CAACK,OAAO,GACvBnB;QAENU,KAAKI,UAAU,CAACC,SAAS,GAAGF;QAC5BH,KAAKI,UAAU,CAACG,SAAS,GAAGD;QAC5BN,KAAKI,UAAU,CAACK,OAAO,GAAGD;QAC1BR,KAAKI,UAAU,CAACM,SAAS,GAAGR,gBAC1B,aACA,eACA,CAAC,mBAAmB,EAAEC,OAAO,EAC7B,CAAC,mBAAmB,EAAEG,OAAO,EAC7B,CAAC,iBAAiB,EAAEE,KAAK;IAE7B;IACAG,iBAAiB;QACfR,OAAOlB;QACPuB,KAAKrB;QACLmB,OAAOpB;IACT;IACA0B,mBAAmB;QACjBT,OAAOf;QACPoB,KAAKlB;QACLgB,OAAOjB;IACT;IACAwB,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRC,OAAO;QACPC,SACE;IACJ;IACAC,0BAAyBlB,IAAI;QAC3B,OAAO;YACLK,WAAW,OAAOL,KAAKmB,UAAU,EAAEhB,UAAU,WAAWH,KAAKmB,UAAU,CAAChB,KAAK,GAAGf;YAChFgC,eAAe;YACfX,SAAS,OAAOT,KAAKmB,UAAU,EAAEX,QAAQ,WAAWR,KAAKmB,UAAU,CAACX,GAAG,GAAGlB;YAC1EiB,WAAW,OAAOP,KAAKmB,UAAU,EAAEb,UAAU,WAAWN,KAAKmB,UAAU,CAACb,KAAK,GAAGjB;QAClF;IACF;IACAgC,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBC,SAAS;IACTC,oBAAmB,EAAEP,UAAU,EAAE;QAC/B,MAAMQ,WAAqB,EAAE;QAE7B,IAAI,OAAOR,WAAWhB,KAAK,KAAK,YAAY,CAACZ,eAAe4B,WAAWhB,KAAK,GAC1EwB,SAASC,IAAI,CACX,CAAC,uBAAuB,EAAET,WAAWhB,KAAK,CAAC,oBAAoB,EAAEf,sBAAsB,EAAE,CAAC;QAG9F,IAAI,OAAO+B,WAAWb,KAAK,KAAK,YAAY,CAACZ,eAAeyB,WAAWb,KAAK,GAC1EqB,SAASC,IAAI,CACX,CAAC,uBAAuB,EAAET,WAAWb,KAAK,CAAC,oBAAoB,EAAEjB,sBAAsB,EAAE,CAAC;QAG9F,IAAI,OAAO8B,WAAWX,GAAG,KAAK,YAAY,CAACb,aAAawB,WAAWX,GAAG,GACpEmB,SAASC,IAAI,CACX,CAAC,qBAAqB,EAAET,WAAWX,GAAG,CAAC,oBAAoB,EAAElB,oBAAoB,EAAE,CAAC;QAGxF,OAAOqC;IACT;AACF,EAAC"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { makeDirectiveIconPlaceholder } from '../iconPlaceholder.js';
|
|
2
|
+
import { getDirectiveLabelOrAttribute } from '../labels.js';
|
|
1
3
|
import { resolveDirectiveTheme } from '../themes.js';
|
|
2
4
|
export const CALLOUT_VARIANTS = [
|
|
3
5
|
'note',
|
|
@@ -23,12 +25,12 @@ export function resolveCalloutVariant(node) {
|
|
|
23
25
|
return isCalloutVariant(variant) ? variant : 'note';
|
|
24
26
|
}
|
|
25
27
|
function getTitle(node) {
|
|
26
|
-
|
|
27
|
-
return typeof title === 'string' && title.trim() ? title.trim() : undefined;
|
|
28
|
+
return getDirectiveLabelOrAttribute(node, 'title');
|
|
28
29
|
}
|
|
29
30
|
export const calloutDirective = {
|
|
30
31
|
name: 'callout',
|
|
31
32
|
allowedAttributes: [
|
|
33
|
+
'icon',
|
|
32
34
|
'theme',
|
|
33
35
|
'title',
|
|
34
36
|
'variant'
|
|
@@ -36,23 +38,31 @@ export const calloutDirective = {
|
|
|
36
38
|
applyHast (node, config, { mergeClassNames }) {
|
|
37
39
|
const variant = typeof node.properties.dataVariant === 'string' ? node.properties.dataVariant : 'note';
|
|
38
40
|
const title = typeof node.properties.dataTitle === 'string' ? node.properties.dataTitle : undefined;
|
|
41
|
+
const icon = typeof node.properties.dataIcon === 'string' ? node.properties.dataIcon : undefined;
|
|
39
42
|
const theme = resolveDirectiveTheme('callout', typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : 'soft', config.themes);
|
|
40
43
|
const children = node.children;
|
|
41
44
|
node.properties.dataTheme = theme.name;
|
|
42
45
|
node.properties.className = mergeClassNames('not-prose', theme.hookClassName, theme.modifierClassName, theme.classes, calloutVariantClasses[isCalloutVariant(variant) ? variant : 'note']);
|
|
43
46
|
node.children = [
|
|
44
|
-
...title ? [
|
|
47
|
+
...title || icon ? [
|
|
45
48
|
{
|
|
46
49
|
type: 'element',
|
|
47
50
|
children: [
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
...icon ? [
|
|
52
|
+
makeDirectiveIconPlaceholder(icon, [
|
|
53
|
+
'pmd-callout__icon inline-flex size-4 shrink-0 text-current'
|
|
54
|
+
])
|
|
55
|
+
] : [],
|
|
56
|
+
...title ? [
|
|
57
|
+
{
|
|
58
|
+
type: 'text',
|
|
59
|
+
value: title
|
|
60
|
+
}
|
|
61
|
+
] : []
|
|
52
62
|
],
|
|
53
63
|
properties: {
|
|
54
64
|
className: [
|
|
55
|
-
'mb-2 text-sm font-semibold tracking-wide'
|
|
65
|
+
'mb-2 flex items-center gap-2 text-sm font-semibold tracking-wide'
|
|
56
66
|
],
|
|
57
67
|
dataDirectiveTitle: 'callout'
|
|
58
68
|
},
|
|
@@ -79,11 +89,12 @@ export const calloutDirective = {
|
|
|
79
89
|
editor: {
|
|
80
90
|
detail: 'Static directive',
|
|
81
91
|
label: 'Callout',
|
|
82
|
-
snippet: ':::callout
|
|
92
|
+
snippet: ':::callout[${Title}]{\n variant="${note}"\n}\n${Content}\n:::\n${}'
|
|
83
93
|
},
|
|
84
94
|
getMdastRenderProperties (node) {
|
|
85
95
|
return {
|
|
86
96
|
dataDirective: 'callout',
|
|
97
|
+
dataIcon: typeof node.attributes?.icon === 'string' ? node.attributes.icon : undefined,
|
|
87
98
|
dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'soft',
|
|
88
99
|
dataTitle: getTitle(node),
|
|
89
100
|
dataVariant: resolveCalloutVariant(node)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/directives/definitions/callout.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 CALLOUT_VARIANTS = [\n 'note',\n 'info',\n 'tip',\n 'warning',\n 'danger',\n 'success',\n] as const\n\nexport type CalloutVariant = (typeof CALLOUT_VARIANTS)[number]\n\nconst calloutVariantClasses: Record<CalloutVariant, string> = {\n danger: 'bg-red-500/10 text-red-50',\n info: 'bg-sky-500/10 text-sky-50',\n note: 'bg-slate-500/10 text-slate-50',\n success: 'bg-emerald-500/10 text-emerald-50',\n tip: 'bg-cyan-500/10 text-cyan-50',\n warning: 'bg-amber-500/10 text-amber-50',\n}\n\nfunction isCalloutVariant(value: unknown): value is CalloutVariant {\n return typeof value === 'string' && CALLOUT_VARIANTS.includes(value as CalloutVariant)\n}\n\nexport function resolveCalloutVariant(node: ContainerDirective): CalloutVariant {\n const variant = node.attributes?.variant\n\n return isCalloutVariant(variant) ? variant : 'note'\n}\n\nfunction getTitle(node: ContainerDirective): string | undefined {\n
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/definitions/callout.ts"],"sourcesContent":["import type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { makeDirectiveIconPlaceholder } from '../iconPlaceholder.js'\nimport { getDirectiveLabelOrAttribute } from '../labels.js'\nimport { resolveDirectiveTheme } from '../themes.js'\n\nexport const CALLOUT_VARIANTS = [\n 'note',\n 'info',\n 'tip',\n 'warning',\n 'danger',\n 'success',\n] as const\n\nexport type CalloutVariant = (typeof CALLOUT_VARIANTS)[number]\n\nconst calloutVariantClasses: Record<CalloutVariant, string> = {\n danger: 'bg-red-500/10 text-red-50',\n info: 'bg-sky-500/10 text-sky-50',\n note: 'bg-slate-500/10 text-slate-50',\n success: 'bg-emerald-500/10 text-emerald-50',\n tip: 'bg-cyan-500/10 text-cyan-50',\n warning: 'bg-amber-500/10 text-amber-50',\n}\n\nfunction isCalloutVariant(value: unknown): value is CalloutVariant {\n return typeof value === 'string' && CALLOUT_VARIANTS.includes(value as CalloutVariant)\n}\n\nexport function resolveCalloutVariant(node: ContainerDirective): CalloutVariant {\n const variant = node.attributes?.variant\n\n return isCalloutVariant(variant) ? variant : 'note'\n}\n\nfunction getTitle(node: ContainerDirective): string | undefined {\n return getDirectiveLabelOrAttribute(node, 'title')\n}\n\nexport const calloutDirective: LayoutDirectiveDefinition = {\n name: 'callout',\n allowedAttributes: ['icon', 'theme', 'title', 'variant'],\n applyHast(node, config, { mergeClassNames }) {\n const variant = typeof node.properties.dataVariant === 'string' ? node.properties.dataVariant : 'note'\n const title = typeof node.properties.dataTitle === 'string' ? node.properties.dataTitle : undefined\n const icon = typeof node.properties.dataIcon === 'string' ? node.properties.dataIcon : undefined\n const theme = resolveDirectiveTheme(\n 'callout',\n typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : 'soft',\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 calloutVariantClasses[isCalloutVariant(variant) ? variant : 'note'],\n )\n\n node.children = [\n ...(title || icon\n ? [\n {\n type: 'element' as const,\n children: [\n ...(icon\n ? [\n makeDirectiveIconPlaceholder(icon, [\n 'pmd-callout__icon inline-flex size-4 shrink-0 text-current',\n ]),\n ]\n : []),\n ...(title ? [{ type: 'text' as const, value: title }] : []),\n ],\n properties: {\n className: ['mb-2 flex items-center gap-2 text-sm font-semibold tracking-wide'],\n dataDirectiveTitle: 'callout',\n },\n tagName: 'div',\n },\n ]\n : []),\n {\n type: 'element',\n children,\n properties: {\n className: ['space-y-3 [&>:first-child]:mt-0 [&>:last-child]:mb-0'],\n dataDirectiveBody: 'callout',\n },\n tagName: 'div',\n },\n ]\n },\n defaultAttributes: {\n variant: 'note',\n },\n description: 'Emphasized content block with note, info, tip, warning, danger, or success variants.',\n editor: {\n detail: 'Static directive',\n label: 'Callout',\n snippet: ':::callout[${Title}]{\\n variant=\"${note}\"\\n}\\n${Content}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDirective: 'callout',\n dataIcon: typeof node.attributes?.icon === 'string' ? node.attributes.icon : undefined,\n dataTheme: typeof node.attributes?.theme === 'string' ? node.attributes.theme : 'soft',\n dataTitle: getTitle(node),\n dataVariant: resolveCalloutVariant(node),\n }\n },\n kind: 'callout',\n openMarker: ':::callout',\n public: true,\n supportsAttributes: true,\n tagName: 'div',\n themeAttributes: {\n theme: 'callout',\n },\n validateAttributes({ attributes }) {\n const warnings: string[] = []\n\n if (typeof attributes.variant === 'string' && !isCalloutVariant(attributes.variant))\n warnings.push(\n `Unsupported callout variant \"${attributes.variant}\". Falling back to \"note\".`,\n )\n\n return warnings\n },\n}\n"],"names":["makeDirectiveIconPlaceholder","getDirectiveLabelOrAttribute","resolveDirectiveTheme","CALLOUT_VARIANTS","calloutVariantClasses","danger","info","note","success","tip","warning","isCalloutVariant","value","includes","resolveCalloutVariant","node","variant","attributes","getTitle","calloutDirective","name","allowedAttributes","applyHast","config","mergeClassNames","properties","dataVariant","title","dataTitle","undefined","icon","dataIcon","theme","dataTheme","themes","children","className","hookClassName","modifierClassName","classes","type","dataDirectiveTitle","tagName","dataDirectiveBody","defaultAttributes","description","editor","detail","label","snippet","getMdastRenderProperties","dataDirective","kind","openMarker","public","supportsAttributes","themeAttributes","validateAttributes","warnings","push"],"mappings":"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"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { LayoutDirectiveDefinition } from '../types.js';
|
|
2
2
|
export declare const CARD_BODY_CLASS_NAMES = "space-y-3 [&>:first-child]:mt-0 [&>:last-child]:mb-0";
|
|
3
3
|
export declare const CARD_TITLE_CLASS_NAMES = "mb-3 text-lg font-semibold tracking-tight";
|
|
4
|
+
export declare const CARD_LINK_SCOPES: readonly ["full", "title"];
|
|
5
|
+
export declare const DEFAULT_CARD_LINK_SCOPE = "full";
|
|
6
|
+
export type CardLinkScope = (typeof CARD_LINK_SCOPES)[number];
|
|
7
|
+
export declare function isCardLinkScope(value: unknown): value is CardLinkScope;
|
|
4
8
|
export declare const cardDirective: LayoutDirectiveDefinition;
|
|
@@ -1,11 +1,42 @@
|
|
|
1
|
+
import { makeDirectiveIconPlaceholder } from '../iconPlaceholder.js';
|
|
2
|
+
import { getDirectiveLabelOrAttribute } from '../labels.js';
|
|
1
3
|
import { resolveDirectiveTheme } from '../themes.js';
|
|
2
4
|
export const CARD_BODY_CLASS_NAMES = 'space-y-3 [&>:first-child]:mt-0 [&>:last-child]:mb-0';
|
|
3
5
|
export const CARD_TITLE_CLASS_NAMES = 'mb-3 text-lg font-semibold tracking-tight';
|
|
6
|
+
export const CARD_LINK_SCOPES = [
|
|
7
|
+
'full',
|
|
8
|
+
'title'
|
|
9
|
+
];
|
|
10
|
+
export const DEFAULT_CARD_LINK_SCOPE = 'full';
|
|
11
|
+
export function isCardLinkScope(value) {
|
|
12
|
+
return typeof value === 'string' && CARD_LINK_SCOPES.includes(value);
|
|
13
|
+
}
|
|
4
14
|
function getAttribute(node, name) {
|
|
5
15
|
const value = node.attributes?.[name];
|
|
6
16
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
7
17
|
}
|
|
8
|
-
function
|
|
18
|
+
function getBooleanAttribute(node, name) {
|
|
19
|
+
const attributes = node.attributes;
|
|
20
|
+
const value = attributes?.[name];
|
|
21
|
+
if (value === true) return true;
|
|
22
|
+
if (typeof value !== 'string') return false;
|
|
23
|
+
return value === 'true';
|
|
24
|
+
}
|
|
25
|
+
function getLinkScope(node) {
|
|
26
|
+
const value = node.attributes?.linkScope;
|
|
27
|
+
if (typeof value !== 'string') return undefined;
|
|
28
|
+
return isCardLinkScope(value) ? value : DEFAULT_CARD_LINK_SCOPE;
|
|
29
|
+
}
|
|
30
|
+
function getLinkProperties(href, newTab) {
|
|
31
|
+
return {
|
|
32
|
+
href,
|
|
33
|
+
...newTab ? {
|
|
34
|
+
rel: 'noopener noreferrer',
|
|
35
|
+
target: '_blank'
|
|
36
|
+
} : {}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function makeTitle(title, href, newTab = false) {
|
|
9
40
|
const children = href ? [
|
|
10
41
|
{
|
|
11
42
|
type: 'element',
|
|
@@ -15,9 +46,7 @@ function makeTitle(title, href) {
|
|
|
15
46
|
value: title
|
|
16
47
|
}
|
|
17
48
|
],
|
|
18
|
-
properties:
|
|
19
|
-
href
|
|
20
|
-
},
|
|
49
|
+
properties: getLinkProperties(href, newTab),
|
|
21
50
|
tagName: 'a'
|
|
22
51
|
}
|
|
23
52
|
] : [
|
|
@@ -38,6 +67,21 @@ function makeTitle(title, href) {
|
|
|
38
67
|
tagName: 'h3'
|
|
39
68
|
};
|
|
40
69
|
}
|
|
70
|
+
function makeFullCardLink(href, title, newTab) {
|
|
71
|
+
return {
|
|
72
|
+
type: 'element',
|
|
73
|
+
children: [],
|
|
74
|
+
properties: {
|
|
75
|
+
...getLinkProperties(href, newTab),
|
|
76
|
+
ariaLabel: title ? `Open ${title}` : 'Open card',
|
|
77
|
+
className: [
|
|
78
|
+
'absolute inset-0 z-10 rounded-[inherit] focus:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300'
|
|
79
|
+
],
|
|
80
|
+
dataDirectiveLink: 'card'
|
|
81
|
+
},
|
|
82
|
+
tagName: 'a'
|
|
83
|
+
};
|
|
84
|
+
}
|
|
41
85
|
function makeEyebrow(eyebrow) {
|
|
42
86
|
return {
|
|
43
87
|
type: 'element',
|
|
@@ -61,23 +105,41 @@ export const cardDirective = {
|
|
|
61
105
|
allowedAttributes: [
|
|
62
106
|
'eyebrow',
|
|
63
107
|
'href',
|
|
108
|
+
'icon',
|
|
109
|
+
'linkScope',
|
|
110
|
+
'newTab',
|
|
64
111
|
'theme',
|
|
65
112
|
'title'
|
|
66
113
|
],
|
|
67
114
|
applyHast (node, config, { mergeClassNames }) {
|
|
68
115
|
const title = typeof node.properties.dataTitle === 'string' ? node.properties.dataTitle : undefined;
|
|
69
116
|
const href = typeof node.properties.dataHref === 'string' ? node.properties.dataHref : undefined;
|
|
117
|
+
const linkScope = typeof node.properties.dataLinkScope === 'string' && isCardLinkScope(node.properties.dataLinkScope) ? node.properties.dataLinkScope : DEFAULT_CARD_LINK_SCOPE;
|
|
118
|
+
const newTab = node.properties.dataNewTab === 'true';
|
|
70
119
|
const eyebrow = typeof node.properties.dataEyebrow === 'string' ? node.properties.dataEyebrow : undefined;
|
|
120
|
+
const icon = typeof node.properties.dataIcon === 'string' ? node.properties.dataIcon : undefined;
|
|
71
121
|
const theme = resolveDirectiveTheme('card', typeof node.properties.dataTheme === 'string' ? node.properties.dataTheme : undefined, config.themes);
|
|
72
122
|
const children = node.children;
|
|
73
123
|
node.properties.dataTheme = theme.name;
|
|
74
|
-
|
|
124
|
+
if (href) {
|
|
125
|
+
node.properties.dataLinkScope = linkScope;
|
|
126
|
+
node.properties.dataNewTab = newTab ? 'true' : 'false';
|
|
127
|
+
}
|
|
128
|
+
node.properties.className = mergeClassNames('not-prose', href && linkScope === 'full' ? 'relative cursor-pointer [&_a:not([data-directive-link])]:relative [&_a:not([data-directive-link])]:z-20' : undefined, theme.hookClassName, theme.modifierClassName, theme.classes);
|
|
75
129
|
node.children = [
|
|
130
|
+
...href && linkScope === 'full' ? [
|
|
131
|
+
makeFullCardLink(href, title, newTab)
|
|
132
|
+
] : [],
|
|
76
133
|
...eyebrow ? [
|
|
77
134
|
makeEyebrow(eyebrow)
|
|
78
135
|
] : [],
|
|
136
|
+
...icon ? [
|
|
137
|
+
makeDirectiveIconPlaceholder(icon, [
|
|
138
|
+
'pmd-card__icon mb-3 inline-flex size-5 text-current'
|
|
139
|
+
])
|
|
140
|
+
] : [],
|
|
79
141
|
...title ? [
|
|
80
|
-
makeTitle(title, href)
|
|
142
|
+
makeTitle(title, href && linkScope === 'title' ? href : undefined, newTab)
|
|
81
143
|
] : [],
|
|
82
144
|
{
|
|
83
145
|
type: 'element',
|
|
@@ -92,19 +154,33 @@ export const cardDirective = {
|
|
|
92
154
|
}
|
|
93
155
|
];
|
|
94
156
|
},
|
|
95
|
-
|
|
157
|
+
attributeValues: {
|
|
158
|
+
linkScope: CARD_LINK_SCOPES,
|
|
159
|
+
newTab: [
|
|
160
|
+
'true',
|
|
161
|
+
'false'
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
defaultAttributes: {
|
|
165
|
+
linkScope: DEFAULT_CARD_LINK_SCOPE,
|
|
166
|
+
newTab: 'false'
|
|
167
|
+
},
|
|
168
|
+
description: 'Card content block with optional title, eyebrow, and card link.',
|
|
96
169
|
editor: {
|
|
97
170
|
detail: 'Layout directive',
|
|
98
171
|
label: 'Card',
|
|
99
|
-
snippet: ':::card
|
|
172
|
+
snippet: ':::card[${Title}]\n${Content}\n:::\n${}'
|
|
100
173
|
},
|
|
101
174
|
getMdastRenderProperties (node) {
|
|
102
175
|
return {
|
|
103
176
|
dataDirective: 'card',
|
|
104
177
|
dataEyebrow: getAttribute(node, 'eyebrow'),
|
|
105
178
|
dataHref: getAttribute(node, 'href'),
|
|
179
|
+
dataIcon: getAttribute(node, 'icon'),
|
|
180
|
+
dataLinkScope: getLinkScope(node),
|
|
181
|
+
dataNewTab: 'newTab' in (node.attributes ?? {}) ? getBooleanAttribute(node, 'newTab') ? 'true' : 'false' : undefined,
|
|
106
182
|
dataTheme: getAttribute(node, 'theme'),
|
|
107
|
-
dataTitle:
|
|
183
|
+
dataTitle: getDirectiveLabelOrAttribute(node, 'title')
|
|
108
184
|
};
|
|
109
185
|
},
|
|
110
186
|
kind: 'card',
|
|
@@ -114,6 +190,11 @@ export const cardDirective = {
|
|
|
114
190
|
tagName: 'article',
|
|
115
191
|
themeAttributes: {
|
|
116
192
|
theme: 'card'
|
|
193
|
+
},
|
|
194
|
+
validateAttributes ({ attributes }) {
|
|
195
|
+
const warnings = [];
|
|
196
|
+
if (typeof attributes.linkScope === 'string' && !isCardLinkScope(attributes.linkScope)) warnings.push(`Invalid card linkScope "${attributes.linkScope}". Falling back to "${DEFAULT_CARD_LINK_SCOPE}".`);
|
|
197
|
+
return warnings;
|
|
117
198
|
}
|
|
118
199
|
};
|
|
119
200
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/directives/definitions/card.ts"],"sourcesContent":["import type { Element, ElementContent } from 'hast'\nimport type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { resolveDirectiveTheme } from '../themes.js'\n\nexport const CARD_BODY_CLASS_NAMES = 'space-y-3 [&>:first-child]:mt-0 [&>:last-child]:mb-0'\nexport const CARD_TITLE_CLASS_NAMES = 'mb-3 text-lg font-semibold tracking-tight'\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 makeTitle(title: string, href?: string): Element {\n const children: ElementContent[] = href\n ? [\n {\n type: 'element',\n children: [{ type: 'text', value: title }],\n properties: {\n href,\n },\n tagName: 'a',\n },\n ]\n : [{ type: 'text', value: title }]\n\n return {\n type: 'element',\n children,\n properties: {\n className: [CARD_TITLE_CLASS_NAMES],\n dataDirectiveTitle: 'card',\n },\n tagName: 'h3',\n }\n}\n\nfunction makeEyebrow(eyebrow: string): Element {\n return {\n type: 'element',\n children: [{ type: 'text', value: eyebrow }],\n properties: {\n className: ['mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground'],\n dataDirectiveEyebrow: 'card',\n },\n tagName: 'p',\n }\n}\n\nexport const cardDirective: LayoutDirectiveDefinition = {\n name: 'card',\n allowedAttributes: ['eyebrow', 'href', 'theme', 'title'],\n applyHast(node, config, { mergeClassNames }) {\n const title = typeof node.properties.dataTitle === 'string' ? node.properties.dataTitle : undefined\n const href = typeof node.properties.dataHref === 'string' ? node.properties.dataHref : undefined\n const eyebrow =\n typeof node.properties.dataEyebrow === 'string' ? node.properties.dataEyebrow : undefined\n const theme = resolveDirectiveTheme(\n 'card',\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 node.children = [\n ...(eyebrow ? [makeEyebrow(eyebrow)] : []),\n ...(title ? [makeTitle(title, href)] : []),\n {\n type: 'element',\n children,\n properties: {\n className: [CARD_BODY_CLASS_NAMES],\n dataDirectiveBody: 'card',\n },\n tagName: 'div',\n },\n ]\n },\n description: 'Card content block with optional title, eyebrow, and title link.',\n editor: {\n detail: 'Layout directive',\n label: 'Card',\n snippet: ':::card {title=\"${Title}\"}\\n${Content}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDirective: 'card',\n dataEyebrow: getAttribute(node, 'eyebrow'),\n dataHref: getAttribute(node, 'href'),\n dataTheme: getAttribute(node, 'theme'),\n dataTitle: getAttribute(node, 'title'),\n }\n },\n kind: 'card',\n openMarker: ':::card',\n public: true,\n supportsAttributes: true,\n tagName: 'article',\n themeAttributes: {\n theme: 'card',\n },\n}\n"],"names":["resolveDirectiveTheme","CARD_BODY_CLASS_NAMES","CARD_TITLE_CLASS_NAMES","getAttribute","node","name","value","attributes","trim","undefined","makeTitle","title","href","children","type","properties","tagName","className","dataDirectiveTitle","makeEyebrow","eyebrow","dataDirectiveEyebrow","cardDirective","allowedAttributes","applyHast","config","mergeClassNames","dataTitle","dataHref","dataEyebrow","theme","dataTheme","themes","hookClassName","modifierClassName","classes","dataDirectiveBody","description","editor","detail","label","snippet","getMdastRenderProperties","dataDirective","kind","openMarker","public","supportsAttributes","themeAttributes"],"mappings":"AAKA,SAASA,qBAAqB,QAAQ,eAAc;AAEpD,OAAO,MAAMC,wBAAwB,uDAAsD;AAC3F,OAAO,MAAMC,yBAAyB,4CAA2C;AAEjF,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,SAASC,UAAUC,KAAa,EAAEC,IAAa;IAC7C,MAAMC,WAA6BD,OAC/B;QACE;YACEE,MAAM;YACND,UAAU;gBAAC;oBAAEC,MAAM;oBAAQR,OAAOK;gBAAM;aAAE;YAC1CI,YAAY;gBACVH;YACF;YACAI,SAAS;QACX;KACD,GACD;QAAC;YAAEF,MAAM;YAAQR,OAAOK;QAAM;KAAE;IAEpC,OAAO;QACLG,MAAM;QACND;QACAE,YAAY;YACVE,WAAW;gBAACf;aAAuB;YACnCgB,oBAAoB;QACtB;QACAF,SAAS;IACX;AACF;AAEA,SAASG,YAAYC,OAAe;IAClC,OAAO;QACLN,MAAM;QACND,UAAU;YAAC;gBAAEC,MAAM;gBAAQR,OAAOc;YAAQ;SAAE;QAC5CL,YAAY;YACVE,WAAW;gBAAC;aAA+E;YAC3FI,sBAAsB;QACxB;QACAL,SAAS;IACX;AACF;AAEA,OAAO,MAAMM,gBAA2C;IACtDjB,MAAM;IACNkB,mBAAmB;QAAC;QAAW;QAAQ;QAAS;KAAQ;IACxDC,WAAUpB,IAAI,EAAEqB,MAAM,EAAE,EAAEC,eAAe,EAAE;QACzC,MAAMf,QAAQ,OAAOP,KAAKW,UAAU,CAACY,SAAS,KAAK,WAAWvB,KAAKW,UAAU,CAACY,SAAS,GAAGlB;QAC1F,MAAMG,OAAO,OAAOR,KAAKW,UAAU,CAACa,QAAQ,KAAK,WAAWxB,KAAKW,UAAU,CAACa,QAAQ,GAAGnB;QACvF,MAAMW,UACJ,OAAOhB,KAAKW,UAAU,CAACc,WAAW,KAAK,WAAWzB,KAAKW,UAAU,CAACc,WAAW,GAAGpB;QAClF,MAAMqB,QAAQ9B,sBACZ,QACA,OAAOI,KAAKW,UAAU,CAACgB,SAAS,KAAK,WAAW3B,KAAKW,UAAU,CAACgB,SAAS,GAAGtB,WAC5EgB,OAAOO,MAAM;QAEf,MAAMnB,WAAWT,KAAKS,QAAQ;QAE9BT,KAAKW,UAAU,CAACgB,SAAS,GAAGD,MAAMzB,IAAI;QACtCD,KAAKW,UAAU,CAACE,SAAS,GAAGS,gBAC1B,aACAI,MAAMG,aAAa,EACnBH,MAAMI,iBAAiB,EACvBJ,MAAMK,OAAO;QAEf/B,KAAKS,QAAQ,GAAG;eACVO,UAAU;gBAACD,YAAYC;aAAS,GAAG,EAAE;eACrCT,QAAQ;gBAACD,UAAUC,OAAOC;aAAM,GAAG,EAAE;YACzC;gBACEE,MAAM;gBACND;gBACAE,YAAY;oBACVE,WAAW;wBAAChB;qBAAsB;oBAClCmC,mBAAmB;gBACrB;gBACApB,SAAS;YACX;SACD;IACH;IACAqB,aAAa;IACbC,QAAQ;QACNC,QAAQ;QACRC,OAAO;QACPC,SAAS;IACX;IACAC,0BAAyBtC,IAAI;QAC3B,OAAO;YACLuC,eAAe;YACfd,aAAa1B,aAAaC,MAAM;YAChCwB,UAAUzB,aAAaC,MAAM;YAC7B2B,WAAW5B,aAAaC,MAAM;YAC9BuB,WAAWxB,aAAaC,MAAM;QAChC;IACF;IACAwC,MAAM;IACNC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpB/B,SAAS;IACTgC,iBAAiB;QACflB,OAAO;IACT;AACF,EAAC"}
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/definitions/card.ts"],"sourcesContent":["import type { Element, ElementContent } from 'hast'\nimport type { ContainerDirective } from 'mdast-util-directive'\n\nimport type { LayoutDirectiveDefinition } from '../types.js'\n\nimport { makeDirectiveIconPlaceholder } from '../iconPlaceholder.js'\nimport { getDirectiveLabelOrAttribute } from '../labels.js'\nimport { resolveDirectiveTheme } from '../themes.js'\n\nexport const CARD_BODY_CLASS_NAMES = 'space-y-3 [&>:first-child]:mt-0 [&>:last-child]:mb-0'\nexport const CARD_TITLE_CLASS_NAMES = 'mb-3 text-lg font-semibold tracking-tight'\nexport const CARD_LINK_SCOPES = ['full', 'title'] as const\nexport const DEFAULT_CARD_LINK_SCOPE = 'full'\n\nexport type CardLinkScope = (typeof CARD_LINK_SCOPES)[number]\n\nexport function isCardLinkScope(value: unknown): value is CardLinkScope {\n return typeof value === 'string' && CARD_LINK_SCOPES.includes(value as CardLinkScope)\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 getLinkScope(node: ContainerDirective): CardLinkScope | undefined {\n const value = node.attributes?.linkScope\n\n if (typeof value !== 'string') return undefined\n\n return isCardLinkScope(value) ? value : DEFAULT_CARD_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 makeTitle(title: string, href?: string, newTab = false): Element {\n const children: ElementContent[] = href\n ? [\n {\n type: 'element',\n children: [{ type: 'text', value: title }],\n properties: getLinkProperties(href, newTab),\n tagName: 'a',\n },\n ]\n : [{ type: 'text', value: title }]\n\n return {\n type: 'element',\n children,\n properties: {\n className: [CARD_TITLE_CLASS_NAMES],\n dataDirectiveTitle: 'card',\n },\n tagName: 'h3',\n }\n}\n\nfunction makeFullCardLink(href: string, title: string | undefined, newTab: boolean): Element {\n return {\n type: 'element',\n children: [],\n properties: {\n ...getLinkProperties(href, newTab),\n ariaLabel: title ? `Open ${title}` : 'Open card',\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: 'card',\n },\n tagName: 'a',\n }\n}\n\nfunction makeEyebrow(eyebrow: string): Element {\n return {\n type: 'element',\n children: [{ type: 'text', value: eyebrow }],\n properties: {\n className: ['mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground'],\n dataDirectiveEyebrow: 'card',\n },\n tagName: 'p',\n }\n}\n\nexport const cardDirective: LayoutDirectiveDefinition = {\n name: 'card',\n allowedAttributes: ['eyebrow', 'href', 'icon', 'linkScope', 'newTab', 'theme', 'title'],\n applyHast(node, config, { mergeClassNames }) {\n const title = typeof node.properties.dataTitle === 'string' ? node.properties.dataTitle : undefined\n const href = typeof node.properties.dataHref === 'string' ? node.properties.dataHref : undefined\n const linkScope =\n typeof node.properties.dataLinkScope === 'string' && isCardLinkScope(node.properties.dataLinkScope)\n ? node.properties.dataLinkScope\n : DEFAULT_CARD_LINK_SCOPE\n const newTab = node.properties.dataNewTab === 'true'\n const eyebrow =\n typeof node.properties.dataEyebrow === 'string' ? node.properties.dataEyebrow : undefined\n const icon = typeof node.properties.dataIcon === 'string' ? node.properties.dataIcon : undefined\n const theme = resolveDirectiveTheme(\n 'card',\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 if (href) {\n node.properties.dataLinkScope = linkScope\n node.properties.dataNewTab = newTab ? 'true' : 'false'\n }\n node.properties.className = mergeClassNames(\n 'not-prose',\n href && linkScope === 'full' ? '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 )\n node.children = [\n ...(href && linkScope === 'full' ? [makeFullCardLink(href, title, newTab)] : []),\n ...(eyebrow ? [makeEyebrow(eyebrow)] : []),\n ...(icon\n ? [\n makeDirectiveIconPlaceholder(icon, [\n 'pmd-card__icon mb-3 inline-flex size-5 text-current',\n ]),\n ]\n : []),\n ...(title ? [makeTitle(title, href && linkScope === 'title' ? href : undefined, newTab)] : []),\n {\n type: 'element',\n children,\n properties: {\n className: [CARD_BODY_CLASS_NAMES],\n dataDirectiveBody: 'card',\n },\n tagName: 'div',\n },\n ]\n },\n attributeValues: {\n linkScope: CARD_LINK_SCOPES,\n newTab: ['true', 'false'],\n },\n defaultAttributes: {\n linkScope: DEFAULT_CARD_LINK_SCOPE,\n newTab: 'false',\n },\n description: 'Card content block with optional title, eyebrow, and card link.',\n editor: {\n detail: 'Layout directive',\n label: 'Card',\n snippet: ':::card[${Title}]\\n${Content}\\n:::\\n${}',\n },\n getMdastRenderProperties(node) {\n return {\n dataDirective: 'card',\n dataEyebrow: getAttribute(node, 'eyebrow'),\n dataHref: getAttribute(node, 'href'),\n dataIcon: getAttribute(node, 'icon'),\n dataLinkScope: getLinkScope(node),\n dataNewTab: 'newTab' in (node.attributes ?? {})\n ? getBooleanAttribute(node, 'newTab') ? 'true' : 'false'\n : undefined,\n dataTheme: getAttribute(node, 'theme'),\n dataTitle: getDirectiveLabelOrAttribute(node, 'title'),\n }\n },\n kind: 'card',\n openMarker: ':::card',\n public: true,\n supportsAttributes: true,\n tagName: 'article',\n themeAttributes: {\n theme: 'card',\n },\n validateAttributes({ attributes }) {\n const warnings: string[] = []\n\n if (typeof attributes.linkScope === 'string' && !isCardLinkScope(attributes.linkScope))\n warnings.push(\n `Invalid card linkScope \"${attributes.linkScope}\". Falling back to \"${DEFAULT_CARD_LINK_SCOPE}\".`,\n )\n\n return warnings\n },\n}\n"],"names":["makeDirectiveIconPlaceholder","getDirectiveLabelOrAttribute","resolveDirectiveTheme","CARD_BODY_CLASS_NAMES","CARD_TITLE_CLASS_NAMES","CARD_LINK_SCOPES","DEFAULT_CARD_LINK_SCOPE","isCardLinkScope","value","includes","getAttribute","node","name","attributes","trim","undefined","getBooleanAttribute","getLinkScope","linkScope","getLinkProperties","href","newTab","rel","target","makeTitle","title","children","type","properties","tagName","className","dataDirectiveTitle","makeFullCardLink","ariaLabel","dataDirectiveLink","makeEyebrow","eyebrow","dataDirectiveEyebrow","cardDirective","allowedAttributes","applyHast","config","mergeClassNames","dataTitle","dataHref","dataLinkScope","dataNewTab","dataEyebrow","icon","dataIcon","theme","dataTheme","themes","hookClassName","modifierClassName","classes","dataDirectiveBody","attributeValues","defaultAttributes","description","editor","detail","label","snippet","getMdastRenderProperties","dataDirective","kind","openMarker","public","supportsAttributes","themeAttributes","validateAttributes","warnings","push"],"mappings":"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"}
|
|
@@ -2,6 +2,10 @@ import type { ContainerDirective } from 'mdast-util-directive';
|
|
|
2
2
|
import type { LayoutDirectiveDefinition } from '../types.js';
|
|
3
3
|
export declare const CARD_GRID_COLUMNS: readonly ["1", "2", "3", "4", "auto"];
|
|
4
4
|
export declare const DEFAULT_CARD_GRID_COLUMNS = "3";
|
|
5
|
+
export declare const CARDS_LINK_SCOPES: readonly ["section", "card", "title"];
|
|
6
|
+
export declare const DEFAULT_CARDS_LINK_SCOPE = "section";
|
|
7
|
+
export declare const FALLBACK_CARDS_LINK_SCOPE = "card";
|
|
5
8
|
export type CardGridColumns = (typeof CARD_GRID_COLUMNS)[number];
|
|
9
|
+
export type CardsLinkScope = (typeof CARDS_LINK_SCOPES)[number];
|
|
6
10
|
export declare function resolveCardGridColumns(node: ContainerDirective): CardGridColumns;
|
|
7
11
|
export declare const cardsDirective: LayoutDirectiveDefinition;
|