diff --git a/package.json b/package.json index 909d7a817..d29e662f7 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "rudder-sdk-js": "^2.20.0", "sanitize-html": "^2.10.0", "styled-components": "^6.0.8", + "tiptap-markdown": "^0.8.4", "use-react-router-breadcrumbs": "^3.0.1", "viem": "^1.4.2", "wagmi": "^1.3.9" diff --git a/src/containers/defineProposal/index.tsx b/src/containers/defineProposal/index.tsx index 023a7a301..19172d14f 100644 --- a/src/containers/defineProposal/index.tsx +++ b/src/containers/defineProposal/index.tsx @@ -6,13 +6,15 @@ import { TextareaWYSIWYG, TextInput, } from '@aragon/ods-old'; +import StarterKit from '@tiptap/starter-kit'; +import {Markdown} from 'tiptap-markdown'; import React, {useEffect, useState} from 'react'; import styled from 'styled-components'; import {useTranslation} from 'react-i18next'; import AddLinks from 'components/addLinks'; import {useWallet} from 'hooks/useWallet'; -import {StringIndexed} from 'utils/types'; +import {ProposalFormData, StringIndexed} from 'utils/types'; import {Controller, useFormContext, useWatch} from 'react-hook-form'; import {isOnlyWhitespace} from 'utils/library'; import {UpdateListItem} from 'containers/updateListItem/updateListItem'; @@ -20,16 +22,36 @@ import {useParams} from 'react-router-dom'; import {VersionSelectionMenu} from 'containers/versionSelectionMenu/versionSelectionMenu'; import {useUpdateContext} from 'context/update'; import {Loading} from 'components/temporary'; +import {useDaoDetailsQuery} from 'hooks/useDaoDetails'; +import {useReleaseNotes} from 'services/aragon-sdk/queries/use-release-notes'; +import {osxUpdates} from 'utils/osxUpdates'; +import {useEditor} from '@tiptap/react'; +import {useProtocolVersions} from 'hooks/useDaoVersions'; const DefineProposal: React.FC = () => { const {t} = useTranslation(); const {address, ensAvatarUrl} = useWallet(); const {control, setValue} = useFormContext(); + const {data: dao} = useDaoDetailsQuery(); const {handlePreparePlugin, osxAvailableVersions, pluginAvailableVersions} = useUpdateContext(); - const pluginSelectedVersion = useWatch({name: 'pluginSelectedVersion'}); - const osSelectedVersion = useWatch({name: 'osSelectedVersion'}); + const {data: releases} = useReleaseNotes(); + const editor = useEditor({extensions: [StarterKit, Markdown]}); + const {data: versions} = useProtocolVersions(dao?.address); + + const pluginSelectedVersion = useWatch< + ProposalFormData, + 'pluginSelectedVersion' + >({ + name: 'pluginSelectedVersion', + }); + const osSelectedVersion = useWatch({ + name: 'osSelectedVersion', + }); + const updateFramework = useWatch({ + name: 'updateFramework', + }); const {type} = useParams(); const [showModal, setShowModal] = useState<{ @@ -43,10 +65,14 @@ const DefineProposal: React.FC = () => { const UpdateItems = [ { id: 'os', - label: `Aragon OSx v${osSelectedVersion?.version}`, - helptext: 'TBD inline release notes', - LinkLabel: t('update.item.releaseNotesLabel'), - ...(osxAvailableVersions?.get(osSelectedVersion?.version)?.isLatest && { + label: osxUpdates.getProtocolUpdateLabel(osSelectedVersion?.version), + releaseNote: osxUpdates.getReleaseNotes({ + releases, + version: osSelectedVersion?.version, + }), + linkLabel: t('update.item.releaseNotesLabel'), + ...(osxAvailableVersions?.get(osSelectedVersion?.version ?? '') + ?.isLatest && { tagLabelNatural: t('update.item.tagLatest'), }), buttonSecondaryLabel: t('update.item.versionCtaLabel'), @@ -61,16 +87,20 @@ const DefineProposal: React.FC = () => { }, { id: 'plugin', - label: `Token voting v${pluginSelectedVersion?.version.release}.${pluginSelectedVersion?.version.build}`, - helptext: 'TBD inline release notes', - LinkLabel: t('update.item.releaseNotesLabel'), + releaseNote: osxUpdates.getReleaseNotes({ + releases, + version: pluginSelectedVersion?.version, + isPlugin: true, + }), + label: osxUpdates.getPluginUpdateLabel(pluginSelectedVersion?.version), + linkLabel: t('update.item.releaseNotesLabel'), ...(pluginAvailableVersions?.get( - `${pluginSelectedVersion?.version.release}.${pluginSelectedVersion?.version.build}` + osxUpdates.getPluginVersion(pluginSelectedVersion?.version) ?? '' )?.isLatest && { tagLabelNatural: t('update.item.tagLatest'), }), ...(pluginAvailableVersions?.get( - `${pluginSelectedVersion?.version.release}.${pluginSelectedVersion?.version.build}` + osxUpdates.getPluginVersion(pluginSelectedVersion?.version) ?? '' )?.isPrepared ? { tagLabelInfo: t('update.item.tagPrepared'), @@ -93,13 +123,100 @@ const DefineProposal: React.FC = () => { useEffect(() => { if (type === 'os-update') { - setValue('proposalTitle', 'Aragon Update'); - setValue( - 'proposalSummary', - 'This is an update for your Aragon OSx based DAO. Review all the details and vote for it.' - ); + const proposalTitle = t('update.proposal.title'); + const proposalSummary = t('update.proposal.summary', { + daoName: dao?.metadata.name, + }); + + setValue('proposalTitle', proposalTitle); + setValue('proposalSummary', proposalSummary); + } + }, [setValue, type, dao, t]); + + useEffect(() => { + if (type === 'os-update') { + let proposalBody = t('update.proposal.descriptionHeader'); + + if (updateFramework?.os) { + const updatedVersion = osxUpdates.getProtocolUpdateLabel( + osSelectedVersion?.version + ); + const releaseNotes = osxUpdates.getReleaseNotes({ + releases, + version: osSelectedVersion?.version, + }); + editor?.commands.setContent(releaseNotes?.summary ?? ''); + proposalBody += t('update.proposal.descriptionProtocolUpgrade', { + updatedVersion, + description: editor?.getHTML().replace(/<(\/){0,1}p>/g, ''), + releaseNotesLink: releaseNotes?.html_url, + currentVersion: osxUpdates.getProtocolUpdateLabel(versions), + }); + } + if (updateFramework?.plugin) { + // Add space between the two updates + if (updateFramework.os) { + proposalBody += '

'; + } + + const updatedVersion = osxUpdates.getPluginUpdateLabel( + pluginSelectedVersion?.version + ); + const releaseNotes = osxUpdates.getReleaseNotes({ + releases, + version: pluginSelectedVersion?.version, + isPlugin: true, + }); + editor?.commands.setContent(releaseNotes?.summary ?? ''); + proposalBody += t('update.proposal.descriptionPluginUpgrade', { + updatedVersion, + description: editor?.getHTML().replace(/<(\/){0,1}p>/g, ''), + releaseNotesLink: releaseNotes?.html_url, + currentVersion: osxUpdates.getPluginUpdateLabel(dao?.plugins[0]), + }); + } + + proposalBody += t('update.proposal.descriptionFooter'); + + setValue('proposal', proposalBody); + } + }, [ + setValue, + type, + dao, + t, + editor, + versions, + releases, + osSelectedVersion, + pluginSelectedVersion, + updateFramework, + ]); + + useEffect(() => { + if (type === 'os-update') { + let index = 0; + setValue('actions', []); + if (updateFramework?.os && pluginSelectedVersion?.version) { + setValue(`actions.${index}.name`, 'os_update'); + setValue(`actions.${index}.inputs.version`, osSelectedVersion?.version); + index++; + } + if (updateFramework?.plugin && pluginSelectedVersion?.version) { + setValue(`actions.${index}.name`, 'plugin_update'); + setValue(`actions.${index}.inputs`, { + versionTag: pluginSelectedVersion?.version, + }); + } } - }, [setValue, type]); + }, [ + osSelectedVersion?.version, + pluginSelectedVersion?.version, + setValue, + type, + updateFramework?.os, + updateFramework?.plugin, + ]); if (!pluginSelectedVersion) { return ; diff --git a/src/containers/reviewProposal/index.tsx b/src/containers/reviewProposal/index.tsx index 97f7af9f6..3e0dd771c 100644 --- a/src/containers/reviewProposal/index.tsx +++ b/src/containers/reviewProposal/index.tsx @@ -3,10 +3,11 @@ import {Erc20TokenDetails} from '@aragon/sdk-client'; import TipTapLink from '@tiptap/extension-link'; import {EditorContent, useEditor} from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; +import {Markdown} from 'tiptap-markdown'; import {Locale, format, formatDistanceToNow} from 'date-fns'; import * as Locales from 'date-fns/locale'; import React, {useEffect, useMemo} from 'react'; -import {useFormContext, useWatch} from 'react-hook-form'; +import {useFormContext} from 'react-hook-form'; import {useTranslation} from 'react-i18next'; import {TFunction} from 'i18next'; import styled from 'styled-components'; @@ -35,7 +36,6 @@ import { } from 'utils/date'; import {getErc20VotingParticipation, getNonEmptyActions} from 'utils/proposals'; import {ProposalResource, SupportedVotingSettings} from 'utils/types'; -import {useParams} from 'react-router-dom'; type ReviewProposalProps = { defineProposalStepNumber: number; @@ -48,10 +48,6 @@ const ReviewProposal: React.FC = ({ }) => { const {t, i18n} = useTranslation(); const {setStep} = useFormStep(); - const {type} = useParams(); - const pluginSelectedVersion = useWatch({name: 'pluginSelectedVersion'}); - const osSelectedVersion = useWatch({name: 'osSelectedVersion'}); - const updateFramework = useWatch({name: 'updateFramework'}); const {data: daoDetails, isLoading: detailsLoading} = useDaoDetailsQuery(); const pluginAddress = daoDetails?.plugins?.[0]?.instanceAddress as string; @@ -76,6 +72,7 @@ const ReviewProposal: React.FC = ({ content: values.proposal, extensions: [ StarterKit, + Markdown, TipTapLink.configure({ openOnClick: false, }), @@ -219,31 +216,6 @@ const ReviewProposal: React.FC = ({ } }, [setValue, values.proposal]); - useEffect(() => { - if (type === 'os-update') { - let index = 0; - setValue('actions', []); - if (updateFramework.os && pluginSelectedVersion?.version) { - setValue(`actions.${index}.name`, 'os_update'); - setValue(`actions.${index}.inputs.version`, osSelectedVersion?.version); - index++; - } - if (updateFramework.plugin && pluginSelectedVersion?.version) { - setValue(`actions.${index}.name`, 'plugin_update'); - setValue(`actions.${index}.inputs`, { - versionTag: pluginSelectedVersion.version, - }); - } - } - }, [ - osSelectedVersion?.version, - pluginSelectedVersion.version, - setValue, - type, - updateFramework.os, - updateFramework.plugin, - ]); - /************************************************* * Render * *************************************************/ @@ -268,11 +240,7 @@ const ReviewProposal: React.FC = ({ - {values.proposal && ( - <> - - - )} + {values.proposal && } {/* */} diff --git a/src/containers/updateListItem/updateListItem.tsx b/src/containers/updateListItem/updateListItem.tsx index a4fc883db..d999bd65f 100644 --- a/src/containers/updateListItem/updateListItem.tsx +++ b/src/containers/updateListItem/updateListItem.tsx @@ -8,8 +8,12 @@ import { Link, Tag, } from '@aragon/ods-old'; -import React from 'react'; +import {EditorContent, useEditor} from '@tiptap/react'; +import StarterKit from '@tiptap/starter-kit'; +import {Markdown} from 'tiptap-markdown'; +import React, {useEffect} from 'react'; import styled from 'styled-components'; +import {IReleaseNote} from 'services/aragon-sdk/domain/release-note'; export const Icons = { multiSelect: { @@ -25,9 +29,9 @@ export const Icons = { }; export type CheckboxListItemProps = { - label: string; - helptext?: string; - LinkLabel: string; + label?: string; + linkLabel: string; + releaseNote?: IReleaseNote; tagLabelNatural?: string; tagLabelInfo?: string; disabled?: boolean; @@ -43,8 +47,8 @@ export type CheckboxListItemProps = { // TODO: This might be a component that export const UpdateListItem: React.FC = ({ label, - helptext, - LinkLabel, + linkLabel, + releaseNote, tagLabelNatural, tagLabelInfo, disabled = false, @@ -56,6 +60,16 @@ export const UpdateListItem: React.FC = ({ onClickActionPrimary, onClickActionSecondary, }) => { + const editor = useEditor({ + editable: false, + extensions: [StarterKit, Markdown], + }); + + // Update editor content on release notes change + useEffect(() => { + editor?.commands.setContent(releaseNote?.summary ?? ''); + }, [editor, releaseNote]); + return ( @@ -70,8 +84,14 @@ export const UpdateListItem: React.FC = ({ {Icons[multiSelect ? 'multiSelect' : 'radio'][type]} - {helptext} - } /> + + + + } + href={releaseNote?.html_url} + /> {(buttonPrimaryLabel || buttonSecondaryLabel) && (

diff --git a/src/containers/versionSelectionMenu/versionSelectionMenu.tsx b/src/containers/versionSelectionMenu/versionSelectionMenu.tsx index 127c70c21..29f65c2df 100644 --- a/src/containers/versionSelectionMenu/versionSelectionMenu.tsx +++ b/src/containers/versionSelectionMenu/versionSelectionMenu.tsx @@ -7,6 +7,9 @@ import {VersionTag} from '@aragon/sdk-client-common'; import {Controller, useFormContext} from 'react-hook-form'; import {useTranslation} from 'react-i18next'; import styled from 'styled-components'; +import {osxUpdates} from 'utils/osxUpdates'; +import {IReleaseNote} from 'services/aragon-sdk/domain/release-note'; +import {useReleaseNotes} from 'services/aragon-sdk/queries/use-release-notes'; export type CheckboxListItemProps = { showModal: { @@ -17,9 +20,9 @@ export type CheckboxListItemProps = { }; type versionList = { - label: string; + label?: string; version: string | VersionTag; - helptext: string; + releaseNote?: IReleaseNote; isLatest?: boolean; isPrepared?: boolean; tagLabelNatural?: string; @@ -33,15 +36,18 @@ export const VersionSelectionMenu: React.FC = ({ const {t} = useTranslation(); const {control} = useFormContext(); const {osxAvailableVersions, pluginAvailableVersions} = useUpdateContext(); + const {data: releases} = useReleaseNotes(); const osVersionList = useMemo(() => { const List: versionList[] = []; osxAvailableVersions?.forEach(value => { - console.log('value', value.version, osxAvailableVersions); List.push({ - label: `OSX v${value.version}`, + label: osxUpdates.getProtocolUpdateLabel(value.version), + releaseNote: osxUpdates.getReleaseNotes({ + releases, + version: value.version, + }), version: value.version, - helptext: 'TBD inline release notes', ...(Boolean(value.isLatest) && { isLatest: true, tagLabelNatural: t('update.item.tagLatest'), @@ -49,15 +55,19 @@ export const VersionSelectionMenu: React.FC = ({ }); }); return List; - }, [osxAvailableVersions, t]); + }, [osxAvailableVersions, releases, t]); const pluginVersionList = useMemo(() => { const List: versionList[] = []; pluginAvailableVersions?.forEach(value => { List.push({ - label: `Token voting v${value.version.release}.${value.version.build}`, + label: osxUpdates.getPluginUpdateLabel(value.version), version: value.version, - helptext: 'TBD inline release notes', + releaseNote: osxUpdates.getReleaseNotes({ + releases, + version: value.version, + isPlugin: true, + }), ...(value.isLatest && { isLatest: true, tagLabelNatural: t('update.item.tagLatest'), @@ -69,7 +79,7 @@ export const VersionSelectionMenu: React.FC = ({ }); }); return List; - }, [pluginAvailableVersions, t]); + }, [pluginAvailableVersions, releases, t]); return ( = ({ ( + render={({field: {onChange, value: fieldValue}}) => ( <> {osVersionList.map((data, index) => { @@ -92,11 +102,11 @@ export const VersionSelectionMenu: React.FC = ({ {...data} key={index} type={ - value23?.version === data.version + fieldValue?.version === data.version ? 'active' : 'default' } - LinkLabel={t('update.item.releaseNotesLabel')} + linkLabel={t('update.item.releaseNotesLabel')} onClick={() => onChange({ version: data.version, @@ -131,7 +141,7 @@ export const VersionSelectionMenu: React.FC = ({ ? 'active' : 'default' } - LinkLabel={t('update.item.releaseNotesLabel')} + linkLabel={t('update.item.releaseNotesLabel')} onClick={() => onChange({ version: data.version, diff --git a/src/locales/en/common.json b/src/locales/en/common.json index 334102889..90e11fb59 100644 --- a/src/locales/en/common.json +++ b/src/locales/en/common.json @@ -1606,7 +1606,13 @@ "descLinkURL": "https://aragon.org/how-to/update-your-aragon-dao" }, "proposal": { - "bannerTitle": "Verified Aragon App Update" + "bannerTitle": "Verified Update", + "title": "Aragon OSx Update", + "summary": "This proposal is an Aragon OSx Update for {{daoName}}. The title, summary, and description text are automatically generated by Aragon App.", + "descriptionFooter": "


It is essential to consider the implications of upgrades before voting. Read the above release notes and confirm that this OSx Update passes Aragon’s Security Verification.

", + "descriptionHeader": "

This proposal contains on-chain transactions that would upgrade specific smart contract components as follows:

    ", + "descriptionProtocolUpgrade": "
  1. \n{{updatedVersion}}\n
      \n
    1. Current version: {{currentVersion}}
    2. \n
    3. Upgrade description: {{description}}
    4. \n
      1. View Release Notes
      \n
    5. Note: The DAO’s address will never change
    6. \n
    ", + "descriptionPluginUpgrade": "
  2. \n{{updatedVersion}}\n
      \n
    1. Current version: {{currentVersion}}
    2. \n
    3. Upgrade description: {{description}}
    4. \n
      1. View Release Notes
      \n
    " }, "modalCritical": { "title": "Are you sure you want to proceed?", @@ -1651,4 +1657,4 @@ "membersDesc": "These addresses form the governing body that approves and executes proposals passed by the community. Add the addresses who will be members of the execution multisig." } } -} \ No newline at end of file +} diff --git a/src/services/aragon-sdk/domain/release-note.ts b/src/services/aragon-sdk/domain/release-note.ts new file mode 100644 index 000000000..3f83e2201 --- /dev/null +++ b/src/services/aragon-sdk/domain/release-note.ts @@ -0,0 +1,16 @@ +export interface IGithubReleaseNote { + url: string; + id: number; + tag_name: string; + html_url: string; + name: string; + draft: boolean; + prerelease: boolean; + created_at: string; + published_at: string; + body: string; +} + +export interface IReleaseNote extends IGithubReleaseNote { + summary: string; +} diff --git a/src/services/aragon-sdk/queries/use-release-notes.ts b/src/services/aragon-sdk/queries/use-release-notes.ts new file mode 100644 index 000000000..cdc9d6071 --- /dev/null +++ b/src/services/aragon-sdk/queries/use-release-notes.ts @@ -0,0 +1,33 @@ +import {UseQueryOptions, useQuery} from '@tanstack/react-query'; +import {aragonSdkQueryKeys} from '../query-keys'; +import {IGithubReleaseNote, IReleaseNote} from '../domain/release-note'; + +// The regex extracts everything between the "Summary" title and the next title (or the end of the string). +const summaryRegex = /(?<=## Summary)(.*?)(?=#{2,}|$)/; + +const parseReleaseNote = (release: IGithubReleaseNote): IReleaseNote => { + const parsedBody = release.body.replace(/\r\n/g, ' '); + const summary = summaryRegex.exec(parsedBody)?.[0].trim() ?? ''; + + return {...release, summary}; +}; + +// TODO: use SDK when the functionality is implemented there +// (see https://aragonassociation.atlassian.net/browse/OS-808) +const fetchReleaseNotes = async (): Promise => { + const data = await fetch('https://api.github.com/repos/aragon/osx/releases'); + const releaseNotes = (await data.json()) as IGithubReleaseNote[]; + const parsedReleaseNotes = releaseNotes.map(parseReleaseNote); + + return parsedReleaseNotes; +}; + +export const useReleaseNotes = ( + options: UseQueryOptions = {} +) => { + return useQuery( + aragonSdkQueryKeys.releaseNotes(), + () => fetchReleaseNotes(), + options + ); +}; diff --git a/src/services/aragon-sdk/query-keys.ts b/src/services/aragon-sdk/query-keys.ts index 517809a26..da012cc63 100644 --- a/src/services/aragon-sdk/query-keys.ts +++ b/src/services/aragon-sdk/query-keys.ts @@ -21,6 +21,7 @@ export enum AragonSdkQueryItem { LOCAL_PROPOSALS = 'LOCAL_PROPOSALS', VOTING_POWER = 'VOTING_POWER', VOTING_SETTINGS = 'VOTING_SETTINGS', + RELEASE_NOTES = 'RELEASE_NOTES', } // Add address and network parameters to all query keys to use the most updated DAO plugin client @@ -62,4 +63,5 @@ export const aragonSdkQueryKeys = { AragonSdkQueryItem.VOTING_SETTINGS, params, ], + releaseNotes: (): QueryKey => [AragonSdkQueryItem.RELEASE_NOTES], }; diff --git a/src/utils/osxUpdates.ts b/src/utils/osxUpdates.ts new file mode 100644 index 000000000..48fe99ff6 --- /dev/null +++ b/src/utils/osxUpdates.ts @@ -0,0 +1,57 @@ +import {IReleaseNote} from 'services/aragon-sdk/domain/release-note'; +import {VersionTag} from '@aragon/sdk-client-common'; + +export interface IGetReleaseNotesParams { + releases?: IReleaseNote[]; + version?: string | VersionTag; + isPlugin?: boolean; +} + +class OsxUpdates { + latestRelease = '1.3.0'; + + getProtocolUpdateLabel = ( + version?: string | [number, number, number] + ): string | undefined => { + const processedVersion = Array.isArray(version) + ? version.join('.') + : version; + + return processedVersion ? `Aragon OSx v${processedVersion}` : undefined; + }; + + getPluginVersion = (version?: VersionTag): string | undefined => { + const {release, build} = version ?? {}; + + return release ? `${release}.${build}` : undefined; + }; + + getPluginUpdateLabel = (version?: VersionTag): string | undefined => { + const pluginVersion = this.getPluginVersion(version); + + return pluginVersion ? `Token voting v${pluginVersion}` : undefined; + }; + + getReleaseNotes = ({ + releases, + version, + isPlugin, + }: IGetReleaseNotesParams): IReleaseNote | undefined => { + if (version == null) { + return undefined; + } + + const processedVersion = + typeof version === 'string' ? version : this.getPluginVersion(version)!; + + const releaseNotes = releases?.find(release => + release.tag_name.includes( + isPlugin ? this.latestRelease : processedVersion + ) + ); + + return releaseNotes; + }; +} + +export const osxUpdates = new OsxUpdates(); diff --git a/src/utils/types.ts b/src/utils/types.ts index 704bebd99..8812a2e2d 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -539,6 +539,15 @@ export interface Link { url: string; } +export interface OsSelectedVersion { + version: string; +} + +export interface PluginSelectedVersion { + version: VersionTag; + isPrepared: boolean; +} + export interface ProposalFormData { actions: Action[]; startDate: string; @@ -565,13 +574,8 @@ export interface ProposalFormData { os: boolean; plugin: boolean; }; - osSelectedVersion?: { - version: string; - }; - pluginSelectedVersion?: { - version: VersionTag; - isPrepared: boolean; - }; + osSelectedVersion?: OsSelectedVersion; + pluginSelectedVersion?: PluginSelectedVersion; } export type ProposalSettingsFormData = ProposalFormData & { diff --git a/yarn.lock b/yarn.lock index ec34e2c0f..5a12ae22a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3995,6 +3995,24 @@ dependencies: "@types/node" "*" +"@types/linkify-it@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.5.tgz#1e78a3ac2428e6d7e6c05c1665c242023a4601d8" + integrity sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw== + +"@types/markdown-it@^12.2.3": + version "12.2.3" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" + integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ== + dependencies: + "@types/linkify-it" "*" + "@types/mdurl" "*" + +"@types/mdurl@*": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.5.tgz#3e0d2db570e9fb6ccb2dc8fde0be1d79ac810d39" + integrity sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA== + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" @@ -13013,6 +13031,11 @@ map-stream@~0.1.0: resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== +markdown-it-task-lists@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz#f68f4d2ac2bad5a2c373ba93081a1a6848417088" + integrity sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA== + markdown-it@^13.0.1: version "13.0.1" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430" @@ -14567,6 +14590,14 @@ prosemirror-markdown@^1.10.1: markdown-it "^13.0.1" prosemirror-model "^1.0.0" +prosemirror-markdown@^1.11.1: + version "1.11.2" + resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.11.2.tgz#f6e529e669d11fa3eec859e93c0d2c91788d6c80" + integrity sha512-Eu5g4WPiCdqDTGhdSsG9N6ZjACQRYrsAkrF9KYfdMaCmjIApH75aVncsWYOJvEk2i1B3i8jZppv3J/tnuHGiUQ== + dependencies: + markdown-it "^13.0.1" + prosemirror-model "^1.0.0" + prosemirror-menu@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.2.tgz#c545a2de0b8cb79babc07682b1d93de0f273aa33" @@ -16857,6 +16888,16 @@ tippy.js@^6.3.7: dependencies: "@popperjs/core" "^2.9.0" +tiptap-markdown@^0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/tiptap-markdown/-/tiptap-markdown-0.8.4.tgz#d6cdbd6e4aa88b58c3c149c2d0d25c70b3e11ac9" + integrity sha512-aCwr8cpVdZeb/2J0ffz8PvpLmQBcFE9GOxk2vB0Y9zlJEGWnSiGo1BWnwaeiyAdQqfBzV7NyNg+oz2A/MbC/Sg== + dependencies: + "@types/markdown-it" "^12.2.3" + markdown-it "^13.0.1" + markdown-it-task-lists "^2.1.1" + prosemirror-markdown "^1.11.1" + title-case@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"