Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(prose): update typing for Link #360

Merged
merged 11 commits into from
Jul 29, 2024
Merged

fix(prose): update typing for Link #360

merged 11 commits into from
Jul 29, 2024

Conversation

seaerchin
Copy link
Contributor

Problem

We need to allow users to set links inside our tiptap component. However, tiptap sets teh href attribute inside the attrs object whereas our validator expects a top level href attribute. this causes any link insertion to break on validation.

Solution

  • Update the LinkMarkSchema to be Unsafe to avoid deeply nested types
  • Update the LinkMarkSchema to have a href attribute so that validation can pass

@seaerchin seaerchin requested a review from a team as a code owner July 24, 2024 11:22
Copy link

vercel bot commented Jul 24, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
isomer-studio ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 29, 2024 4:53am

Comment on lines +137 to +139
attrs: {
href: child.permalink,
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only relevant change because we update the href to be inside attrs now. i searched the 2 .js files in this directory to check if we needed to update href

fact-check me @dcshzj if this is enoguh

Base automatically changed from feat/prose-renderer to main July 24, 2024 11:48
Comment on lines 44 to 59
target: Type.Union([
// NOTE: Taken with reference to
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-target
// There's technically 1 more property - unfencedTop but we're disallowing
// because it allows embedded frames to traverse beyond its root
Type.Literal("_blank"),
Type.Literal("_self"),
Type.Literal("_parent"),
Type.Literal("_top"),
]),
// NOTE: The href given by tiptap here
// https://github.com/ueberdosis/tiptap/blob/main/packages/extension-link/src/link.ts
// defaults to `null` href but href could also be passed as `undefined`
href: Type.Union([Type.String(), Type.Null()]),
rel: Type.String(),
class: Type.Union([Type.String(), Type.Null()]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: I don't think we should match the schema that Tiptap provides entirely, our schema is intended to be a subset of the schema because we only want to allow certain behaviours instead of all the available options that HTML/Tiptap provides. Adding all here means we lose the signal on what is allowed and what isn't.

In general we override the rel and class when we output to the user, so those properties will be ignored. For target we should only support _blank.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done - where do i see the properties that we strip? couldn't find a Text component

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly in getSanitizedInlineContent.ts:

export const getSanitizedInlineContent = (content: string) => {
DOMPurify.addHook("beforeSanitizeElements", (curr) => {
// Add rel="noopener noreferrer nofollow" to all anchor tags and
// open them in a new tab, if they point to an external site
if (curr.tagName !== "A") {
return curr
}
const href = curr.getAttribute("href")
if (href && (href.startsWith("http://") || href.startsWith("https://"))) {
curr.setAttribute("rel", "noopener noreferrer nofollow")
curr.setAttribute("target", "_blank")
}
return curr
})
const sanitizedContent = DOMPurify.sanitize(content, {
ALLOWED_TAGS: [
"b", // bold
"strong", // bold
"i", // italic
"em", // italic
"u", // underline
"s", // strikethrough
"del", // strikethrough
"strike", // strikethrough
"sub", // subscript
"sup", // superscript
"a", // anchor
"br", // line break
"code", // code
],
ALLOWED_ATTR: ["href", "rel", "target"],
})
return sanitizedContent
}

{
type: Type.Literal("link", { default: "link" }),
href: Type.String(),
attrs: Type.Object({
target: Type.Literal("_blank"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: hmm this property should be optional

Suggested change
target: Type.Literal("_blank"),
target: Type.Optional(Type.Literal("_blank")),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think that's quite right because we're using tiptap's link schema. they default it to the options.target, which is _blank by default, see ss

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm but we are not using Tiptap's link schema entirely. In HTML it is entirely possible to omit the target attribute and the link will have a default behaviour of _self. This schema means that all links must have _blank, which may not be the case for internal links.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right! i misunderstood the schema here because i thought it was only validating tiptap. i'll set it to optional("_self" | "_blank") wdyt?

@seaerchin seaerchin requested review from dcshzj and a team July 26, 2024 05:49
@seaerchin seaerchin merged commit 98fbbde into main Jul 29, 2024
17 of 19 checks passed
@seaerchin seaerchin deleted the fix/prose-link branch July 29, 2024 06:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants