@comark/vue 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Comark team and contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,24 @@
1
+ export declare const Binding: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
2
+ value: {
3
+ type: (ArrayConstructor | ObjectConstructor | StringConstructor | NumberConstructor | BooleanConstructor)[];
4
+ default: undefined;
5
+ };
6
+ defaultValue: {
7
+ type: StringConstructor;
8
+ default: undefined;
9
+ };
10
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
11
+ [key: string]: any;
12
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
13
+ value: {
14
+ type: (ArrayConstructor | ObjectConstructor | StringConstructor | NumberConstructor | BooleanConstructor)[];
15
+ default: undefined;
16
+ };
17
+ defaultValue: {
18
+ type: StringConstructor;
19
+ default: undefined;
20
+ };
21
+ }>> & Readonly<{}>, {
22
+ value: string | number | boolean | Record<string, any> | unknown[];
23
+ defaultValue: string;
24
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,23 @@
1
+ import { Text, computed, defineComponent, h } from 'vue';
2
+ export const Binding = defineComponent({
3
+ name: 'Binding',
4
+ props: {
5
+ value: {
6
+ type: [String, Number, Boolean, Object, Array],
7
+ default: undefined,
8
+ },
9
+ defaultValue: {
10
+ type: String,
11
+ default: undefined,
12
+ },
13
+ },
14
+ setup(props) {
15
+ const rendered = computed(() => {
16
+ if (props.value !== undefined && props.value !== null) {
17
+ return typeof props.value === 'object' ? JSON.stringify(props.value) : String(props.value);
18
+ }
19
+ return props.defaultValue ?? '';
20
+ });
21
+ return () => h(Text, rendered.value);
22
+ },
23
+ });
@@ -38,6 +38,10 @@ export interface ComarkProps {
38
38
  caret?: boolean | {
39
39
  class: string;
40
40
  };
41
+ /**
42
+ * Additional data to pass to the renderer
43
+ */
44
+ data?: Record<string, unknown>;
41
45
  }
42
46
  type ComarkComponent = ReturnType<typeof defineComponent<ComarkProps>>;
43
47
  /**
@@ -96,6 +96,13 @@ export const Comark = defineComponent({
96
96
  type: [Boolean, Object],
97
97
  default: false,
98
98
  },
99
+ /**
100
+ * Additional data to pass to the renderer
101
+ */
102
+ data: {
103
+ type: Object,
104
+ default: () => ({}),
105
+ },
99
106
  },
100
107
  async setup(props, ctx) {
101
108
  const markdown = computed(() => {
@@ -123,6 +130,7 @@ export const Comark = defineComponent({
123
130
  componentsManifest: props.componentsManifest,
124
131
  class: props.streaming ? 'comark-stream' : '',
125
132
  caret: props.caret,
133
+ data: props.data,
126
134
  });
127
135
  };
128
136
  },
@@ -26,6 +26,10 @@ export interface ComarkRendererProps {
26
26
  caret?: boolean | {
27
27
  class: string;
28
28
  };
29
+ /**
30
+ * Additional data to pass to the renderer
31
+ */
32
+ data?: Record<string, unknown>;
29
33
  }
30
34
  type ComarkRendererComponent = ReturnType<typeof defineComponent<ComarkRendererProps>>;
31
35
  /**
@@ -1,10 +1,8 @@
1
1
  import { computed, defineAsyncComponent, defineComponent, getCurrentInstance, h, inject, onErrorCaptured, ref, toRaw } from 'vue';
2
2
  import { findLastTextNodeAndAppendNode, getCaret } from "../utils/caret.js";
3
+ import { pascalCase, resolveAttributes } from 'comark/utils';
3
4
  // Cache for dynamically resolved components
4
5
  const asyncComponentCache = new Map();
5
- const camelize = (s) => s.replace(/-(\w)/g, (_, c) => c ? c.toUpperCase() : '');
6
- const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
7
- const pascalCase = (str) => capitalize(camelize(str));
8
6
  /**
9
7
  * Helper to get tag from a ComarkNode
10
8
  */
@@ -23,21 +21,6 @@ function getProps(node) {
23
21
  }
24
22
  return {};
25
23
  }
26
- function parsePropValue(value) {
27
- if (value === 'true')
28
- return true;
29
- if (value === 'false')
30
- return false;
31
- if (value === 'null')
32
- return null;
33
- try {
34
- return JSON.parse(value);
35
- }
36
- catch {
37
- // noop
38
- }
39
- return value;
40
- }
41
24
  /**
42
25
  * Helper to get children from a ComarkNode
43
26
  */
@@ -74,7 +57,7 @@ function resolveComponent(tag, components, componentsManifest) {
74
57
  /**
75
58
  * Render a single Comark node to Vue VNode
76
59
  */
77
- function renderNode(node, components = {}, key, componentsManifest, parent) {
60
+ function renderNode(node, components = {}, key, componentsManifest, parent, renderData = { frontmatter: {}, meta: {}, data: {}, props: {} }) {
78
61
  // Handle text nodes (strings)
79
62
  if (typeof node === 'string') {
80
63
  return node;
@@ -97,21 +80,16 @@ function renderNode(node, components = {}, key, componentsManifest, parent) {
97
80
  }
98
81
  }
99
82
  const component = customComponent || tag;
100
- // Prepare props
101
- // Prepare props use for...in instead of Object.entries() to avoid intermediate array allocation
83
+ // Resolve `:prefix` bindings and let Vue-specific attribute mapping run
84
+ // on top (e.g. `className` `class`).
85
+ const resolved = resolveAttributes(nodeProps, renderData, { parseJson: true });
102
86
  const props = {};
103
- for (const k in nodeProps) {
104
- if (k === '$') {
105
- continue;
106
- }
87
+ for (const k in resolved) {
107
88
  if (k === 'className') {
108
- props.class = nodeProps[k];
109
- }
110
- else if (k.charCodeAt(0) === 58 /* ':' */) {
111
- props[k.substring(1)] = parsePropValue(nodeProps[k]);
89
+ props.class = resolved[k];
112
90
  }
113
91
  else {
114
- props[k] = nodeProps[k];
92
+ props[k] = resolved[k];
115
93
  }
116
94
  }
117
95
  // @ts-expect-error - component might be a Vue component
@@ -125,6 +103,11 @@ function renderNode(node, components = {}, key, componentsManifest, parent) {
125
103
  if (node.length === 2) {
126
104
  return h(component, props);
127
105
  }
106
+ // Only shadow the parent's `props` scope when the current element has its
107
+ // own attributes. Bare wrappers (`<p>`, `<ul>`, `<li>`, …) must keep the
108
+ // parent's scope so bindings like `{{ props.x }}` reach across them.
109
+ const hasOwnAttrs = Object.keys(resolved).length > 0;
110
+ const childrenRenderData = hasOwnAttrs ? { ...renderData, props } : renderData;
128
111
  // Separate template elements (slots) from regular children
129
112
  const slots = {};
130
113
  const regularChildren = [];
@@ -154,12 +137,12 @@ function renderNode(node, components = {}, key, componentsManifest, parent) {
154
137
  if (slotName) {
155
138
  const slotChildren = getChildren(child);
156
139
  slots[slotName] = () => slotChildren
157
- .map((slotChild, idx) => renderNode(slotChild, components, idx, componentsManifest, node))
140
+ .map((slotChild, idx) => renderNode(slotChild, components, idx, componentsManifest, node, childrenRenderData))
158
141
  .filter((slotChild) => slotChild !== null);
159
142
  continue;
160
143
  }
161
144
  }
162
- const rendered = renderNode(child, components, i, componentsManifest, node);
145
+ const rendered = renderNode(child, components, i, componentsManifest, node, childrenRenderData);
163
146
  if (rendered !== null) {
164
147
  regularChildren.push(rendered);
165
148
  }
@@ -244,6 +227,13 @@ export const ComarkRenderer = defineComponent({
244
227
  type: [Boolean, Object],
245
228
  default: false,
246
229
  },
230
+ /**
231
+ * Additional data to pass to the renderer
232
+ */
233
+ data: {
234
+ type: Object,
235
+ default: () => ({}),
236
+ },
247
237
  },
248
238
  async setup(props) {
249
239
  const componentErrors = ref(new Set());
@@ -278,8 +268,14 @@ export const ComarkRenderer = defineComponent({
278
268
  nodes.push(caret.value);
279
269
  }
280
270
  }
271
+ const renderData = {
272
+ frontmatter: props.tree.frontmatter,
273
+ meta: props.tree.meta,
274
+ data: props.data || {},
275
+ props: {},
276
+ };
281
277
  const children = nodes
282
- .map((node, index) => renderNode(node, components.value, index, componentManifest))
278
+ .map((node, index) => renderNode(node, components.value, index, componentManifest, undefined, renderData))
283
279
  .filter((child) => child !== null);
284
280
  // Wrap in a fragment
285
281
  return h('div', { class: 'comark-content' }, children);
@@ -55,8 +55,8 @@ export declare const Mermaid: import("vue").DefineComponent<import("vue").Extrac
55
55
  };
56
56
  }>> & Readonly<{}>, {
57
57
  class: string;
58
+ width: string;
58
59
  theme: ThemeNames | DiagramColors;
59
60
  themeDark: ThemeNames | DiagramColors;
60
61
  height: string;
61
- width: string;
62
62
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -13,7 +13,7 @@ export const Mermaid = defineComponent({
13
13
  },
14
14
  height: {
15
15
  type: String,
16
- default: '400px',
16
+ default: 'auto',
17
17
  },
18
18
  width: {
19
19
  type: String,
@@ -0,0 +1,3 @@
1
+ export * from 'comark/plugins/binding';
2
+ export { default } from 'comark/plugins/binding';
3
+ export { Binding } from '../components/Binding.ts';
@@ -0,0 +1,3 @@
1
+ export * from 'comark/plugins/binding';
2
+ export { default } from 'comark/plugins/binding';
3
+ export { Binding } from "../components/Binding.js";
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/breaks';
2
+ export { default } from 'comark/plugins/breaks';
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/breaks';
2
+ export { default } from 'comark/plugins/breaks';
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/footnotes';
2
+ export { default } from 'comark/plugins/footnotes';
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/footnotes';
2
+ export { default } from 'comark/plugins/footnotes';
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/punctuation';
2
+ export { default } from 'comark/plugins/punctuation';
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/punctuation';
2
+ export { default } from 'comark/plugins/punctuation';
package/dist/vite.d.ts CHANGED
@@ -18,4 +18,6 @@ import type { Plugin } from 'vite';
18
18
  * })
19
19
  * ```
20
20
  */
21
- export default function comark(): Plugin;
21
+ export default function comark(opts?: {
22
+ prose?: boolean;
23
+ }): Plugin;
package/dist/vite.js CHANGED
@@ -5,7 +5,7 @@ import { existsSync } from 'node:fs';
5
5
  const runtimeDir = fileURLToPath(new URL('./utils', import.meta.url));
6
6
  function viteComarkSlot(node, context) {
7
7
  const isVueSlotWithUnwrap = node.tag === 'slot'
8
- && node.props.find(p => p.name === 'unwrap' || p.name === 'mdc-wunwrap' || (p.name === 'bind' && p.rawName === ':comark-unwrap'));
8
+ && node.props.find(p => p.name === 'unwrap' || p.name === 'mdc-unwrap' || (p.name === 'bind' && p.rawName === ':comark-unwrap'));
9
9
  if (isVueSlotWithUnwrap) {
10
10
  const transform = context.ssr
11
11
  ? context.nodeTransforms.find(nt => nt.name === 'ssrTransformSlotOutlet')
@@ -96,7 +96,7 @@ function generateComponentsModule(files) {
96
96
  * })
97
97
  * ```
98
98
  */
99
- export default function comark() {
99
+ export default function comark(opts = {}) {
100
100
  let proseDir;
101
101
  let proseFilesCache = null;
102
102
  async function resolveProseFiles() {
@@ -146,6 +146,8 @@ export default function comark() {
146
146
  return generateComponentsModule(files);
147
147
  },
148
148
  async transform(code) {
149
+ if (opts.prose === false)
150
+ return null;
149
151
  if (!code.includes('createApp') || !code.includes('.mount('))
150
152
  return null;
151
153
  // Skip if already injected
package/package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "name": "@comark/vue",
3
3
  "type": "module",
4
- "version": "0.2.1",
4
+ "version": "0.3.1",
5
5
  "description": "Vue components for Comark",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/comarkdown/comark.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/comarkdown/comark/issues"
12
+ },
13
+ "homepage": "https://comark.dev/rendering/vue",
6
14
  "exports": {
7
15
  ".": "./dist/index.js",
8
16
  "./vite": "./dist/vite.js",
@@ -21,17 +29,9 @@
21
29
  "publishConfig": {
22
30
  "access": "public"
23
31
  },
24
- "scripts": {
25
- "stub": "node ../../scripts/stub.mjs",
26
- "build": "tsc",
27
- "dev": "tsc --watch",
28
- "test": "vitest run",
29
- "prepack": "tsc",
30
- "release": "release-it"
31
- },
32
32
  "peerDependencies": {
33
33
  "beautiful-mermaid": "^1.1.3",
34
- "katex": "^0.16.33",
34
+ "katex": "^0.16.45",
35
35
  "shiki": "^4.0.0",
36
36
  "vue": "^3.5.0"
37
37
  },
@@ -47,7 +47,7 @@
47
47
  }
48
48
  },
49
49
  "dependencies": {
50
- "comark": "^0.2.1"
50
+ "comark": "^0.3.1"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@vue/compiler-core": "^3.5.32",
@@ -55,5 +55,12 @@
55
55
  "vite": "^8.0.8",
56
56
  "vitest": "^4.1.4",
57
57
  "vue": "^3.5.32"
58
+ },
59
+ "scripts": {
60
+ "stub": "node ../../scripts/stub.mjs",
61
+ "build": "tsc",
62
+ "dev": "tsc --watch",
63
+ "test": "vitest run",
64
+ "release": "release-it"
58
65
  }
59
- }
66
+ }