From 628c4b23d7e5e5fe390863a06a7e8ba5a6a0846c Mon Sep 17 00:00:00 2001 From: MapleLeaf <19603573+itsMapleLeaf@users.noreply.github.com> Date: Mon, 20 Dec 2021 19:11:07 -0600 Subject: [PATCH] support embed singleton fields via props --- example.js | 25 ++++++---- notes.md | 6 +-- package.json | 2 + .../tests/rendering.test.tsx | 49 ++++++++++--------- packages/reacord/src/embed-author.tsx | 35 ------------- packages/reacord/src/embed.tsx | 38 +++++++++++--- packages/reacord/src/main.ts | 1 - pnpm-lock.yaml | 42 ++++++++++++++++ vitest.config.ts | 8 +++ 9 files changed, 128 insertions(+), 78 deletions(-) delete mode 100644 packages/reacord/src/embed-author.tsx create mode 100644 vitest.config.ts diff --git a/example.js b/example.js index 5f37024..60efcf5 100644 --- a/example.js +++ b/example.js @@ -13,11 +13,22 @@ function KitchenSink() { format="long|short|relative|etc" /> {/* embeds */} - - - author name - - title + description{"\n"} aaaaaaaaa field content @@ -28,10 +39,6 @@ function KitchenSink() { - - - footer content - {/* files */} diff --git a/notes.md b/notes.md index 9d0c5c4..554c1a1 100644 --- a/notes.md +++ b/notes.md @@ -6,10 +6,10 @@ - [x] color - [x] author - [x] description - - [ ] title - text children, url - - [ ] footer - icon url, timestamp, text children + - [x] title - text children, url + - [x] footer - icon url, timestamp, text children + - [x] thumbnail - url - [ ] image - url - - [ ] thumbnail - url - [ ] fields - name, value, inline - message components - [ ] buttons diff --git a/package.json b/package.json index c3fb25b..7e2dfbc 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@typescript-eslint/eslint-plugin": "^5.8.0", "@typescript-eslint/parser": "^5.8.0", "c8": "^7.10.0", + "chai": "^4.3.4", "eslint": "^8.5.0", "eslint-config-prettier": "^8.3.0", "eslint-import-resolver-typescript": "^2.5.0", @@ -26,6 +27,7 @@ "eslint-plugin-react-hooks": "^4.3.0", "eslint-plugin-unicorn": "^39.0.0", "prettier": "^2.5.1", + "should": "^13.2.3", "typescript": "^4.5.4", "vite": "^2.7.4", "vitest": "^0.0.102" diff --git a/packages/integration-tests/tests/rendering.test.tsx b/packages/integration-tests/tests/rendering.test.tsx index 8e56e89..8f9fe81 100644 --- a/packages/integration-tests/tests/rendering.test.tsx +++ b/packages/integration-tests/tests/rendering.test.tsx @@ -1,12 +1,13 @@ /* eslint-disable unicorn/no-null */ import type { Message } from "discord.js" import { Client, TextChannel } from "discord.js" +import { deepEqual } from "node:assert" import type { ReacordRoot } from "reacord" -import { createRoot, Embed, EmbedAuthor, Text } from "reacord" +import { createRoot, Embed, Text } from "reacord" import { pick } from "reacord-helpers/pick.js" import { raise } from "reacord-helpers/raise.js" import React from "react" -import { afterAll, beforeAll, expect, test } from "vitest" +import { afterAll, beforeAll, test } from "vitest" import { testBotToken, testChannelId } from "./test-environment.js" const client = new Client({ @@ -61,28 +62,20 @@ test("nested text", async () => { await assertMessages([{ content: "hi world hi moon hi sun" }]) }) -test("empty embed fallback", async () => { +test.only("empty embed fallback", async () => { await root.render() await assertMessages([{ embeds: [{ description: "_ _" }] }]) }) -test("embed with only author", async () => { - await root.render( - - only author - , - ) +test.only("embed with only author", async () => { + await root.render() await assertMessages([ { embeds: [{ description: "_ _", author: { name: "only author" } }] }, ]) }) test("empty embed author", async () => { - await root.render( - - - , - ) + await root.render() await assertMessages([{ embeds: [{ description: "_ _" }] }]) }) @@ -91,14 +84,25 @@ test("kitchen sink", async () => { <> message content no space - + description more description - - hi craw - another hi @@ -146,7 +150,8 @@ function extractMessageData(message: Message) { async function assertMessages(expected: Array>) { const messages = await channel.messages.fetch() - expect(messages.map((message) => extractMessageData(message))).toEqual( + deepEqual( + messages.map((message) => extractMessageData(message)), expected.map((message) => ({ content: "", ...message, diff --git a/packages/reacord/src/embed-author.tsx b/packages/reacord/src/embed-author.tsx deleted file mode 100644 index 2d8cbee..0000000 --- a/packages/reacord/src/embed-author.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import type { MessageEmbedOptions } from "discord.js" -import type { ReactNode } from "react" -import React from "react" -import { ContainerInstance } from "./container-instance.js" - -export type EmbedAuthorProps = { - url?: string - iconUrl?: string - children?: ReactNode -} - -export function EmbedAuthor({ children, ...options }: EmbedAuthorProps) { - return ( - new EmbedAuthorInstance(options)}> - {children} - - ) -} - -type EmbedAuthorOptions = Omit - -class EmbedAuthorInstance extends ContainerInstance { - readonly name = "EmbedAuthor" - - constructor(private readonly props: EmbedAuthorOptions) { - super({ warnOnNonTextChildren: true }) - } - - override renderToEmbed(options: MessageEmbedOptions) { - options.author ??= {} - options.author.name = this.getChildrenText() - options.author.url = this.props.url - options.author.iconURL = this.props.iconUrl - } -} diff --git a/packages/reacord/src/embed.tsx b/packages/reacord/src/embed.tsx index 90ff810..8a69212 100644 --- a/packages/reacord/src/embed.tsx +++ b/packages/reacord/src/embed.tsx @@ -8,13 +8,26 @@ import React from "react" import { ContainerInstance } from "./container-instance.js" export type EmbedProps = { + title?: string color?: ColorResolvable + url?: string + timestamp?: Date | number | string + thumbnailUrl?: string + author?: { + name?: string + url?: string + iconUrl?: string + } + footer?: { + text?: string + iconUrl?: string + } children?: ReactNode } export function Embed(props: EmbedProps) { return ( - new EmbedInstance(props.color)}> + new EmbedInstance(props)}> {props.children} ) @@ -23,22 +36,31 @@ export function Embed(props: EmbedProps) { class EmbedInstance extends ContainerInstance { readonly name = "Embed" - constructor(readonly color?: ColorResolvable) { + constructor(readonly props: EmbedProps) { super({ warnOnNonTextChildren: false }) } override renderToMessage(message: MessageOptions) { message.embeds ??= [] - message.embeds.push(this.embedOptions) + message.embeds.push(this.getEmbedOptions()) } - get embedOptions(): MessageEmbedOptions { - /* eslint-disable unicorn/no-null */ + getEmbedOptions(): MessageEmbedOptions { const options: MessageEmbedOptions = { - color: this.color, - description: null as unknown as undefined, + ...this.props, + author: { + ...this.props.author, + iconURL: this.props.author?.iconUrl, + }, + footer: { + text: "", + ...this.props.footer, + iconURL: this.props.footer?.iconUrl, + }, + timestamp: this.props.timestamp + ? new Date(this.props.timestamp) // this _may_ need date-fns to parse this + : undefined, } - /* eslint-enable unicorn/no-null */ for (const child of this.children) { if (!child.renderToEmbed) { diff --git a/packages/reacord/src/main.ts b/packages/reacord/src/main.ts index 2edf69b..67e81d1 100644 --- a/packages/reacord/src/main.ts +++ b/packages/reacord/src/main.ts @@ -1,4 +1,3 @@ -export * from "./embed-author.js" export * from "./embed.js" export * from "./root.js" export * from "./text.js" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee534c1..0258312 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,7 @@ importers: '@typescript-eslint/eslint-plugin': ^5.8.0 '@typescript-eslint/parser': ^5.8.0 c8: ^7.10.0 + chai: ^4.3.4 eslint: ^8.5.0 eslint-config-prettier: ^8.3.0 eslint-import-resolver-typescript: ^2.5.0 @@ -17,6 +18,7 @@ importers: eslint-plugin-react-hooks: ^4.3.0 eslint-plugin-unicorn: ^39.0.0 prettier: ^2.5.1 + should: ^13.2.3 typescript: ^4.5.4 vite: ^2.7.4 vitest: ^0.0.102 @@ -25,6 +27,7 @@ importers: '@typescript-eslint/eslint-plugin': 5.8.0_836011a006f4f5d67178564baf2b6d34 '@typescript-eslint/parser': 5.8.0_eslint@8.5.0+typescript@4.5.4 c8: 7.10.0 + chai: 4.3.4 eslint: 8.5.0 eslint-config-prettier: 8.3.0_eslint@8.5.0 eslint-import-resolver-typescript: 2.5.0_f385d671d5f1c72a868db745a891bc1f @@ -34,6 +37,7 @@ importers: eslint-plugin-react-hooks: 4.3.0_eslint@8.5.0 eslint-plugin-unicorn: 39.0.0_eslint@8.5.0 prettier: 2.5.1 + should: 13.2.3 typescript: 4.5.4 vite: 2.7.4 vitest: 0.0.102_c8@7.10.0+vite@2.7.4 @@ -3982,6 +3986,44 @@ packages: engines: {node: '>=8'} dev: true + /should-equal/2.0.0: + resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==} + dependencies: + should-type: 1.4.0 + dev: true + + /should-format/3.0.3: + resolution: {integrity: sha1-m/yPdPo5IFxT04w01xcwPidxJPE=} + dependencies: + should-type: 1.4.0 + should-type-adaptors: 1.1.0 + dev: true + + /should-type-adaptors/1.1.0: + resolution: {integrity: sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==} + dependencies: + should-type: 1.4.0 + should-util: 1.0.1 + dev: true + + /should-type/1.4.0: + resolution: {integrity: sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=} + dev: true + + /should-util/1.0.1: + resolution: {integrity: sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==} + dev: true + + /should/13.2.3: + resolution: {integrity: sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==} + dependencies: + should-equal: 2.0.0 + should-format: 3.0.3 + should-type: 1.4.0 + should-type-adaptors: 1.1.0 + should-util: 1.0.1 + dev: true + /side-channel/1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..b220064 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,8 @@ +// eslint-disable-next-line import/no-unused-modules +export default { + test: { + deps: { + inline: ["should"], + }, + }, +}