Closed Sub6Resources closed 1 year ago
I think this is a fantastic improvement over the current state. It extends what is possible while making the API easier to understand. We could apply the same idea to our image renders as well, though it remains to be seen if we can merge the two entirely into one 'extension' feature.
Perhaps some sort of ImageExtension
helper class (and perhaps a few helper subclasses) might make that possible. I'll look the current implementation over and see what could be done
Maybe I'm a bit pedantic but the naming of "Extension" might be confusing to some, especially since extension
is already a reserved keyword in dart, and might clash with other classes since it's such a common term. Intellisense may also add to confusion if you don't explicitly check where the import is coming from.
HtmlExtensions or something that better differentiates it might be an improvement imo :)
This is an idea for a simplified version of our public-facing API. I've been thinking a lot about the customRender API. I like the matchers, but the interface can be confusing. These suggestions should make interfacing with our widget easier, so basic users don't have to know the internals of how the project works, while still allowing advanced users to get everything they need to done.
@erickok any thoughts or feedback? Any feedback from any community members?
To start, here's what the
Html
widget would look like in the example with my proposed changes:Changes
tagsList
is no longer required when adding custom widgets. It'll still be there as a parameter for black/white-listing tags, butHtml
will automatically search through the given extensions and enable support for the custom tags by default. This requires that theHtml.tags
member be turned into a getter that has that same behavior.customRenders
replaced withextensions
. This is the major shift. CurrentlycustomRenders
takes in aMap<bool Function(RenderContext), CustomRender>
, which is a bit confusing.extensions
will just take in aList<Extension>
. More details on theExtension
class below.RenderContext
in builder replaced byExtensionContext
.ExtensionContext
will store and provide direct access to some of the most commonly used attributes, as well as all the extra stuffRenderContext
holds.New
Extension
ClassThis new class encapsulates the "matcher"/"renderer" logic into a container. Keeping it in a class also means that the object can persist and receive data across the various phases of the Html widget's lexing/styling/processing/parsing/rendering/disposing lifecycle. This also makes the Extensions tightly coupled with the tree, rather than a hacky afterthought.
Here's what the basic signature of the
Extension
class might look like. By default, the only thing that needs to be overwritten by child classes is thematches
method. Everything else will work out of the box, with default behavior:And then there's the
ExtensionContext
class, which has the following members available:These classes haven't actually been written or implemented, so things may be subject to change as specific implementation requirements open or close different doors.
Benefit: Clearer Path Towards First and Third-Party Extensions
This new approach would make the modular design a little more intuitive.
Each of our first-party packages would now just need to override the
Extension
class, and including them is a bit more intuitive than, say,svgAssetUriMatcher(): svgAssetImageRender()
, etc. They would still be able to support custom options, error callbacks, etc, in their constructors.In addition, this opens the door more widely for third-party packages to extend flutter_html's functionality in a way that is easy to use and doesn't affect existing users.
For example, a third-party could write and publish support for:
Included
Extension
Helper ClassesSince the average use case isn't worth creating a whole class to override
Extension
for, flutter_html will provide a couple helper class constructors for basic use cases, as used in the example above. Here's what their signatures might look like:Hopefully it's fairly obvious how these would be implemented!
Example
Extension
:Here's a somewhat silly example of what an extension subclass might look like and how it would be used by the user (I'm coding this in the GitHub text editor, so forgive any typos or errors 😅):
And, here's the usage in an app:
Which would output something along the lines of
One...
Two...
Three...