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

Added CSS.escape to font-family.ts #4545

Merged
merged 3 commits into from
Nov 18, 2023

Conversation

SanderLeenders
Copy link
Contributor

Please describe your changes

Added CSS.escape to renderHTML. Prevents invalid css when using fonts with numbers in their names, like https://fonts.google.com/specimen/Exo+2

How did you accomplish your changes

Added CSS.escape() to renderHTML

How have you tested your changes

Tested local

How can we verify your changes

Before Screenshot 2023-10-18 at 15 07 03
After
image

Remarks

Checklist

  • The changes are not breaking the editor
  • Added tests where possible
  • Followed the guidelines
  • Fixed linting issues

Related issues

@netlify
Copy link

netlify bot commented Oct 18, 2023

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit d7f1476
🔍 Latest deploy log https://app.netlify.com/sites/tiptap-embed/deploys/65574a014e5eb7000804b84f
😎 Deploy Preview https://deploy-preview-4545--tiptap-embed.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@janthurau janthurau self-assigned this Nov 17, 2023
Added CSS.escape to renderHTML. Prevents invalid css when using fonts with numbers in their names, like https://fonts.google.com/specimen/Exo+2
@janthurau
Copy link
Collaborator

@SanderLeenders I think this will also escape ,, if you specify multiple fonts, right? So we'd probably need to escape only the real font names. See on the demo:

image

@SanderLeenders
Copy link
Contributor Author

@janthurau you are right! I've added a fix for this.

@janthurau janthurau merged commit 8358a2b into ueberdosis:develop Nov 18, 2023
13 checks passed
@ricardasnav
Copy link

Hi
This change broke rendering on the server side where CSS is not available as a global variable. I use Cloudflare workers to render the output and now it throws.

@nperez0111
Copy link
Contributor

I'm not sure that this was the right move, I think I'm going to make a PR to revert this

@jonahallibone
Copy link

I'm not sure that this was the right move, I think I'm going to make a PR to revert this

This SO answer provides an alternate solution:

https://stackoverflow.com/questions/7638775/do-i-need-to-wrap-quotes-around-font-family-names-in-css

@nperez0111
Copy link
Contributor

I'm not sure that this was the right move, I think I'm going to make a PR to revert this

This SO answer provides an alternate solution:

stackoverflow.com/questions/7638775/do-i-need-to-wrap-quotes-around-font-family-names-in-css

Sorry there are a few recommendations here are you saying that we should wrap with "? That feels hackish.

Or maybe we can do what we did before and just wrap in " if it contains a number or space

nperez0111 added a commit that referenced this pull request May 17, 2024
Using `CSS.escape` is the wrong tool for the job here:
 - it is meant for CSS selectors and does not handle CSS variables properly.
 - you can't use `var(--title)` as a font-family because it was getting escaped to `var\(--title\)`

Instead this introduces using a regex to see if we should quote the font-family. Quoting when:
 - font-family includes at least one number or whitespace character
nperez0111 added a commit that referenced this pull request Jun 4, 2024
Using `CSS.escape` is the wrong tool for the job here:
 - it is meant for CSS selectors and does not handle CSS variables properly.
 - you can't use `var(--title)` as a font-family because it was getting escaped to `var\(--title\)`
@SanderLeenders
Copy link
Contributor Author

SanderLeenders commented Oct 18, 2024

Hi @nperez0111 I see that you have reverted my code. Therefor my original problem is back.

Currently, Titap can't handle input like this:
<p><span style="font-family: 'Exo 2'">This should be Exo 2, but it is not</span></p>

It gets rendered as:
<p><span style="font-family: Exo 2">This should be Exo 2, but it is not</span></p>
which is invalid.

Do you have any suggestions on how to fix or prevent this?

@SanderLeenders
Copy link
Contributor Author

Hi @nperez0111, have you seen my previous comment? I’d appreciate your input on this.

I agree that my solution was causing issues (e.g., CSS variables), but I also believe that TipTap's output should be a valid input for TipTap. If you have any suggestions, I’d love to hear them.

@nperez0111
Copy link
Contributor

Sorry for not getting back to you @SanderLeenders, I think the easiest thing to do here is to just have a basic polyfill for CSS.escape like this:

function cssEscape(value: string): string {
  const length = value.length;
  let result = '';

  for (let i = 0; i < length; i++) {
    const char = value.charAt(i);
    const code = char.charCodeAt(0);

    // If the character is a control character, or a non-printable character, or a space
    if (code < 0x20 || code === 0x7F || (code >= 0x80 && code <= 0x9F) || char === ' ') {
      result += '\\' + code.toString(16) + ' ';
    } else {
      // If the character is a special character in CSS
      switch (char) {
        case '\0':
          result += '\uFFFD';
          break;
        case '"':
        case '#':
        case '$':
        case '%':
        case '&':
        case '\'':
        case '(':
        case ')':
        case '*':
        case '+':
        case ',':
        case '.':
        case '/':
        case ':':
        case ';':
        case '<':
        case '=':
        case '>':
        case '?':
        case '@':
        case '[':
        case '\\':
        case ']':
        case '^':
        case '`':
        case '{':
        case '|':
        case '}':
        case '~':
          result += '\\' + char;
          break;
        default:
          result += char;
      }
    }
  }

  return result;
}

// Example usage
const escaped = cssEscape('Hello, world!');
console.log(escaped); // Output: Hello\,\ world\!

@SanderLeenders
Copy link
Contributor Author

Hi @nperez0111 thanks for your response.

Adding a polyfill could potentially work as a solution for @ricardasnav but I'm afraid it isn't a real solution. As you mentioned here (b84c62f) using CSS.escape leads to problems with CSS variables.

font-family: var(--title-font-family) //valid 
font-family: var\(--title-font-family\) //using CSS.escape or cssEscape is invalid

I've explored other solutions, but it seems the primary issue lies here:

parseHTML: element => element.style.fontFamily?.replace(/['"]+/g, ''),

In parseHTML, quotes are removed, which was introduced in 1af7829 However, it's unclear to me why this change was made.

Additionally, I found another potential solution in this commit: (b84c62f#diff-c07afc8dd73997be0302de13651fee649282c27b8da412598d9dc59b3e55ceeb) which suggests:

 style: `font-family: ${attributes.fontFamily.split(',')
                  .map((fontFamily: string) => (fontFamily.match(/(\d|\s)+/g) ? `"${fontFamily.trim()}"` : fontFamily.trim())).join(', ')}`,

However, this approach does not appear to have made it into production.

Thanks in advance for any additional insights you can provide!

@nperez0111
Copy link
Contributor

Haha, I wrote that last commit & forgot about it. The commit message reminded me. I don't know why that didn't make it!

@nperez0111
Copy link
Contributor

@SanderLeenders some comments on this here: #5164

@nperez0111
Copy link
Contributor

@SanderLeenders on further review, I think you are right that we should not be doing this quote removal on parsing the HTML. Can I leave this to you to open a new PR for this?

As long as we have our existing tests pass & any new cases that were not being handled I'd be happy to accept a PR here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

5 participants