@qkix/chartkit-vue-renderer 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 qkix
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.
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @qkix/chartkit-vue-renderer
2
+
3
+ Vue 3 renderer for [Chartkit](https://www.npmjs.com/package/@qkix/chartkit-core)
4
+ charts. The chart is an **SVG built on the server** - a page with a chart on it
5
+ ships exactly as much chart library as a page without one: none.
6
+
7
+ ```bash
8
+ npm install @qkix/chartkit-vue-renderer
9
+ ```
10
+
11
+ Works in Nuxt (server-rendered, nothing to hydrate) and in any plain Vue 3 app.
12
+
13
+ ## A chart on its own
14
+
15
+ ```vue
16
+ <script setup lang="ts">
17
+ import { Chart, type ChartSpec } from '@qkix/chartkit-vue-renderer';
18
+
19
+ defineProps<{ spec: ChartSpec }>();
20
+ </script>
21
+
22
+ <template>
23
+ <Chart :spec="spec" locale="en-US" />
24
+ </template>
25
+ ```
26
+
27
+ | Prop | |
28
+ | ----------- | ------------------------------------------------------------------------------------------ |
29
+ | `spec` | the chart |
30
+ | `locale` | number formatting, worth passing explicitly when building on a server |
31
+ | `id-prefix` | prefix for the ids the accessible name points at - needed when a page holds several charts |
32
+
33
+ `class`, `style` and any other attribute you put on `<Chart>` land on the
34
+ wrapping element.
35
+
36
+ A spec that will not draw renders **nothing**, the same as any other broken
37
+ content. A half-drawn chart would look like real data.
38
+
39
+ ## A chart inside a Better Blocks document
40
+
41
+ ```vue
42
+ <script setup lang="ts">
43
+ import { BlocksRenderer } from '@qkix/better-blocks-vue-renderer';
44
+ import { chartBlockPlugin } from '@qkix/chartkit-vue-renderer';
45
+
46
+ defineProps<{ content: unknown }>();
47
+ </script>
48
+
49
+ <template>
50
+ <BlocksRenderer :content="content" :block-plugins="[chartBlockPlugin]" />
51
+ </template>
52
+ ```
53
+
54
+ Neither package knows the other's internals. Leave the plugin out and the chart
55
+ is not drawn, while the rest of the document renders normally - content is never
56
+ lost by a front end that has not been taught about charts.
57
+
58
+ Unlike the React plugin this is a constant rather than a factory: a Vue
59
+ component reads what it needs from its own props, so there is nothing to close
60
+ over.
61
+
62
+ Charts in one document get distinct id prefixes derived from their title, so
63
+ their accessible names never collide.
64
+
65
+ ## License
66
+
67
+ MIT
@@ -0,0 +1,12 @@
1
+ import { ChartSpec } from '@qkix/chartkit-core';
2
+ import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
3
+ type __VLS_Props = {
4
+ spec: ChartSpec;
5
+ /** Locale for number formatting. Worth passing explicitly when building on a server. */
6
+ locale?: string;
7
+ /** Prefix for the ids the accessible name points at. Needed when a page holds several charts. */
8
+ idPrefix?: string;
9
+ };
10
+ declare const _default: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>;
11
+ export default _default;
12
+ //# sourceMappingURL=Chart.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Chart.vue.d.ts","sourceRoot":"","sources":["../src/Chart.vue"],"names":[],"mappings":";AAqDA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAElE,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;;AAuDF,wBAMG"}
@@ -0,0 +1,11 @@
1
+ import { ChartSpec } from '@qkix/chartkit-core';
2
+ import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
3
+ type __VLS_Props = {
4
+ node: {
5
+ spec?: ChartSpec;
6
+ [attribute: string]: unknown;
7
+ };
8
+ };
9
+ declare const _default: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>;
10
+ export default _default;
11
+ //# sourceMappingURL=ChartBlock.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartBlock.vue.d.ts","sourceRoot":"","sources":["../src/ChartBlock.vue"],"names":[],"mappings":";AAgDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAIrD,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,SAAS,CAAC;QAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CAC1D,CAAC;;AAmEF,wBAMG"}
@@ -0,0 +1,64 @@
1
+ import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
2
+ import { ChartSpec } from '@qkix/chartkit-core';
3
+ /**
4
+ * Chartkit as a Better Blocks block plugin.
5
+ *
6
+ * `chartBlock` in `@qkix/chartkit-core` carries the framework-free half - the
7
+ * type, the validator, the migrator. This adds the Vue component.
8
+ *
9
+ * The `satisfies` below is the load-bearing line: chartkit-core writes its
10
+ * definition structurally rather than importing `BlockDefinition`, because a
11
+ * chart has no business depending on a rich-text document format. This package
12
+ * legitimately depends on both, so this is where the two are checked against
13
+ * each other.
14
+ */
15
+ /**
16
+ * The plugin to hand to `BlocksRenderer`'s `blockPlugins`.
17
+ *
18
+ * A constant rather than a factory, unlike the React one: a Vue component reads
19
+ * what it needs from its own props, so there is nothing to close over.
20
+ */
21
+ export declare const chartBlockPlugin: {
22
+ component: DefineComponent<{
23
+ node: {
24
+ spec?: ChartSpec;
25
+ [attribute: string]: unknown;
26
+ };
27
+ }, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<{
28
+ node: {
29
+ spec?: ChartSpec;
30
+ [attribute: string]: unknown;
31
+ };
32
+ }> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>;
33
+ type: string;
34
+ content: "void";
35
+ validate(node: {
36
+ type: string;
37
+ spec?: unknown;
38
+ [attribute: string]: unknown;
39
+ }, context: {
40
+ path: string;
41
+ fail: (path: string, message: string) => void;
42
+ }): void;
43
+ migrate(node: {
44
+ type: string;
45
+ spec?: unknown;
46
+ [attribute: string]: unknown;
47
+ }): {
48
+ status: "unchanged";
49
+ reason?: undefined;
50
+ node?: undefined;
51
+ } | {
52
+ status: "skipped";
53
+ reason: string;
54
+ node?: undefined;
55
+ } | {
56
+ status: "migrated";
57
+ node: {
58
+ spec: ChartSpec;
59
+ type: string;
60
+ };
61
+ reason?: undefined;
62
+ };
63
+ };
64
+ //# sourceMappingURL=blockPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blockPlugin.d.ts","sourceRoot":"","sources":["../src/blockPlugin.ts"],"names":[],"mappings":";;AAAA;;;;;;;;;;;GAWG;AAOH;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;gBAI+c,CAAC;;;;;gBAAD,CAAC;;;;;;;;YAAsoM,CAAC;;;;;;;;YAAihB,CAAC;;;;cAAsG,CAAC;YAAyB,CAAC;;;;YAAsF,CAAC;;;;;;;cAAmJ,CAAC;;CADx9O,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { default as Chart } from './Chart.vue';
2
+ export { chartBlockPlugin } from './blockPlugin';
3
+ export type { ChartSpec, ChartType, Series, ChartOptions } from '@qkix/chartkit-core';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjD,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.mjs ADDED
@@ -0,0 +1,41 @@
1
+ import { defineComponent as a, computed as o, openBlock as l, createElementBlock as p, mergeProps as u, createCommentVNode as i, createBlock as m } from "vue";
2
+ import { renderChart as d, chartBlock as h } from "@qkix/chartkit-core";
3
+ const _ = ["innerHTML"], f = /* @__PURE__ */ a({
4
+ inheritAttrs: !1,
5
+ __name: "Chart",
6
+ props: {
7
+ spec: {},
8
+ locale: {},
9
+ idPrefix: {}
10
+ },
11
+ setup(n) {
12
+ const r = n, e = o(
13
+ () => d(r.spec, { locale: r.locale, idPrefix: r.idPrefix })
14
+ ), t = o(() => e.value.ok ? e.value.svg : "");
15
+ return (s, c) => t.value ? (l(), p("div", u({ key: 0 }, s.$attrs, { innerHTML: t.value }), null, 16, _)) : i("", !0);
16
+ }
17
+ }), v = /* @__PURE__ */ a({
18
+ __name: "ChartBlock",
19
+ props: {
20
+ node: {}
21
+ },
22
+ setup(n) {
23
+ const r = n, e = o(() => r.node.spec), t = o(() => {
24
+ var c;
25
+ return `chartkit-${String(((c = e.value) == null ? void 0 : c.title) ?? "chart").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40) || "chart"}`;
26
+ });
27
+ return (s, c) => e.value ? (l(), m(f, {
28
+ key: 0,
29
+ spec: e.value,
30
+ "id-prefix": t.value
31
+ }, null, 8, ["spec", "id-prefix"])) : i("", !0);
32
+ }
33
+ }), x = {
34
+ ...h,
35
+ component: v
36
+ };
37
+ export {
38
+ f as Chart,
39
+ x as chartBlockPlugin
40
+ };
41
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/Chart.vue","../src/ChartBlock.vue","../src/blockPlugin.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A Chartkit chart, as a Vue component.\n *\n * The work happens in `@qkix/chartkit-core`, which turns a spec into a finished\n * SVG string. This is the thin part - and being thin is the point: the rendered\n * page carries an SVG and nothing else. No hydration work, no client-side chart\n * library, no bytes. The SVG is built synchronously, so the server and the\n * client produce identical markup.\n */\nimport { computed } from 'vue';\n\nimport { renderChart, type ChartSpec } from '@qkix/chartkit-core';\n\nconst props = defineProps<{\n spec: ChartSpec;\n /** Locale for number formatting. Worth passing explicitly when building on a server. */\n locale?: string;\n /** Prefix for the ids the accessible name points at. Needed when a page holds several charts. */\n idPrefix?: string;\n}>();\n\n// `class`, `style` and anything else the consumer puts on <Chart> is bound to\n// the wrapper by hand, so nothing is left dangling when the chart draws nothing.\ndefineOptions({ inheritAttrs: false });\n\nconst result = computed(() =>\n renderChart(props.spec, { locale: props.locale, idPrefix: props.idPrefix })\n);\n\n// An invalid spec renders nothing, the same as any other broken content. A\n// half-drawn chart would look like real data, which is worse than an absence.\nconst svg = computed(() => (result.value.ok ? result.value.svg : ''));\n</script>\n\n<template>\n <!-- The markup is this library's own output, from a builder that escapes every\n author-controlled value on the way in - see chartkit-core's svg.ts. -->\n <div v-if=\"svg\" v-bind=\"$attrs\" v-html=\"svg\"></div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Adapts a Better Blocks chart node to the Chart component.\n *\n * Better Blocks hands a registered block its whole node, since it cannot know\n * what attributes the block has. Chart takes a spec. This is the one line\n * between them.\n */\nimport { computed } from 'vue';\n\nimport type { ChartSpec } from '@qkix/chartkit-core';\n\nimport Chart from './Chart.vue';\n\nconst props = defineProps<{\n node: { spec?: ChartSpec; [attribute: string]: unknown };\n}>();\n\nconst spec = computed(() => props.node.spec);\n\n// Charts in one document must not share the ids their accessible names point\n// at. There is no node id to lean on, so the title is the most stable thing\n// available.\nconst idPrefix = computed(() => {\n const slug =\n String(spec.value?.title ?? 'chart')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 40) || 'chart';\n return `chartkit-${slug}`;\n});\n</script>\n\n<template>\n <Chart v-if=\"spec\" :spec=\"spec\" :id-prefix=\"idPrefix\" />\n</template>\n","/**\n * Chartkit as a Better Blocks block plugin.\n *\n * `chartBlock` in `@qkix/chartkit-core` carries the framework-free half - the\n * type, the validator, the migrator. This adds the Vue component.\n *\n * The `satisfies` below is the load-bearing line: chartkit-core writes its\n * definition structurally rather than importing `BlockDefinition`, because a\n * chart has no business depending on a rich-text document format. This package\n * legitimately depends on both, so this is where the two are checked against\n * each other.\n */\n\nimport type { VueBlockPlugin } from '@qkix/better-blocks-vue-renderer';\nimport { chartBlock } from '@qkix/chartkit-core';\n\nimport ChartBlock from './ChartBlock.vue';\n\n/**\n * The plugin to hand to `BlocksRenderer`'s `blockPlugins`.\n *\n * A constant rather than a factory, unlike the React one: a Vue component reads\n * what it needs from its own props, so there is nothing to close over.\n */\nexport const chartBlockPlugin = {\n ...chartBlock,\n component: ChartBlock,\n} satisfies VueBlockPlugin;\n"],"names":["props","__props","result","computed","renderChart","svg","_openBlock","_createElementBlock","_mergeProps","$attrs","_hoisted_1","spec","idPrefix","_a","_createBlock","Chart","chartBlockPlugin","chartBlock","ChartBlock"],"mappings":";;;;;;;;;;;AAcA,UAAMA,IAAQC,GAYRC,IAASC;AAAA,MAAS,MACtBC,EAAYJ,EAAM,MAAM,EAAE,QAAQA,EAAM,QAAQ,UAAUA,EAAM,SAAA,CAAU;AAAA,IAAA,GAKtEK,IAAMF,EAAS,MAAOD,EAAO,MAAM,KAAKA,EAAO,MAAM,MAAM,EAAG;qBAMvDG,EAAA,SAAXC,EAAA,GAAAC,EAAmD,OAAnDC,EAAmD,EAAA,KAAA,EAAA,GAA3BC,UAAM,EAAE,WAAQJ,EAAA,MAAA,CAAG,GAAA,MAAA,IAAAK,CAAA;;;;;;;;ACxB7C,UAAMV,IAAQC,GAIRU,IAAOR,EAAS,MAAMH,EAAM,KAAK,IAAI,GAKrCY,IAAWT,EAAS,MAAM;;AAO9B,aAAO,YALL,SAAOU,IAAAF,EAAK,UAAL,gBAAAE,EAAY,UAAS,OAAO,EAChC,cACA,QAAQ,eAAe,GAAG,EAC1B,QAAQ,UAAU,EAAE,EACpB,MAAM,GAAG,EAAE,KAAK,OACE;AAAA,IACzB,CAAC;qBAIcF,EAAA,cAAbG,EAAwDC,GAAA;AAAA;MAApC,MAAMJ,EAAA;AAAA,MAAO,aAAWC,EAAA;AAAA,IAAA;;ICXjCI,IAAmB;AAAA,EAC9B,GAAGC;AAAA,EACH,WAAWC;AACb;"}
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "@qkix/chartkit-vue-renderer",
3
+ "version": "0.1.0",
4
+ "description": "Vue 3 renderer for Chartkit charts - server-rendered SVG with zero client-side JavaScript, and the Better Blocks block plugin that draws a chart inside a document",
5
+ "type": "module",
6
+ "types": "./dist/index.d.ts",
7
+ "module": "./dist/index.mjs",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.mjs"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@qkix/chartkit-core": "^0.2.4"
20
+ },
21
+ "peerDependencies": {
22
+ "@qkix/better-blocks-vue-renderer": ">=0.1.0",
23
+ "vue": ">=3.3.0"
24
+ },
25
+ "peerDependenciesMeta": {
26
+ "@qkix/better-blocks-vue-renderer": {
27
+ "optional": true
28
+ }
29
+ },
30
+ "devDependencies": {
31
+ "@vitejs/plugin-vue": "^5.2.1",
32
+ "@vue/test-utils": "^2.4.6",
33
+ "eslint": "^10.8.1",
34
+ "jsdom": "^25.0.1",
35
+ "prettier": "^3.4.2",
36
+ "typescript": "^5.7.2",
37
+ "vite": "^6.0.0",
38
+ "vite-plugin-dts": "^4.5.0",
39
+ "vitest": "^3.0.0",
40
+ "vue": "^3.5.13",
41
+ "vue-tsc": "^2.2.0",
42
+ "@qkix/eslint-config": "0.0.0",
43
+ "@qkix/better-blocks-vue-renderer": "^0.1.0",
44
+ "@qkix/tsconfig": "0.0.0"
45
+ },
46
+ "keywords": [
47
+ "chart",
48
+ "charts",
49
+ "svg",
50
+ "vue",
51
+ "vue3",
52
+ "nuxt",
53
+ "chartkit",
54
+ "strapi",
55
+ "ssr",
56
+ "zero-js"
57
+ ],
58
+ "license": "MIT",
59
+ "author": "qkix",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/qkix/strapi-plugins.git",
63
+ "directory": "packages/chartkit-vue-renderer"
64
+ },
65
+ "bugs": {
66
+ "url": "https://github.com/qkix/strapi-plugins/issues"
67
+ },
68
+ "homepage": "https://github.com/qkix/strapi-plugins#readme",
69
+ "engines": {
70
+ "node": ">=20.0.0 <=24.x.x",
71
+ "npm": ">=6.0.0"
72
+ },
73
+ "nx": {
74
+ "tags": [
75
+ "scope:renderer-extension"
76
+ ]
77
+ },
78
+ "publishConfig": {
79
+ "access": "public"
80
+ },
81
+ "scripts": {
82
+ "build": "vite build",
83
+ "clean": "rm -rf dist",
84
+ "lint": "eslint . && prettier --check .",
85
+ "format": "prettier --write .",
86
+ "test": "vitest run",
87
+ "test:watch": "vitest",
88
+ "typecheck": "vue-tsc --noEmit -p tsconfig.json"
89
+ }
90
+ }