a8cteam51 / special-projects-blocks-monorepo

MIT License
8 stars 1 forks source link

Add a SVG-based Stretchy Type block #32

Open DAreRodz opened 1 month ago

DAreRodz commented 1 month ago

Co-authored by @SantosGuillamot

What?

This PR adds a Stretchy block that makes its text fill all the available width. It's built on top of https://github.com/a8cteam51/special-projects-blocks-monorepo/pull/5.

The PR changes the block implementation, using SVGs to maintain the text ratio and some JavaScript code to update it whenever the text changes.

Features:

https://github.com/user-attachments/assets/d41a247c-d600-41f0-ba80-8762d1213370

How?

The implementation uses the following APIs, listed with the global usage % of browsers that support them:

The main idea is to use an SVG wrapper with foreingObject around the HTML code of the block content. With the SVG wrapper, we can use the viewBox property to make a scalable SVG that maintains its size ratio.

In addition, it uses ResizeObserver and a span wrapper with width: fit-content to monitor changes in the SVG content. That way, we can react to any changes that modify the text dimensions and update viewBox accordingly. This only happens when the text size ratio changes.

(*) The viewBox property is computed in the editor and persisted in the HTML. This effectively sets an initial value for viewBox without JavaScript, which mitigates the problem of scaling the SVG with code. However, that value is not 100% reliable, as different users could see different fonts with different sizes for the same text.

Alternatives

Window 'resize' event + computed font-size This approach only reacts to changes in the viewport size, meaning that the size won't be re-computed when the element content changes dynamically or when the parent container dimensions change. Also, the font-size prop should be updated anytime the available width changes per frame.

ResizeObserver (95.37%) + computed font-size This approach is similar to the above, but it uses a ResizeObserver in the parent container rather than subscribing to resize events on window. It can react to the available width, although it still has to update font-size per frame.

Container Query Units (90.97%) + ResizeObserver + computed var(--ratio) This one is similar to the SVG approach. The difference is that it uses container query units to set a font-size value relative to the container's width. The text's height/width ratio is re-calculated whenever the text changes and the font-size value updated accordingly.

CSS custom properties (89.97%) + Container Query Units This only-CSS solution could be based on Roman Komarov's Fit-to-Width Text technique. We tested it in the feature/stretchy-type-paragraph branch. It's reliable in most cases, but some fonts seem to be adjusted incorrectly.