Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/tempo-md/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from './lib/code-block';
export * from './lib/emoji';
export * from './lib/frontmatter';
export * from './lib/markdown';
export * from './lib/details';
export { default as supportedLanguages } from './lib/data/supported-languages';
export { default as supportedEmojis } from './lib/data/emojis';
17 changes: 17 additions & 0 deletions packages/tempo-md/src/lib/__tests__/details.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { describe, expect, it } from 'vitest';
import { details } from '../details';

describe('details', () => {
it('should return a string', () => {
expect(details({ summary: 'Click me', content: 'This is the content of the details element.' })).toBe(
`
<details>
<summary>Click me</summary>

This is the content of the details element.

</details>
`.trim()
);
});
});
29 changes: 29 additions & 0 deletions packages/tempo-md/src/lib/details.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export interface DetailsConfig {
summary: string;
content: string;
}

/**
* Creates a details element.
*
* @example
* ```ts
* const details = details({
* summary: 'Click me',
* content: 'This is the content of the details element.'
* });
* ```
*
* @param config - The configuration for the details element.
* @returns The details element as a string.
*/
export function details(config: DetailsConfig): string {
return `
<details>
<summary>${config.summary}</summary>

${config.content}

</details>
`.trim();
}
1 change: 1 addition & 0 deletions packages/tempo-md/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export {
} from './emoji';
export { default as supportedLanguages } from './data/supported-languages';
export { default as supportedEmojis } from './data/emojis';
export { details, type DetailsConfig } from './details';
export * as default from './markdown';
9 changes: 9 additions & 0 deletions packages/tempo/src/lib/__tests__/tempo-document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ describe('Text Elements', () => {
});

describe('Special Elements', () => {

it('should add a details element', () => {
const document = new TempoDocument().details({
summary: 'Hello World!',
content: ['Hello 2 World!', 'Hello 3 World!'],
});
expect(document.toJSON().nodes).toEqual([]);
});

it('should add a table', () => {
const document = new TempoDocument().table([
['Hello World!', 'Hello 2 World!'],
Expand Down
97 changes: 90 additions & 7 deletions packages/tempo/src/lib/tempo-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export type DocumentNodeType =
| 'break'
| 'numberList'
| 'bulletList'
| 'alert';
| 'alert'
| 'details';

interface BaseDocumentNode<N extends unknown[], D extends object = object> {
type: DocumentNodeType;
Expand All @@ -58,6 +59,27 @@ export interface ParagraphNode extends BaseDocumentNode<TempoTextNode[]> {
type: 'paragraph';
}

interface DetailsSummaryNode {
type: 'details-summary';
data: {
nodes: TempoTextNode[];
};
computed: string;
}

interface DetailsContentNode {
type: 'details-content';
data: {
nodes: TempoDocumentNode[];
};
computed: string;
}

export interface DetailsNode
extends BaseDocumentNode<[DetailsSummaryNode, DetailsContentNode]> {
type: 'details';
}

interface TableRow<T extends 'row' | 'header'> {
type: T;
order: T extends 'row' ? number : undefined;
Expand Down Expand Up @@ -144,7 +166,8 @@ export type TempoDocumentNode =
| BreakNode
| NumberListNode
| BulletListNode
| AlertNode;
| AlertNode
| DetailsNode;

export type TempoDocumentMetadata = md.Frontmatter | null;

Expand Down Expand Up @@ -406,6 +429,62 @@ export class TempoDocument {
|------------------
*/

/**
* Append a details element to the document.
*
* @example
* ```ts
* const doc = tempo()
* .details({
* summary: 'Click me',
* content: 'This is the content of the details element.'
* })
* .toString();
* // Output: <details>
* // <summary>Click me</summary>
* // This is the content of the details element.
* // </details>
* ```
*
* @param config - The configuration for the details element.
* @returns The TempoDocument instance with the details element appended.
*/
public details({
summary,
content,
}: {
summary: TempoTextInput;
content: Array<TempoTextInput | TempoDocumentNode>;
}): this {
this.nodes.push({
type: 'details',
data: {
nodes: [
{
type: 'details-summary',
data: {
nodes: computeNodes(summary),
},
computed: md.paragraph(computeText(summary)),
},
{
type: 'details-content',
data: {
nodes: content.map(computeNodes),
},
computed: content.map((node) => node.computed).join('\n'),
},
],
},
computed: md.details({
summary: md.paragraph(computeText(summary)),
content: transformToMarkdown(content),
}),
});

return this;
}

/**
* Append a table to the document.
*
Expand Down Expand Up @@ -736,11 +815,7 @@ export class TempoDocument {
* @returns A string representation of the document, that can be used for rendering.
*/
public toString(): string {
const result = this.nodes
.map((section) => section.computed)
.join('\n\n')
.trim()
.concat('\n');
const result = transformToMarkdown(this.nodes);

if (this.metadata) {
return md.frontmatter(this.metadata).concat('\n', result);
Expand Down Expand Up @@ -794,3 +869,11 @@ export class TempoDocument {
};
}
}

function transformToMarkdown(nodes: TempoDocumentNode[]): string {
return nodes
.map((section) => section.computed)
.join('\n\n')
.trim()
.concat('\n');
}
Loading