Skip to content
Open
1 change: 1 addition & 0 deletions packages/remark-callouts/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./lib/remark-callouts";
export { default } from "./lib/remark-callouts";
export { Callout } from "./lib/Callout";
22 changes: 22 additions & 0 deletions packages/remark-callouts/src/lib/Callout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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 <blockquote className={className}>{children}</blockquote>;
}

// If we're here, it's a foldable callout

const elem = useRef(null);

const handleClick = () => {
elem.current.classList.toggle("callout-folded");
};

return (
<blockquote className={className} ref={elem} onClick={handleClick}>{children}</blockquote>
);
};

export { Callout };
15 changes: 10 additions & 5 deletions packages/remark-callouts/src/lib/remark-callouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,15 @@ export const callouts: Plugin = function (providedConfig?: Partial<Config>) {
const [t, ...rest] = paragraph.children;

const regex = new RegExp(
`^\\[!(?<keyword>(.*?))\\][\t\f ]?(?<title>.*?)$`,
`^\\[!(?<keyword>(.*?))\\](?<foldChar>[+-]?)[\t\f ]?(?<title>.*?)$`,
"gi"
);
const m = regex.exec(t.value);

// 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;
Expand Down Expand Up @@ -236,12 +236,17 @@ export const callouts: Plugin = function (providedConfig?: Partial<Config>) {
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};`,
},
});
Expand Down
35 changes: 35 additions & 0 deletions packages/remark-callouts/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,38 @@ 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: 0.8em;
right: 1em;
transform: rotate(45deg);
transition: all 0.3s ease-in-out;
}

blockquote.callout-foldable.callout-folded .callout-title strong::after {
transform: rotate(-45deg);
}
3 changes: 2 additions & 1 deletion packages/remark-callouts/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down