comark-cards 0.0.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +69 -0
- package/README.md +53 -1
- package/dist/client-CONO3MxN.mjs +117 -0
- package/dist/client.d.mts +23 -0
- package/dist/client.mjs +1 -0
- package/dist/html.d.mts +7 -0
- package/dist/html.mjs +34 -0
- package/dist/index.d.mts +41 -0
- package/dist/index.mjs +193 -0
- package/dist/react.d.mts +49 -0
- package/dist/react.mjs +64 -0
- package/dist/style.css +1 -0
- package/dist/svelte/Card.svelte +21 -0
- package/dist/svelte/CardGroup.svelte +10 -0
- package/dist/svelte/CardTitle.svelte +6 -0
- package/dist/svelte/Column.svelte +6 -0
- package/dist/svelte/Columns.svelte +10 -0
- package/dist/svelte/index.d.ts +32 -0
- package/dist/svelte/index.js +11 -0
- package/dist/vue.d.mts +112 -0
- package/dist/vue.mjs +102 -0
- package/package.json +84 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 onmax
|
|
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.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
The icons are Lucide's (https://lucide.dev), under its license:
|
|
26
|
+
|
|
27
|
+
ISC License
|
|
28
|
+
|
|
29
|
+
Copyright (c) 2026 Lucide Icons and Contributors
|
|
30
|
+
|
|
31
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
32
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
33
|
+
copyright notice and this permission notice appear in all copies.
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
36
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
37
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
38
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
39
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
40
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
41
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
The following Lucide icons are derived from the Feather project:
|
|
46
|
+
|
|
47
|
+
airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out
|
|
48
|
+
|
|
49
|
+
The MIT License (MIT) (for the icons listed above)
|
|
50
|
+
|
|
51
|
+
Copyright (c) 2013-present Cole Bemis
|
|
52
|
+
|
|
53
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
54
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
55
|
+
in the Software without restriction, including without limitation the rights
|
|
56
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
57
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
58
|
+
furnished to do so, subject to the following conditions:
|
|
59
|
+
|
|
60
|
+
The above copyright notice and this permission notice shall be included in all
|
|
61
|
+
copies or substantial portions of the Software.
|
|
62
|
+
|
|
63
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
64
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
65
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
66
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
67
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
68
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
69
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,55 @@
|
|
|
1
1
|
# comark-cards
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://npmx.dev/package/comark-cards)
|
|
4
|
+
[](https://npmx.dev/package/comark-cards)
|
|
5
|
+
[](https://npmx.dev/package/comark-cards)
|
|
6
|
+
[](https://npmx.dev/package/comark-cards)
|
|
7
|
+
[](https://comark.onmax.me/cards/)
|
|
8
|
+
|
|
9
|
+
Cards, link cards, and columns in Nuxt UI's syntax, with no script. A [Comark](https://comark.dev) plugin for HTML, Vue, React, and Svelte.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pnpm add comark comark-cards
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createHtmlRenderer } from "@comark/html";
|
|
17
|
+
import cards, { components } from "comark-cards/html";
|
|
18
|
+
|
|
19
|
+
const render = createHtmlRenderer({ plugins: [cards()], components });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```md
|
|
23
|
+
::card-group
|
|
24
|
+
:::card{title="Guides" icon="lucide:book-open" to="/guides/"}
|
|
25
|
+
Start here.
|
|
26
|
+
:::
|
|
27
|
+
|
|
28
|
+
:::card{title="GitHub" to="https://github.com/onmax/comark-plugins" color="neutral"}
|
|
29
|
+
Read the code.
|
|
30
|
+
:::
|
|
31
|
+
::
|
|
32
|
+
|
|
33
|
+
::columns{cols="2"}
|
|
34
|
+
Left.
|
|
35
|
+
|
|
36
|
+
Right.
|
|
37
|
+
::
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`::card` takes `title` (or a `#title` slot), `description`, `icon`, `to`, `target`, and `color`. A card with `to` is covered by one link named after its title; a web address opens in a new tab. `::columns{cols}` makes a cell of each block inside, and `:::column` groups several. Icons resolve through comark-icon; pass `iconResolver` to share the page's.
|
|
41
|
+
|
|
42
|
+
The plugin adds every problem to `meta.issues`, so a host can reject a document before publishing it: `href` written instead of `to`, a script link, an unknown color, a `cols` outside 1 to 6, and an icon it can't draw. Each issue names its block and says how to fix it.
|
|
43
|
+
|
|
44
|
+
## Renderers
|
|
45
|
+
|
|
46
|
+
| Renderer | Import |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `@comark/html` | `comark-cards/html`: the styles are inlined once per document |
|
|
49
|
+
| `@comark/vue` | `comark-cards/vue` |
|
|
50
|
+
| `@comark/react` | `comark-cards/react` |
|
|
51
|
+
| `@comark/svelte` | `comark-cards/svelte` |
|
|
52
|
+
|
|
53
|
+
Each entry exports the parse plugin as `default` and the renderer's `components`. The Vue, React, and Svelte components add the styles when they mount; import `comark-cards/style.css` with your styles so a server-rendered page doesn't shift.
|
|
54
|
+
|
|
55
|
+
The styles follow shadcn/ui: they read its CSS variables, such as `--accent` and `--border`, when the page has them, and use its neutral theme otherwise, while colors read Nuxt UI's `--ui-*` variables. Set the shared `--comark-*` tokens to theme every plugin at once; the rules sit in a `comark` CSS layer, so any plain rule of your own wins.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
//#region ../zoom/dist/theme.mjs
|
|
2
|
+
const tokens = [
|
|
3
|
+
[
|
|
4
|
+
"background",
|
|
5
|
+
"background",
|
|
6
|
+
"#fff",
|
|
7
|
+
"#0a0a0a"
|
|
8
|
+
],
|
|
9
|
+
[
|
|
10
|
+
"foreground",
|
|
11
|
+
"foreground",
|
|
12
|
+
"#0a0a0a",
|
|
13
|
+
"#fafafa"
|
|
14
|
+
],
|
|
15
|
+
[
|
|
16
|
+
"muted",
|
|
17
|
+
"muted-foreground",
|
|
18
|
+
"#737373",
|
|
19
|
+
"#a1a1a1"
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
"border",
|
|
23
|
+
"border",
|
|
24
|
+
"#e5e5e5",
|
|
25
|
+
"rgb(255 255 255/.1)"
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
"accent",
|
|
29
|
+
"accent",
|
|
30
|
+
"#f5f5f5",
|
|
31
|
+
"#262626"
|
|
32
|
+
],
|
|
33
|
+
[
|
|
34
|
+
"ring",
|
|
35
|
+
"ring",
|
|
36
|
+
"#a1a1a1",
|
|
37
|
+
"#737373"
|
|
38
|
+
]
|
|
39
|
+
];
|
|
40
|
+
const resolve = (scheme) => tokens.map((token) => `--_comark-${token[0]}:var(--comark-${token[0]},var(--${token[1]},${token[scheme]}))`).join(";");
|
|
41
|
+
/**
|
|
42
|
+
* Resolves the `--comark-*` tokens on `selector`, falling back to shadcn/ui's variables and then to its neutral theme.
|
|
43
|
+
* They resolve on the component rather than `:root`, so a `.dark` class anywhere above it switches the theme, and a
|
|
44
|
+
* `--comark-*` set on any ancestor still inherits down. `:where()` keeps them at zero specificity.
|
|
45
|
+
*/
|
|
46
|
+
function theme(selector) {
|
|
47
|
+
const where = `:where(${selector})`;
|
|
48
|
+
return `${where}{${resolve(2)};--_comark-radius:var(--comark-radius,var(--radius,.625rem));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){${where}{${resolve(3)}}}`;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/styles.ts
|
|
52
|
+
/**
|
|
53
|
+
* Cards in the style of shadcn/ui's Card, two to a row in a group and one when the group is narrower than 36rem, and
|
|
54
|
+
* columns from `::columns`, on the shared `--comark-*` tokens. The group is a size container, so a group in a narrow
|
|
55
|
+
* column stacks whatever the screen's width. A card's color tints its icon and, on a link card, its hovered border;
|
|
56
|
+
* each reads Nuxt UI's `--ui-*` variable when the page has it, then `--ccr-*`. Primary and error fall back to shadcn/ui's
|
|
57
|
+
* `--primary` and `--destructive`, and primary then to the foreground, so a card is neutral like the other plugins until
|
|
58
|
+
* the page has a brand color. The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
|
|
59
|
+
*/
|
|
60
|
+
const css = `@layer comark{${[
|
|
61
|
+
theme(".ccr,.ccr-group,.ccr-columns"),
|
|
62
|
+
":where(.ccr){--ccr-primary:var(--ui-primary,var(--primary,var(--_comark-foreground)));--ccr-secondary:var(--ui-secondary,#2563eb);--ccr-success:var(--ui-success,#16a34a);--ccr-info:var(--ui-info,#2563eb);--ccr-warning:var(--ui-warning,#ca8a04);--ccr-error:var(--ui-error,var(--destructive,#dc2626));--ccr-neutral:var(--_comark-foreground)}",
|
|
63
|
+
"@media (prefers-color-scheme:dark){:where(.ccr){--ccr-secondary:var(--ui-secondary,#60a5fa);--ccr-success:var(--ui-success,#4ade80);--ccr-info:var(--ui-info,#60a5fa);--ccr-warning:var(--ui-warning,#facc15);--ccr-error:var(--ui-error,var(--destructive,#f87171))}}",
|
|
64
|
+
".ccr-group,.ccr-columns{display:grid;gap:1rem;margin:1.5rem 0;container-type:inline-size}",
|
|
65
|
+
".ccr-group{grid-template-columns:repeat(2,minmax(0,1fr))}",
|
|
66
|
+
...[
|
|
67
|
+
2,
|
|
68
|
+
3,
|
|
69
|
+
4,
|
|
70
|
+
5,
|
|
71
|
+
6
|
|
72
|
+
].map((cols) => `.ccr-columns[data-cols='${cols}']{grid-template-columns:repeat(${cols},minmax(0,1fr))}`),
|
|
73
|
+
"@container (width<36rem){.ccr-group>*,.ccr-columns>*{grid-column:1/-1}}",
|
|
74
|
+
".ccr-group>.ccr{margin:0}",
|
|
75
|
+
".ccr-column>:first-child{margin-top:0}",
|
|
76
|
+
".ccr-column>:last-child{margin-bottom:0}",
|
|
77
|
+
".ccr{--ccr:var(--ccr-primary);position:relative;margin:1.5rem 0;padding:1.25rem;border:1px solid var(--_comark-border);border-radius:calc(var(--_comark-radius) + 2px);background:var(--_comark-background);box-shadow:0 1px 2px rgb(0 0 0/.05);color:var(--_comark-muted);font:400 .875rem/1.375rem var(--_comark-font);transition:background-color .15s,border-color .15s}",
|
|
78
|
+
...[
|
|
79
|
+
"secondary",
|
|
80
|
+
"success",
|
|
81
|
+
"info",
|
|
82
|
+
"warning",
|
|
83
|
+
"error",
|
|
84
|
+
"neutral"
|
|
85
|
+
].map((color) => `.ccr[data-color='${color}']{--ccr:var(--ccr-${color})}`),
|
|
86
|
+
".ccr>:last-child{margin-bottom:0}",
|
|
87
|
+
".ccr>.ci{--comark-icon-size:1.25rem;display:block;margin-bottom:.75rem;color:var(--ccr)}",
|
|
88
|
+
".ccr-title{margin:0 0 .25rem;color:var(--_comark-foreground);font-size:.9375rem;font-weight:600;line-height:1.375rem;text-wrap:balance}",
|
|
89
|
+
".ccr-title+*{margin-top:0}",
|
|
90
|
+
".ccr-link{position:absolute;inset:0;z-index:0;border-radius:inherit}",
|
|
91
|
+
".ccr-link:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 50%,transparent)}",
|
|
92
|
+
".ccr :is(a,button):not(.ccr-link){position:relative;z-index:1}",
|
|
93
|
+
".ccr:has(>.ccr-link):hover{border-color:color-mix(in srgb,var(--ccr) 50%,var(--_comark-border));background:color-mix(in srgb,var(--_comark-accent) 50%,var(--_comark-background))}",
|
|
94
|
+
".ccr-external{position:absolute;top:1rem;inset-inline-end:1rem;width:1rem;height:1rem;color:var(--_comark-muted)}",
|
|
95
|
+
".ccr:dir(rtl) .ccr-external{scale:-1 1}",
|
|
96
|
+
"@media print{.ccr{break-inside:avoid}.ccr-external{display:none}}"
|
|
97
|
+
].join("")}}`;
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/client.ts
|
|
100
|
+
/** Adds the card styles to the page once. The Vue, React, and Svelte components call it when they mount. */
|
|
101
|
+
function addStyles() {
|
|
102
|
+
if (document.querySelector("style[data-comark-cards]")) return;
|
|
103
|
+
const style = document.createElement("style");
|
|
104
|
+
style.dataset.comarkCards = "";
|
|
105
|
+
style.textContent = css;
|
|
106
|
+
document.head.append(style);
|
|
107
|
+
}
|
|
108
|
+
/** Lucide's arrow-up-right (ISC), drawn in the corner of a card that opens in a new tab. */
|
|
109
|
+
const external = "M7 7h10v10M7 17 17 7";
|
|
110
|
+
/** Returns whether a card URL is safe to place in an href. */
|
|
111
|
+
const isSafeHref = (value) => !!value && !/^\s*(?:javascript|vbscript|data):/i.test(value);
|
|
112
|
+
/** Web URLs open in a new tab, including protocol-relative URLs. */
|
|
113
|
+
const isExternalHref = (value) => /^(?:https?:\/\/|\/\/)/i.test(value ?? "");
|
|
114
|
+
/** The `rel` of a link that opens in a new tab, so the page it opens can't reach back into this one. */
|
|
115
|
+
const rel = (target) => target === "_blank" ? "noopener noreferrer" : void 0;
|
|
116
|
+
//#endregion
|
|
117
|
+
export { rel as a, isSafeHref as i, external as n, css as o, isExternalHref as r, addStyles as t };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/styles.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Cards in the style of shadcn/ui's Card, two to a row in a group and one when the group is narrower than 36rem, and
|
|
4
|
+
* columns from `::columns`, on the shared `--comark-*` tokens. The group is a size container, so a group in a narrow
|
|
5
|
+
* column stacks whatever the screen's width. A card's color tints its icon and, on a link card, its hovered border;
|
|
6
|
+
* each reads Nuxt UI's `--ui-*` variable when the page has it, then `--ccr-*`. Primary and error fall back to shadcn/ui's
|
|
7
|
+
* `--primary` and `--destructive`, and primary then to the foreground, so a card is neutral like the other plugins until
|
|
8
|
+
* the page has a brand color. The rules sit in the `comark` layer, so any unlayered rule of the host's wins.
|
|
9
|
+
*/
|
|
10
|
+
export declare const css: string;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/client.d.ts
|
|
13
|
+
/** Adds the card styles to the page once. The Vue, React, and Svelte components call it when they mount. */
|
|
14
|
+
export declare function addStyles(): void;
|
|
15
|
+
/** Lucide's arrow-up-right (ISC), drawn in the corner of a card that opens in a new tab. */
|
|
16
|
+
export declare const external = "M7 7h10v10M7 17 17 7";
|
|
17
|
+
/** Returns whether a card URL is safe to place in an href. */
|
|
18
|
+
export declare const isSafeHref: (value?: string) => boolean;
|
|
19
|
+
/** Web URLs open in a new tab, including protocol-relative URLs. */
|
|
20
|
+
export declare const isExternalHref: (value?: string) => boolean;
|
|
21
|
+
/** The `rel` of a link that opens in a new tab, so the page it opens can't reach back into this one. */
|
|
22
|
+
export declare const rel: (target?: string) => string | undefined;
|
|
23
|
+
//#endregion
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { t as addStyles, o as css, n as external, r as isExternalHref, i as isSafeHref, a as rel } from "./client-CONO3MxN.mjs";
|
package/dist/html.d.mts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import _default, { CardAttributes, CardColor, CardsMeta, CardsOptions, ColumnsAttributes, colors } from "./index.mjs";
|
|
2
|
+
import { NodeHandler } from "comark";
|
|
3
|
+
//#region src/html.d.ts
|
|
4
|
+
/** The HTML renderer for `::card-group`, `::card`, and `::columns`. Pass it as `components`. */
|
|
5
|
+
export declare const components: Record<"card" | "card-title" | "card-group" | "columns" | "column", NodeHandler>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { type CardAttributes, type CardColor, type CardsMeta, type CardsOptions, type ColumnsAttributes, colors, _default as default };
|
package/dist/html.mjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { a as rel, n as external, o as css } from "./client-CONO3MxN.mjs";
|
|
2
|
+
import src_default, { colors } from "./index.mjs";
|
|
3
|
+
import { escapeHtml } from "comark/utils";
|
|
4
|
+
import { iconHtml, iconStyles } from "comark-icon/html";
|
|
5
|
+
//#region src/html.ts
|
|
6
|
+
const styled = /* @__PURE__ */ new WeakSet();
|
|
7
|
+
const attr = (value) => escapeHtml(String(value), { "\"": """ });
|
|
8
|
+
const styles = (state) => {
|
|
9
|
+
if (styled.has(state.context)) return "";
|
|
10
|
+
styled.add(state.context);
|
|
11
|
+
return `<style data-comark-cards>${css}</style>`;
|
|
12
|
+
};
|
|
13
|
+
const card = async (node, state) => {
|
|
14
|
+
const [, attrs] = node;
|
|
15
|
+
const target = attrs.target ? attrs.target : void 0;
|
|
16
|
+
const link = attrs.to ? `<a class="ccr-link" href="${attr(attrs.to)}"${target ? ` target="${attr(target)}"` : ""}${rel(target) ? ` rel="${rel(target)}"` : ""} aria-label="${attr(attrs.label)}"></a>` : "";
|
|
17
|
+
const icon = attrs.icon ? iconHtml(attrs.icon) : "";
|
|
18
|
+
const arrow = attrs.external ? `<svg class="ccr-external" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="${external}"></path></svg>` : "";
|
|
19
|
+
return `${styles(state)}${attrs.icon ? iconStyles(state) : ""}<div class="ccr" data-color="${attr(attrs.color ?? "primary")}">${link}${icon}${arrow}${await state.flow(node, state)}</div>`;
|
|
20
|
+
};
|
|
21
|
+
const title = async (node, state) => `<p class="ccr-title">${await state.flow(node, state)}</p>`;
|
|
22
|
+
const group = async (node, state) => `${styles(state)}<div class="ccr-group">${await state.flow(node, state)}</div>`;
|
|
23
|
+
const columns = async (node, state) => `${styles(state)}<div class="ccr-columns" data-cols="${attr(node[1].cols ?? "2")}">${await state.flow(node, state)}</div>`;
|
|
24
|
+
const column = async (node, state) => `<div class="ccr-column">${await state.flow(node, state)}</div>`;
|
|
25
|
+
/** The HTML renderer for `::card-group`, `::card`, and `::columns`. Pass it as `components`. */
|
|
26
|
+
const components = {
|
|
27
|
+
card,
|
|
28
|
+
"card-title": title,
|
|
29
|
+
"card-group": group,
|
|
30
|
+
columns,
|
|
31
|
+
column
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { colors, components, src_default as default };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { IconData, Icons } from "comark-icon";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
export type CardsOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the cards' `icon`, from `createIcons()` in comark-icon. Pass the one the page's other plugins use, so they
|
|
6
|
+
* share its `collections` and `fetch`. By default icons come from the Iconify API.
|
|
7
|
+
*/
|
|
8
|
+
iconResolver?: Icons;
|
|
9
|
+
};
|
|
10
|
+
export type CardsMeta = {
|
|
11
|
+
/** One readable sentence per problem with a `::card` or `::columns`. Empty when there are none. Other plugins add theirs too. */
|
|
12
|
+
issues: string[];
|
|
13
|
+
/** The comark-linter rule of each issue, by its sentence, so the linter reports it under its own code. */
|
|
14
|
+
issueRules: Record<string, string>;
|
|
15
|
+
};
|
|
16
|
+
/** Nuxt UI's colors, which tint a card's icon and border. */
|
|
17
|
+
export declare const colors: readonly ["primary", "secondary", "success", "info", "warning", "error", "neutral"];
|
|
18
|
+
export type CardColor = (typeof colors)[number];
|
|
19
|
+
/**
|
|
20
|
+
* What a `::card` becomes. A link card has `to`, its `target`, `external` when it opens in a new tab, and `label`, the
|
|
21
|
+
* link's name. Its title, when it has one, is a `card-title` node before its content.
|
|
22
|
+
*/
|
|
23
|
+
export type CardAttributes = {
|
|
24
|
+
color?: CardColor;
|
|
25
|
+
to?: string;
|
|
26
|
+
target?: string;
|
|
27
|
+
external?: string;
|
|
28
|
+
label?: string;
|
|
29
|
+
icon?: IconData;
|
|
30
|
+
};
|
|
31
|
+
/** What a `::columns` becomes: how many columns, with each cell a `column` node. */
|
|
32
|
+
export type ColumnsAttributes = {
|
|
33
|
+
cols?: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Turns `::card-group` and `::card{title description icon to target color}` into cards, link cards when they have `to`,
|
|
37
|
+
* and `::columns{cols}` into a grid with a cell per block. Problems are added to `meta.issues`.
|
|
38
|
+
*/
|
|
39
|
+
declare const _default: import("comark").ComarkPluginFactory<CardsOptions, CardsMeta, {}>;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { _default as default };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { i as isSafeHref, r as isExternalHref } from "./client-CONO3MxN.mjs";
|
|
2
|
+
import { defineComarkPlugin } from "comark";
|
|
3
|
+
import { resolveAttributes } from "comark/render";
|
|
4
|
+
import { textContent } from "comark/utils";
|
|
5
|
+
import { createIcons, describeIconProblem, iconProblemRule } from "comark-icon";
|
|
6
|
+
//#region src/index.ts
|
|
7
|
+
/** Nuxt UI's colors, which tint a card's icon and border. */
|
|
8
|
+
const colors = [
|
|
9
|
+
"primary",
|
|
10
|
+
"secondary",
|
|
11
|
+
"success",
|
|
12
|
+
"info",
|
|
13
|
+
"warning",
|
|
14
|
+
"error",
|
|
15
|
+
"neutral"
|
|
16
|
+
];
|
|
17
|
+
const isElement = (node) => Array.isArray(node) && node[0] !== null;
|
|
18
|
+
const isContent = (node) => Array.isArray(node) ? node[0] !== null : node.trim() !== "";
|
|
19
|
+
const childrenOf = (node) => node.slice(2);
|
|
20
|
+
const text = (value) => value === void 0 || value === null || value instanceof Object ? "" : String(value).trim();
|
|
21
|
+
const clip = (value) => {
|
|
22
|
+
const words = value.trim().replace(/\s+/g, " ");
|
|
23
|
+
return words.length > 40 ? `${words.slice(0, 39)}…` : words;
|
|
24
|
+
};
|
|
25
|
+
const isColor = (value) => colors.some((color) => color === value);
|
|
26
|
+
const isTemplate = (node, name) => isElement(node) && node[0] === "template" && node[1].name === name;
|
|
27
|
+
const unwrap = (nodes) => nodes.filter(isContent).flatMap((node) => isElement(node) && node[0] === "p" ? childrenOf(node) : [node]);
|
|
28
|
+
const resolve = (node, walk) => resolveAttributes(node[1], walk.data, { parseJson: true });
|
|
29
|
+
const CARD_PROPS = [
|
|
30
|
+
"title",
|
|
31
|
+
"description",
|
|
32
|
+
"icon",
|
|
33
|
+
"to",
|
|
34
|
+
"href",
|
|
35
|
+
"target",
|
|
36
|
+
"color"
|
|
37
|
+
];
|
|
38
|
+
function unknownProps(node, name, block, props, walk) {
|
|
39
|
+
const known = props.flatMap((prop) => prop === "href" ? [] : [`\`${prop}\``]);
|
|
40
|
+
const list = known.length > 1 ? `${known.slice(0, -1).join(", ")}, or ${known.at(-1)}` : known[0];
|
|
41
|
+
for (const key of Object.keys(node[1])) {
|
|
42
|
+
const prop = key.replace(/^:/, "");
|
|
43
|
+
if (!props.includes(prop) && prop !== "id" && prop !== "class") walk.issues.push({
|
|
44
|
+
rule: "comark/cards/unknown-prop",
|
|
45
|
+
message: `${name}: \`${prop}\` isn't a prop of \`${block}\`, so it's ignored. Use ${list}.`
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function card(node, walk) {
|
|
50
|
+
const attrs = resolve(node, walk);
|
|
51
|
+
const children = childrenOf(node);
|
|
52
|
+
const slot = children.find((child) => isTemplate(child, "title"));
|
|
53
|
+
const content = children.flatMap((child) => child === slot ? [] : isTemplate(child, "default") ? childrenOf(child) : [child]);
|
|
54
|
+
const title = slot ? unwrap(childrenOf(slot)) : text(attrs.title) ? [text(attrs.title)] : [];
|
|
55
|
+
const words = clip(textContent([
|
|
56
|
+
"p",
|
|
57
|
+
{},
|
|
58
|
+
...title
|
|
59
|
+
]));
|
|
60
|
+
const name = `\`::card\` ${++walk.cards}${words ? ` ("${words}")` : ""}`;
|
|
61
|
+
unknownProps(node, name, "::card", CARD_PROPS, walk);
|
|
62
|
+
const description = text(attrs.description);
|
|
63
|
+
if (!content.some(isContent) && description) content.push([
|
|
64
|
+
"p",
|
|
65
|
+
{},
|
|
66
|
+
description
|
|
67
|
+
]);
|
|
68
|
+
const written = text(attrs.color);
|
|
69
|
+
const result = {};
|
|
70
|
+
result.color = isColor(written) ? written : "primary";
|
|
71
|
+
if (written && !isColor(written)) walk.issues.push({
|
|
72
|
+
rule: "comark/cards/invalid-color",
|
|
73
|
+
message: `${name}: \`color\` is "${clip(written)}", so it shows as primary. Write one of ${colors.join(", ")}.`
|
|
74
|
+
});
|
|
75
|
+
let to = text(attrs.to);
|
|
76
|
+
const href = text(attrs.href);
|
|
77
|
+
if (href && !to) {
|
|
78
|
+
walk.issues.push({
|
|
79
|
+
rule: "comark/cards/href-instead-of-to",
|
|
80
|
+
message: `${name}: Nuxt UI links a card with \`to\`, so it ignores \`href\`. Write \`to="${clip(href)}"\` instead.`
|
|
81
|
+
});
|
|
82
|
+
to = href;
|
|
83
|
+
}
|
|
84
|
+
if (to && !isSafeHref(to)) {
|
|
85
|
+
walk.issues.push({
|
|
86
|
+
rule: "comark/cards/unsafe-link",
|
|
87
|
+
message: `${name}: \`to\` must be a page or a web address, so it isn't a link.`
|
|
88
|
+
});
|
|
89
|
+
to = "";
|
|
90
|
+
}
|
|
91
|
+
if (to) {
|
|
92
|
+
result.to = to;
|
|
93
|
+
const target = text(attrs.target) || (isExternalHref(to) ? "_blank" : "");
|
|
94
|
+
if (target) result.target = target;
|
|
95
|
+
if (target === "_blank") result.external = "true";
|
|
96
|
+
result.label = words || "Card link";
|
|
97
|
+
}
|
|
98
|
+
const icon = text(attrs.icon);
|
|
99
|
+
if (icon) walk.icons.push({
|
|
100
|
+
card: node,
|
|
101
|
+
value: icon,
|
|
102
|
+
name
|
|
103
|
+
});
|
|
104
|
+
node[1] = result;
|
|
105
|
+
const head = title.length ? [[
|
|
106
|
+
"card-title",
|
|
107
|
+
{},
|
|
108
|
+
...title
|
|
109
|
+
]] : [];
|
|
110
|
+
node.splice(2, node.length - 2, ...head, ...content);
|
|
111
|
+
}
|
|
112
|
+
function columns(node, walk) {
|
|
113
|
+
const name = `\`::columns\` ${++walk.columns}`;
|
|
114
|
+
unknownProps(node, name, "::columns", ["cols"], walk);
|
|
115
|
+
const written = text(resolve(node, walk).cols);
|
|
116
|
+
let cols = "2";
|
|
117
|
+
if (/^[1-6]$/.test(written)) cols = written;
|
|
118
|
+
else if (written) walk.issues.push({
|
|
119
|
+
rule: "comark/cards/invalid-cols",
|
|
120
|
+
message: `${name}: \`cols\` is "${clip(written)}", so it shows 2 columns. Write a number from 1 to 6.`
|
|
121
|
+
});
|
|
122
|
+
const cells = childrenOf(node).filter(isContent).map((child) => isElement(child) && child[0] === "column" ? [
|
|
123
|
+
"column",
|
|
124
|
+
{},
|
|
125
|
+
...childrenOf(child)
|
|
126
|
+
] : [
|
|
127
|
+
"column",
|
|
128
|
+
{},
|
|
129
|
+
child
|
|
130
|
+
]);
|
|
131
|
+
if (!cells.length) walk.issues.push({
|
|
132
|
+
rule: "comark/cards/empty-columns",
|
|
133
|
+
message: `${name} is empty. Put a block inside for each column, or remove it.`
|
|
134
|
+
});
|
|
135
|
+
node[1] = { cols };
|
|
136
|
+
node.splice(2, node.length - 2, ...cells);
|
|
137
|
+
}
|
|
138
|
+
function transform(nodes, walk) {
|
|
139
|
+
for (const node of nodes) {
|
|
140
|
+
if (!isElement(node)) continue;
|
|
141
|
+
if (node[0] === "card") card(node, walk);
|
|
142
|
+
else if (node[0] === "columns") columns(node, walk);
|
|
143
|
+
else if (node[0] === "card-group") node[1] = {};
|
|
144
|
+
transform(childrenOf(node), walk);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async function addIcons(walk, resolver) {
|
|
148
|
+
if (!walk.icons.length) return;
|
|
149
|
+
const resolved = await resolver.resolve(walk.icons.map(({ value }) => value));
|
|
150
|
+
for (const { card: node, value, name } of walk.icons) {
|
|
151
|
+
const icon = resolved.get(value);
|
|
152
|
+
if (!icon) continue;
|
|
153
|
+
if ("problem" in icon) walk.issues.push({
|
|
154
|
+
rule: iconProblemRule(icon),
|
|
155
|
+
message: `${name}, icon "${clip(value)}": ${describeIconProblem(value, icon)}`
|
|
156
|
+
});
|
|
157
|
+
else node[1].icon = icon;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Turns `::card-group` and `::card{title description icon to target color}` into cards, link cards when they have `to`,
|
|
162
|
+
* and `::columns{cols}` into a grid with a cell per block. Problems are added to `meta.issues`.
|
|
163
|
+
*/
|
|
164
|
+
var src_default = defineComarkPlugin((options = {}) => {
|
|
165
|
+
const resolver = options.iconResolver ?? createIcons();
|
|
166
|
+
return {
|
|
167
|
+
name: "comark-cards",
|
|
168
|
+
async post(state) {
|
|
169
|
+
const { tree } = state;
|
|
170
|
+
const walk = {
|
|
171
|
+
data: {
|
|
172
|
+
frontmatter: tree.frontmatter,
|
|
173
|
+
meta: tree.meta,
|
|
174
|
+
data: {},
|
|
175
|
+
props: {}
|
|
176
|
+
},
|
|
177
|
+
issues: [],
|
|
178
|
+
icons: [],
|
|
179
|
+
cards: 0,
|
|
180
|
+
columns: 0
|
|
181
|
+
};
|
|
182
|
+
transform(tree.nodes, walk);
|
|
183
|
+
await addIcons(walk, resolver);
|
|
184
|
+
tree.meta.issues = [...tree.meta.issues ?? [], ...walk.issues.map((issue) => issue.message)];
|
|
185
|
+
tree.meta.issueRules = {
|
|
186
|
+
...tree.meta.issueRules,
|
|
187
|
+
...Object.fromEntries(walk.issues.map((issue) => [issue.message, issue.rule]))
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
//#endregion
|
|
193
|
+
export { colors, src_default as default };
|
package/dist/react.d.mts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import _default, { CardAttributes, CardColor, CardsMeta, CardsOptions, ColumnsAttributes, colors } from "./index.mjs";
|
|
2
|
+
import { IconData } from "comark-icon/react";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
//#region src/react.d.ts
|
|
5
|
+
type Children = {
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
type CardProps = Children & {
|
|
9
|
+
color?: string;
|
|
10
|
+
to?: string;
|
|
11
|
+
target?: string;
|
|
12
|
+
external?: string | boolean;
|
|
13
|
+
label?: string;
|
|
14
|
+
icon?: IconData;
|
|
15
|
+
};
|
|
16
|
+
/** `::card` for `@comark/react`. */
|
|
17
|
+
export declare function Card({ color, to, target, external: opens, label, icon, children }: CardProps): import("react").DetailedReactHTMLElement<{
|
|
18
|
+
className: string;
|
|
19
|
+
"data-color": string;
|
|
20
|
+
}, HTMLElement>;
|
|
21
|
+
/** A card's title for `@comark/react`. */
|
|
22
|
+
export declare function CardTitle({ children }: Children): import("react").DetailedReactHTMLElement<{
|
|
23
|
+
className: string;
|
|
24
|
+
}, HTMLElement>;
|
|
25
|
+
/** `::card-group` for `@comark/react`. */
|
|
26
|
+
export declare function CardGroup({ children }: Children): import("react").DetailedReactHTMLElement<{
|
|
27
|
+
className: string;
|
|
28
|
+
}, HTMLElement>;
|
|
29
|
+
/** `::columns` for `@comark/react`. */
|
|
30
|
+
export declare function Columns({ cols, children }: Children & {
|
|
31
|
+
cols?: string | number;
|
|
32
|
+
}): import("react").DetailedReactHTMLElement<{
|
|
33
|
+
className: string;
|
|
34
|
+
"data-cols": string;
|
|
35
|
+
}, HTMLElement>;
|
|
36
|
+
/** Each cell of a `::columns` for `@comark/react`. */
|
|
37
|
+
export declare function Column({ children }: Children): import("react").DetailedReactHTMLElement<{
|
|
38
|
+
className: string;
|
|
39
|
+
}, HTMLElement>;
|
|
40
|
+
/** Pass these as `components` to `@comark/react`. */
|
|
41
|
+
export declare const components: {
|
|
42
|
+
Card: typeof Card;
|
|
43
|
+
CardTitle: typeof CardTitle;
|
|
44
|
+
CardGroup: typeof CardGroup;
|
|
45
|
+
Columns: typeof Columns;
|
|
46
|
+
Column: typeof Column;
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
export { type CardAttributes, type CardColor, type CardsMeta, type CardsOptions, type ColumnsAttributes, colors, _default as default };
|
package/dist/react.mjs
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { a as rel, i as isSafeHref, n as external, r as isExternalHref, t as addStyles } from "./client-CONO3MxN.mjs";
|
|
2
|
+
import src_default, { colors } from "./index.mjs";
|
|
3
|
+
import { Icon } from "comark-icon/react";
|
|
4
|
+
import { createElement, useEffect } from "react";
|
|
5
|
+
//#region src/react.ts
|
|
6
|
+
const arrow = () => createElement("svg", {
|
|
7
|
+
className: "ccr-external",
|
|
8
|
+
viewBox: "0 0 24 24",
|
|
9
|
+
width: 16,
|
|
10
|
+
height: 16,
|
|
11
|
+
fill: "none",
|
|
12
|
+
stroke: "currentColor",
|
|
13
|
+
strokeWidth: 2,
|
|
14
|
+
strokeLinecap: "round",
|
|
15
|
+
strokeLinejoin: "round",
|
|
16
|
+
"aria-hidden": true
|
|
17
|
+
}, createElement("path", { d: external }));
|
|
18
|
+
/** `::card` for `@comark/react`. */
|
|
19
|
+
function Card({ color = "primary", to, target, external: opens, label, icon, children }) {
|
|
20
|
+
useEffect(addStyles, []);
|
|
21
|
+
const href = isSafeHref(to) ? to : void 0;
|
|
22
|
+
const linkTarget = target || (isExternalHref(href) ? "_blank" : void 0);
|
|
23
|
+
return createElement("div", {
|
|
24
|
+
className: "ccr",
|
|
25
|
+
"data-color": color
|
|
26
|
+
}, href ? createElement("a", {
|
|
27
|
+
className: "ccr-link",
|
|
28
|
+
href,
|
|
29
|
+
target: linkTarget,
|
|
30
|
+
rel: rel(linkTarget),
|
|
31
|
+
"aria-label": label
|
|
32
|
+
}) : null, icon?.src ? createElement(Icon, icon) : null, opens ? arrow() : null, children);
|
|
33
|
+
}
|
|
34
|
+
/** A card's title for `@comark/react`. */
|
|
35
|
+
function CardTitle({ children }) {
|
|
36
|
+
return createElement("p", { className: "ccr-title" }, children);
|
|
37
|
+
}
|
|
38
|
+
/** `::card-group` for `@comark/react`. */
|
|
39
|
+
function CardGroup({ children }) {
|
|
40
|
+
useEffect(addStyles, []);
|
|
41
|
+
return createElement("div", { className: "ccr-group" }, children);
|
|
42
|
+
}
|
|
43
|
+
/** `::columns` for `@comark/react`. */
|
|
44
|
+
function Columns({ cols = "2", children }) {
|
|
45
|
+
useEffect(addStyles, []);
|
|
46
|
+
return createElement("div", {
|
|
47
|
+
className: "ccr-columns",
|
|
48
|
+
"data-cols": String(cols)
|
|
49
|
+
}, children);
|
|
50
|
+
}
|
|
51
|
+
/** Each cell of a `::columns` for `@comark/react`. */
|
|
52
|
+
function Column({ children }) {
|
|
53
|
+
return createElement("div", { className: "ccr-column" }, children);
|
|
54
|
+
}
|
|
55
|
+
/** Pass these as `components` to `@comark/react`. */
|
|
56
|
+
const components = {
|
|
57
|
+
Card,
|
|
58
|
+
CardTitle,
|
|
59
|
+
CardGroup,
|
|
60
|
+
Columns,
|
|
61
|
+
Column
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { Card, CardGroup, CardTitle, Column, Columns, colors, components, src_default as default };
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer comark{:where(.ccr,.ccr-group,.ccr-columns){--_comark-background:var(--comark-background,var(--background,#fff));--_comark-foreground:var(--comark-foreground,var(--foreground,#0a0a0a));--_comark-muted:var(--comark-muted,var(--muted-foreground,#737373));--_comark-border:var(--comark-border,var(--border,#e5e5e5));--_comark-accent:var(--comark-accent,var(--accent,#f5f5f5));--_comark-ring:var(--comark-ring,var(--ring,#a1a1a1));--_comark-radius:var(--comark-radius,var(--radius,.625rem));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){:where(.ccr,.ccr-group,.ccr-columns){--_comark-background:var(--comark-background,var(--background,#0a0a0a));--_comark-foreground:var(--comark-foreground,var(--foreground,#fafafa));--_comark-muted:var(--comark-muted,var(--muted-foreground,#a1a1a1));--_comark-border:var(--comark-border,var(--border,rgb(255 255 255/.1)));--_comark-accent:var(--comark-accent,var(--accent,#262626));--_comark-ring:var(--comark-ring,var(--ring,#737373))}}:where(.ccr){--ccr-primary:var(--ui-primary,var(--primary,var(--_comark-foreground)));--ccr-secondary:var(--ui-secondary,#2563eb);--ccr-success:var(--ui-success,#16a34a);--ccr-info:var(--ui-info,#2563eb);--ccr-warning:var(--ui-warning,#ca8a04);--ccr-error:var(--ui-error,var(--destructive,#dc2626));--ccr-neutral:var(--_comark-foreground)}@media (prefers-color-scheme:dark){:where(.ccr){--ccr-secondary:var(--ui-secondary,#60a5fa);--ccr-success:var(--ui-success,#4ade80);--ccr-info:var(--ui-info,#60a5fa);--ccr-warning:var(--ui-warning,#facc15);--ccr-error:var(--ui-error,var(--destructive,#f87171))}}.ccr-group,.ccr-columns{display:grid;gap:1rem;margin:1.5rem 0;container-type:inline-size}.ccr-group{grid-template-columns:repeat(2,minmax(0,1fr))}.ccr-columns[data-cols='2']{grid-template-columns:repeat(2,minmax(0,1fr))}.ccr-columns[data-cols='3']{grid-template-columns:repeat(3,minmax(0,1fr))}.ccr-columns[data-cols='4']{grid-template-columns:repeat(4,minmax(0,1fr))}.ccr-columns[data-cols='5']{grid-template-columns:repeat(5,minmax(0,1fr))}.ccr-columns[data-cols='6']{grid-template-columns:repeat(6,minmax(0,1fr))}@container (width<36rem){.ccr-group>*,.ccr-columns>*{grid-column:1/-1}}.ccr-group>.ccr{margin:0}.ccr-column>:first-child{margin-top:0}.ccr-column>:last-child{margin-bottom:0}.ccr{--ccr:var(--ccr-primary);position:relative;margin:1.5rem 0;padding:1.25rem;border:1px solid var(--_comark-border);border-radius:calc(var(--_comark-radius) + 2px);background:var(--_comark-background);box-shadow:0 1px 2px rgb(0 0 0/.05);color:var(--_comark-muted);font:400 .875rem/1.375rem var(--_comark-font);transition:background-color .15s,border-color .15s}.ccr[data-color='secondary']{--ccr:var(--ccr-secondary)}.ccr[data-color='success']{--ccr:var(--ccr-success)}.ccr[data-color='info']{--ccr:var(--ccr-info)}.ccr[data-color='warning']{--ccr:var(--ccr-warning)}.ccr[data-color='error']{--ccr:var(--ccr-error)}.ccr[data-color='neutral']{--ccr:var(--ccr-neutral)}.ccr>:last-child{margin-bottom:0}.ccr>.ci{--comark-icon-size:1.25rem;display:block;margin-bottom:.75rem;color:var(--ccr)}.ccr-title{margin:0 0 .25rem;color:var(--_comark-foreground);font-size:.9375rem;font-weight:600;line-height:1.375rem;text-wrap:balance}.ccr-title+*{margin-top:0}.ccr-link{position:absolute;inset:0;z-index:0;border-radius:inherit}.ccr-link:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 50%,transparent)}.ccr :is(a,button):not(.ccr-link){position:relative;z-index:1}.ccr:has(>.ccr-link):hover{border-color:color-mix(in srgb,var(--ccr) 50%,var(--_comark-border));background:color-mix(in srgb,var(--_comark-accent) 50%,var(--_comark-background))}.ccr-external{position:absolute;top:1rem;inset-inline-end:1rem;width:1rem;height:1rem;color:var(--_comark-muted)}.ccr:dir(rtl) .ccr-external{scale:-1 1}@media print{.ccr{break-inside:avoid}.ccr-external{display:none}}}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- `::card` for `@comark/svelte`. -->
|
|
2
|
+
<script>
|
|
3
|
+
import { onMount } from "svelte";
|
|
4
|
+
import { addStyles, external as arrow, isExternalHref, isSafeHref, rel } from "comark-cards/client";
|
|
5
|
+
import { Icon } from "comark-icon/svelte";
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
color = "primary",
|
|
9
|
+
to = undefined,
|
|
10
|
+
target = undefined,
|
|
11
|
+
external = undefined,
|
|
12
|
+
label = undefined,
|
|
13
|
+
icon = undefined,
|
|
14
|
+
children,
|
|
15
|
+
} = $props();
|
|
16
|
+
onMount(addStyles);
|
|
17
|
+
const href = $derived(isSafeHref(to) ? to : undefined);
|
|
18
|
+
const linkTarget = $derived(target || (isExternalHref(href) ? "_blank" : undefined));
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<div class="ccr" data-color={color}>{#if href}<a class="ccr-link" href={href} target={linkTarget} rel={rel(linkTarget)} aria-label={label}></a>{/if}{#if icon?.src}<Icon {...icon} />{/if}{#if external}<svg class="ccr-external" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d={arrow} /></svg>{/if}{@render children?.()}</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!-- `::card-group` for `@comark/svelte`. -->
|
|
2
|
+
<script>
|
|
3
|
+
import { onMount } from "svelte";
|
|
4
|
+
import { addStyles } from "comark-cards/client";
|
|
5
|
+
|
|
6
|
+
let { children } = $props();
|
|
7
|
+
onMount(addStyles);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<div class="ccr-group">{@render children?.()}</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!-- `::columns` for `@comark/svelte`. -->
|
|
2
|
+
<script>
|
|
3
|
+
import { onMount } from "svelte";
|
|
4
|
+
import { addStyles } from "comark-cards/client";
|
|
5
|
+
|
|
6
|
+
let { cols = "2", children } = $props();
|
|
7
|
+
onMount(addStyles);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<div class="ccr-columns" data-cols={String(cols)}>{@render children?.()}</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Component, Snippet } from "svelte";
|
|
2
|
+
import type { IconData } from "comark-icon";
|
|
3
|
+
|
|
4
|
+
export { colors, default } from "comark-cards";
|
|
5
|
+
export type {
|
|
6
|
+
CardAttributes,
|
|
7
|
+
CardColor,
|
|
8
|
+
CardsMeta,
|
|
9
|
+
CardsOptions,
|
|
10
|
+
ColumnsAttributes,
|
|
11
|
+
} from "comark-cards";
|
|
12
|
+
|
|
13
|
+
export declare const Card: Component<{
|
|
14
|
+
color?: string;
|
|
15
|
+
to?: string;
|
|
16
|
+
target?: string;
|
|
17
|
+
external?: string | boolean;
|
|
18
|
+
label?: string;
|
|
19
|
+
icon?: IconData;
|
|
20
|
+
children?: Snippet;
|
|
21
|
+
}>;
|
|
22
|
+
export declare const CardTitle: Component<{ children?: Snippet }>;
|
|
23
|
+
export declare const CardGroup: Component<{ children?: Snippet }>;
|
|
24
|
+
export declare const Columns: Component<{ cols?: string | number; children?: Snippet }>;
|
|
25
|
+
export declare const Column: Component<{ children?: Snippet }>;
|
|
26
|
+
export declare const components: {
|
|
27
|
+
Card: typeof Card;
|
|
28
|
+
CardTitle: typeof CardTitle;
|
|
29
|
+
CardGroup: typeof CardGroup;
|
|
30
|
+
Columns: typeof Columns;
|
|
31
|
+
Column: typeof Column;
|
|
32
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// `::card-group`, `::card`, and `::columns` for `@comark/svelte`. Pass `components` to it; the parse plugin comes from
|
|
2
|
+
// `comark-cards`.
|
|
3
|
+
import Card from "./Card.svelte";
|
|
4
|
+
import CardGroup from "./CardGroup.svelte";
|
|
5
|
+
import CardTitle from "./CardTitle.svelte";
|
|
6
|
+
import Column from "./Column.svelte";
|
|
7
|
+
import Columns from "./Columns.svelte";
|
|
8
|
+
|
|
9
|
+
export { colors, default } from "comark-cards";
|
|
10
|
+
export { Card, CardGroup, CardTitle, Column, Columns };
|
|
11
|
+
export const components = { Card, CardTitle, CardGroup, Columns, Column };
|
package/dist/vue.d.mts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import _default, { CardAttributes, CardColor, CardsMeta, CardsOptions, ColumnsAttributes, colors } from "./index.mjs";
|
|
2
|
+
import { PropType } from "vue";
|
|
3
|
+
import { IconData } from "comark-icon/vue";
|
|
4
|
+
//#region src/vue.d.ts
|
|
5
|
+
/** `::card` for `@comark/vue`. */
|
|
6
|
+
export declare const Card: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
7
|
+
color: {
|
|
8
|
+
type: StringConstructor;
|
|
9
|
+
default: string;
|
|
10
|
+
};
|
|
11
|
+
to: StringConstructor;
|
|
12
|
+
target: StringConstructor;
|
|
13
|
+
external: (StringConstructor | BooleanConstructor)[];
|
|
14
|
+
label: StringConstructor;
|
|
15
|
+
icon: PropType<IconData>;
|
|
16
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
19
|
+
color: {
|
|
20
|
+
type: StringConstructor;
|
|
21
|
+
default: string;
|
|
22
|
+
};
|
|
23
|
+
to: StringConstructor;
|
|
24
|
+
target: StringConstructor;
|
|
25
|
+
external: (StringConstructor | BooleanConstructor)[];
|
|
26
|
+
label: StringConstructor;
|
|
27
|
+
icon: PropType<IconData>;
|
|
28
|
+
}>> & Readonly<{}>, {
|
|
29
|
+
color: string;
|
|
30
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
31
|
+
/** A card's title for `@comark/vue`. */
|
|
32
|
+
export declare const CardTitle: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
33
|
+
[key: string]: any;
|
|
34
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
35
|
+
/** `::card-group` for `@comark/vue`. */
|
|
36
|
+
export declare const CardGroup: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
39
|
+
/** `::columns` for `@comark/vue`. */
|
|
40
|
+
export declare const Columns: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
41
|
+
cols: {
|
|
42
|
+
type: (StringConstructor | NumberConstructor)[];
|
|
43
|
+
default: string;
|
|
44
|
+
};
|
|
45
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
46
|
+
[key: string]: any;
|
|
47
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
48
|
+
cols: {
|
|
49
|
+
type: (StringConstructor | NumberConstructor)[];
|
|
50
|
+
default: string;
|
|
51
|
+
};
|
|
52
|
+
}>> & Readonly<{}>, {
|
|
53
|
+
cols: string | number;
|
|
54
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
55
|
+
/** Each cell of a `::columns` for `@comark/vue`. */
|
|
56
|
+
export declare const Column: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
57
|
+
[key: string]: any;
|
|
58
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
59
|
+
/** Pass these as `components` to `@comark/vue`. */
|
|
60
|
+
export declare const components: {
|
|
61
|
+
Card: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
62
|
+
color: {
|
|
63
|
+
type: StringConstructor;
|
|
64
|
+
default: string;
|
|
65
|
+
};
|
|
66
|
+
to: StringConstructor;
|
|
67
|
+
target: StringConstructor;
|
|
68
|
+
external: (StringConstructor | BooleanConstructor)[];
|
|
69
|
+
label: StringConstructor;
|
|
70
|
+
icon: PropType<IconData>;
|
|
71
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
72
|
+
[key: string]: any;
|
|
73
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
74
|
+
color: {
|
|
75
|
+
type: StringConstructor;
|
|
76
|
+
default: string;
|
|
77
|
+
};
|
|
78
|
+
to: StringConstructor;
|
|
79
|
+
target: StringConstructor;
|
|
80
|
+
external: (StringConstructor | BooleanConstructor)[];
|
|
81
|
+
label: StringConstructor;
|
|
82
|
+
icon: PropType<IconData>;
|
|
83
|
+
}>> & Readonly<{}>, {
|
|
84
|
+
color: string;
|
|
85
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
86
|
+
CardTitle: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
87
|
+
[key: string]: any;
|
|
88
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
89
|
+
CardGroup: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
90
|
+
[key: string]: any;
|
|
91
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
92
|
+
Columns: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
93
|
+
cols: {
|
|
94
|
+
type: (StringConstructor | NumberConstructor)[];
|
|
95
|
+
default: string;
|
|
96
|
+
};
|
|
97
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
98
|
+
[key: string]: any;
|
|
99
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
100
|
+
cols: {
|
|
101
|
+
type: (StringConstructor | NumberConstructor)[];
|
|
102
|
+
default: string;
|
|
103
|
+
};
|
|
104
|
+
}>> & Readonly<{}>, {
|
|
105
|
+
cols: string | number;
|
|
106
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
107
|
+
Column: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
108
|
+
[key: string]: any;
|
|
109
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
110
|
+
};
|
|
111
|
+
//#endregion
|
|
112
|
+
export { type CardAttributes, type CardColor, type CardsMeta, type CardsOptions, type ColumnsAttributes, colors, _default as default };
|
package/dist/vue.mjs
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { a as rel, i as isSafeHref, n as external, r as isExternalHref, t as addStyles } from "./client-CONO3MxN.mjs";
|
|
2
|
+
import src_default, { colors } from "./index.mjs";
|
|
3
|
+
import { defineComponent, h, onMounted } from "vue";
|
|
4
|
+
import { Icon } from "comark-icon/vue";
|
|
5
|
+
//#region src/vue.ts
|
|
6
|
+
const arrow = () => h("svg", {
|
|
7
|
+
class: "ccr-external",
|
|
8
|
+
viewBox: "0 0 24 24",
|
|
9
|
+
width: "16",
|
|
10
|
+
height: "16",
|
|
11
|
+
fill: "none",
|
|
12
|
+
stroke: "currentColor",
|
|
13
|
+
"stroke-width": "2",
|
|
14
|
+
"stroke-linecap": "round",
|
|
15
|
+
"stroke-linejoin": "round",
|
|
16
|
+
"aria-hidden": "true"
|
|
17
|
+
}, [h("path", { d: external })]);
|
|
18
|
+
/** `::card` for `@comark/vue`. */
|
|
19
|
+
const Card = defineComponent({
|
|
20
|
+
name: "Card",
|
|
21
|
+
inheritAttrs: false,
|
|
22
|
+
props: {
|
|
23
|
+
color: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: "primary"
|
|
26
|
+
},
|
|
27
|
+
to: String,
|
|
28
|
+
target: String,
|
|
29
|
+
external: [String, Boolean],
|
|
30
|
+
label: String,
|
|
31
|
+
icon: Object
|
|
32
|
+
},
|
|
33
|
+
setup(props, { slots }) {
|
|
34
|
+
onMounted(addStyles);
|
|
35
|
+
return () => h("div", {
|
|
36
|
+
class: "ccr",
|
|
37
|
+
"data-color": props.color
|
|
38
|
+
}, [
|
|
39
|
+
isSafeHref(props.to) ? h("a", {
|
|
40
|
+
class: "ccr-link",
|
|
41
|
+
href: props.to,
|
|
42
|
+
target: props.target || (isExternalHref(props.to) ? "_blank" : void 0),
|
|
43
|
+
rel: rel(props.target || (isExternalHref(props.to) ? "_blank" : void 0)),
|
|
44
|
+
"aria-label": props.label
|
|
45
|
+
}) : null,
|
|
46
|
+
props.icon?.src ? h(Icon, { ...props.icon }) : null,
|
|
47
|
+
props.external ? arrow() : null,
|
|
48
|
+
slots.default?.()
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
/** A card's title for `@comark/vue`. */
|
|
53
|
+
const CardTitle = defineComponent({
|
|
54
|
+
name: "CardTitle",
|
|
55
|
+
inheritAttrs: false,
|
|
56
|
+
setup(_, { slots }) {
|
|
57
|
+
return () => h("p", { class: "ccr-title" }, slots.default?.());
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
/** `::card-group` for `@comark/vue`. */
|
|
61
|
+
const CardGroup = defineComponent({
|
|
62
|
+
name: "CardGroup",
|
|
63
|
+
inheritAttrs: false,
|
|
64
|
+
setup(_, { slots }) {
|
|
65
|
+
onMounted(addStyles);
|
|
66
|
+
return () => h("div", { class: "ccr-group" }, slots.default?.());
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
/** `::columns` for `@comark/vue`. */
|
|
70
|
+
const Columns = defineComponent({
|
|
71
|
+
name: "Columns",
|
|
72
|
+
inheritAttrs: false,
|
|
73
|
+
props: { cols: {
|
|
74
|
+
type: [String, Number],
|
|
75
|
+
default: "2"
|
|
76
|
+
} },
|
|
77
|
+
setup(props, { slots }) {
|
|
78
|
+
onMounted(addStyles);
|
|
79
|
+
return () => h("div", {
|
|
80
|
+
class: "ccr-columns",
|
|
81
|
+
"data-cols": String(props.cols)
|
|
82
|
+
}, slots.default?.());
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
/** Each cell of a `::columns` for `@comark/vue`. */
|
|
86
|
+
const Column = defineComponent({
|
|
87
|
+
name: "Column",
|
|
88
|
+
inheritAttrs: false,
|
|
89
|
+
setup(_, { slots }) {
|
|
90
|
+
return () => h("div", { class: "ccr-column" }, slots.default?.());
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
/** Pass these as `components` to `@comark/vue`. */
|
|
94
|
+
const components = {
|
|
95
|
+
Card,
|
|
96
|
+
CardTitle,
|
|
97
|
+
CardGroup,
|
|
98
|
+
Columns,
|
|
99
|
+
Column
|
|
100
|
+
};
|
|
101
|
+
//#endregion
|
|
102
|
+
export { Card, CardGroup, CardTitle, Column, Columns, colors, components, src_default as default };
|
package/package.json
CHANGED
|
@@ -1,12 +1,93 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comark-cards",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "Cards, link cards, and columns in Nuxt UI's syntax, with no script. A Comark plugin.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"card",
|
|
7
|
+
"cards",
|
|
8
|
+
"columns",
|
|
9
|
+
"comark",
|
|
10
|
+
"markdown",
|
|
11
|
+
"mdc",
|
|
12
|
+
"plugin"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://comark.onmax.me/cards",
|
|
15
|
+
"bugs": "https://github.com/onmax/comark-plugins/issues",
|
|
5
16
|
"license": "MIT",
|
|
6
17
|
"author": "onmax",
|
|
7
18
|
"repository": {
|
|
8
19
|
"type": "git",
|
|
9
20
|
"url": "git+https://github.com/onmax/comark-plugins.git",
|
|
10
21
|
"directory": "packages/cards"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"sideEffects": [
|
|
28
|
+
"*.css"
|
|
29
|
+
],
|
|
30
|
+
"exports": {
|
|
31
|
+
".": "./dist/index.mjs",
|
|
32
|
+
"./client": "./dist/client.mjs",
|
|
33
|
+
"./html": "./dist/html.mjs",
|
|
34
|
+
"./react": "./dist/react.mjs",
|
|
35
|
+
"./style.css": "./dist/style.css",
|
|
36
|
+
"./svelte": {
|
|
37
|
+
"types": "./dist/svelte/index.d.ts",
|
|
38
|
+
"svelte": "./dist/svelte/index.js",
|
|
39
|
+
"default": "./dist/svelte/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./vue": "./dist/vue.mjs",
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public",
|
|
46
|
+
"provenance": true
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"comark-icon": "^0.4.1"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@comark/html": "^0.8.1",
|
|
53
|
+
"@comark/react": "^0.8.1",
|
|
54
|
+
"@comark/vue": "^0.8.1",
|
|
55
|
+
"@types/react": "^19.3.0",
|
|
56
|
+
"@types/react-dom": "^19.3.0",
|
|
57
|
+
"comark": "^0.8.1",
|
|
58
|
+
"react": "^19.3.1",
|
|
59
|
+
"react-dom": "^19.3.1",
|
|
60
|
+
"svelte": "^5.57.2",
|
|
61
|
+
"vue": "^3.5.44",
|
|
62
|
+
"comark-zoom": "0.4.1"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@comark/html": "^0.8.0",
|
|
66
|
+
"comark": "^0.8.0",
|
|
67
|
+
"react": ">=18",
|
|
68
|
+
"svelte": ">=5",
|
|
69
|
+
"vue": ">=3.5"
|
|
70
|
+
},
|
|
71
|
+
"peerDependenciesMeta": {
|
|
72
|
+
"@comark/html": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"react": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"svelte": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"vue": {
|
|
82
|
+
"optional": true
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"engines": {
|
|
86
|
+
"node": ">=22.12.0"
|
|
87
|
+
},
|
|
88
|
+
"scripts": {
|
|
89
|
+
"build": "tsdown",
|
|
90
|
+
"dev": "tsdown --watch",
|
|
91
|
+
"doctor": "vite-doctor . --no-cache --max-warnings 0 --format text"
|
|
11
92
|
}
|
|
12
|
-
}
|
|
93
|
+
}
|