diff --git a/packages/remark-callouts/src/index.ts b/packages/remark-callouts/src/index.ts
index 28c2aea52..c66d78faf 100644
--- a/packages/remark-callouts/src/index.ts
+++ b/packages/remark-callouts/src/index.ts
@@ -1,2 +1,3 @@
export * from "./lib/remark-callouts";
export { default } from "./lib/remark-callouts";
+export { Callout } from "./lib/Callout";
\ No newline at end of file
diff --git a/packages/remark-callouts/src/lib/Callout.tsx b/packages/remark-callouts/src/lib/Callout.tsx
new file mode 100644
index 000000000..215e7f780
--- /dev/null
+++ b/packages/remark-callouts/src/lib/Callout.tsx
@@ -0,0 +1,20 @@
+import { useRef } from "react";
+
+const Callout = ({ className, children }) => {
+ // If it's not a foldable callout, just render it as a blockquote
+ if (!className.includes("callout-foldable")) {
+ return
{children}
;
+ }
+
+ const elem = useRef(null);
+
+ const handleClick = () => {
+ elem.current.classList.toggle("callout-folded");
+ };
+
+ return (
+ {children}
+ );
+};
+
+export { Callout };
\ No newline at end of file
diff --git a/packages/remark-callouts/src/lib/remark-callouts.ts b/packages/remark-callouts/src/lib/remark-callouts.ts
index 4924638f3..6a5429e17 100644
--- a/packages/remark-callouts/src/lib/remark-callouts.ts
+++ b/packages/remark-callouts/src/lib/remark-callouts.ts
@@ -113,7 +113,7 @@ export const callouts: Plugin = function (providedConfig?: Partial) {
const [t, ...rest] = paragraph.children;
const regex = new RegExp(
- `^\\[!(?(.*?))\\][\t\f ]?(?.*?)$`,
+ `^\\[!(?(.*?))\\](?[+-]?)[\t\f ]?(?.*?)$`,
"gi"
);
const m = regex.exec(t.value);
@@ -121,7 +121,7 @@ export const callouts: Plugin = function (providedConfig?: Partial) {
// if no callout syntax, forget about it.
if (!m) return;
- const [key, title] = [m.groups?.keyword, m.groups?.title];
+ const [key, foldChar, title] = [m.groups?.keyword, m.groups?.foldChar, m.groups?.title];
// if there's nothing inside the brackets, is it really a callout ?
if (!key) return;
@@ -236,12 +236,17 @@ export const callouts: Plugin = function (providedConfig?: Partial) {
blockquote.children.unshift(titleNode as BlockContent);
// Add classes for the callout block
+ const classList = [formatClassNameMap(config.classNameMaps.block)(keyword.toLowerCase())]
+ if (foldChar) {
+ classList.push('callout-foldable')
+ if (foldChar === '-') {
+ classList.push('callout-folded')
+ }
+ }
blockquote.data = config.dataMaps.block({
...blockquote.data,
hProperties: {
- className: formatClassNameMap(config.classNameMaps.block)(
- keyword.toLowerCase()
- ),
+ className: classList.join(" "),
style: `border-left-color:${entry?.color};`,
},
});
diff --git a/packages/remark-callouts/styles.css b/packages/remark-callouts/styles.css
index d96092264..7b54cab2e 100644
--- a/packages/remark-callouts/styles.css
+++ b/packages/remark-callouts/styles.css
@@ -23,6 +23,7 @@
align-items: center;
padding: 10px;
gap: 10px;
+ position: relative;
}
.callout-title > strong {
@@ -62,3 +63,40 @@ p:after {
p:after {
display: none;
}
+
+blockquote.callout-foldable {
+ cursor: pointer;
+ display: grid;
+ grid-template-rows: min-content 1fr;
+ transition: all 0.3s ease-in-out;
+}
+
+blockquote.callout-foldable.callout-folded {
+ grid-template-rows: min-content 0fr;
+}
+
+blockquote.callout-foldable .callout-content {
+ overflow: hidden;
+ padding: 0px 10px;
+}
+
+blockquote.callout-foldable .callout-title strong::after {
+ content: "";
+ display: inline-block;
+ height: 10px;
+ width: 10px;
+ border-style: solid;
+ border-width: 0 3px 3px 0;
+ border-color: var(--tw-prose-body);
+ position: absolute;
+ top: 50%;
+ right: 1em;
+ transform: translateY(-50%) rotate(45deg);
+ transform-origin: center;
+ transition: all 0.3s ease-in-out;
+}
+
+blockquote.callout-foldable.callout-folded .callout-title strong::after {
+ transform: translateY(-50%) rotate(-45deg);
+ transform-origin: center;
+}
diff --git a/packages/remark-callouts/tsconfig.lib.json b/packages/remark-callouts/tsconfig.lib.json
index 18857e49b..677a24aed 100644
--- a/packages/remark-callouts/tsconfig.lib.json
+++ b/packages/remark-callouts/tsconfig.lib.json
@@ -7,7 +7,8 @@
"types": ["node"],
"moduleResolution": "node",
"esModuleInterop": true,
- "forceConsistentCasingInFileNames": true
+ "forceConsistentCasingInFileNames": true,
+ "jsx": "react-jsx"
},
"exclude": ["**/*.spec.ts", "**/*.test.ts"],
"include": ["src/**/*.ts"]