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

Extract and re-use element morphing logic #1234

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Commits on Apr 15, 2024

  1. Extract and re-use element morphing logic

    Follow-up to [hotwired#1185][]
    Related to [hotwired#1192][]
    
    The `morph{Page,Frames,Elements}` functions
    ---
    
    Introduce a new `src/core/morphing` module to expose a centralized and
    re-usable `morphElements(currentElement, newElement)` function to be
    invoked across the various morphing contexts. Next, move the logic from
    the `MorphRenderer` into a module-private `IdomorphCallbacks` class. The
    `IdomorphCallbacks` class (like its `MorphRenderer` predecessor) wraps a
    call to `Idiomorph` based on its own set of callbacks. The bulk of the
    logic remains in the `IdomorphCallbacks` class, including checks for
    `[data-turbo-permanent]`. To serve as a seam for integration, the class
    retains a reference to a callback responsible for:
    
    * providing options for the `Idiomorph`
    * determining whether or not a node should be skipped while morphing
    
    The `MorphingPageRenderer` skips `<turbo-frame refresh="morph">` elements
    so that it can override their rendering to use morphing. Similarly, the
    `MorphingFrameRenderer` provides the `morphStyle: "innerHTML"` option to
    morph its children.
    
    Changes to the renderers
    ---
    
    To integrate with the new module, first rename the `MorphRenderer` to
    `MorphingPageRenderer` to set a new precedent that communicates the
    level of the document the morphing is scoped to. With that change in
    place, define the static `MorphingPageRenderer.renderElement` to mirror
    the other existing renderer static functions (like
    [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and
    [FrameRenderer.renderElement][]). This integrates with the changes
    proposed in [hotwired#1028][].
    
    Next, modify the rest of the `MorphingPageRenderer` to integrate with
    its `PageRenderer` ancestor in a way that invokes the static
    `renderElement` function. This involves overriding the
    `preservingPermanentElements(callback)` method. In theory, morphing has
    implications on the concept of "permanence". In practice, morphing has
    the `[data-turbo-permanent]` attribute receive special treatment during
    morphing.
    
    Following the new precedent, introduce a new `MorphingFrameRenderer`
    class to define the `MorphingFrameRenderer.renderElement` function that
    invokes the `morphElements` function with `newElement.children` and
    `morphStyle: "innerHTML"`.
    
    Changes to the StreamActions
    ---
    
    The extraction of the `morphElements` function makes entirety of the
    `src/core/streams/actions/morph.js` module redundant. This commit
    removes that module and invokes `morphElements` directly within the
    `StreamActions.morph` function.
    
    Future possibilities
    ---
    
    In the future, additional changes could be made to expose the morphing
    capabilities as part of the `window.Turbo` interface.
    
    For example, applications could experiment with supporting [Page
    Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by
    overriding the rendering mechanism in `turbo:before-render`:
    
    ```js
    addEventListener("turbo:before-render", (event) => {
      const someCriteriaForMorphing = ...
    
      if (someCriteriaForMorphing) {
        event.detail.render = Turbo.morphPage
      }
    })
    
    addEventListener("turbo:before-frame-render", (event) => {
      const someCriteriaForMorphingAFrame = ...
    
      if (someCriteriaForMorphingAFrame) {
        event.detail.render = Turbo.morphFrames
      }
    })
    ```
    
    [hotwired#1185]: hotwired#1185 (comment)
    [hotwired#1192]: hotwired#1192
    [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11
    [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9
    [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16
    [hotwired#1028]: hotwired#1028
    [hotwired#1177]: hotwired#1177
    seanpdoyle committed Apr 15, 2024
    Configuration menu
    Copy the full SHA
    346b551 View commit details
    Browse the repository at this point in the history