Jump to content
Search Community

Tween targets inside shadowRoot

mikaL test
Moderator Tag

Recommended Posts

1 hour ago, mikaL said:

That's where it's often used, but it doesn't have to be. ShadowRoot inherits from DocumentFragment --> Node , so it's got append() , appendChild() etc. methods.

 

Right, I get all that. I was just trying to understand your workflow. Like are you cloning a template, creating elements dynamically and then appending them, appending already existing elements, using innerHTML, etc? 

 

Link to comment
Share on other sites

4 hours ago, GreenSock said:

I'm still not sure I'm loving this concept. Do ya'll think it'll really get used and provide enough value to expand the API surface area? 

 

I'm pretty sure people will start using it once it starts showing up in demos. It will probably also be a good learning experience for some as I don't think a lot of people know you can do element.querySelectorAll.

 

But I think the biggest usage will be with React and Angular. I've shown some React examples, but Angular is probably worse.

 

Ex HTML:

 

<div #heading class="heading">Lorem Ipsum</div>

<div>
  <div #img class="img"></div>
  <div #img class="img"></div>
  <div #img class="img"></div>
</div>

 

Ex TS:

@component()
class MyComponent implements AfterViewInit {
  
  @ViewChild("heading") 
  heading: ElementRef;

  @ViewChildren("img") 
  images: QueryList<ElementRef>;

  ngAfterViewInit(): void {
        
    const imageElements = this.images.map(img => img.nativeElement);
    
    gsap.to(this.heading.nativeElement, {
      y: 100
    });
    
    gsap.to(imageElements, {
      autoAlpha: 1,
      stagger: 0.1
    });
  }
}

 

With context...

@component()
class MyComponent implements AfterViewInit {

  constructor(el: ElementRef) {
    this.el = el.nativeElement;
  }

  ngAfterViewInit(): void {
    
    const $ = gsap.context(this.el);
    
    gsap.to($(".heading"), {
      y: 100
    });
    
    gsap.to($(".img"), {
      autoAlpha: 1,
      stagger: 0.1
    });
  }
}

 

 

  • Like 2
Link to comment
Share on other sites

 

1 hour ago, OSUblake said:

 

Right, I get all that. I was just trying to understand your workflow. Like are you cloning a template, creating elements dynamically and then appending them, appending already existing elements, using innerHTML, etc? 

 

I'm using a library, uhtml, that uses template literals, like lit-html. Details here , if you're interested. So data is in plain objects, and then gets rendered thru uhtml. My "components" are functions, with hooks too, so it's kind of like React, but of course much simpler, no virtual DOM etc. GSAP is used to build a root timeline + component-timelines. Root timeline is used to control all animations, so that it can be stepped frame by frame, to be fed into video encoder in backend, that renders the HTML in browser (puppeteer).

 

  • Like 1
Link to comment
Share on other sites

uhtml is a lot like lit-html, but the API is simpler, closer to standard HTML, or JSX. I didn't go with his hooks solution though (he's got at least 3 hooks libraries too, and I just couldn't figure it out) 

Link to comment
Share on other sites

18 hours ago, OSUblake said:

I'm pretty sure people will start using it once it starts showing up in demos. It will probably also be a good learning experience for some as I don't think a lot of people know you can do element.querySelectorAll.

 

But I think the biggest usage will be with React and Angular. I've shown some React examples, but Angular is probably worse.

I don't think it'd be terribly difficult to add this, but once we add it, we're committed - I'm curious if everyone thinks this is worth doing. Will it solve "ref hell" and smooth out working with GSAP in frameworks like React and Angular? Any other suggestions? 

 

What I don't want is a band-aid solution and then later we realize there's a much more intuitive way to structure things. Not having much experience with these frameworks, I don't feel like I'm in a great position to judge. @elegantseagulls? @Dipscom? @Rodrigo? Anyone else? 
 

To summarize, we're basically providing a way to scope a gsap.utils.toArray() to a particular element, and we can also add some conditional checks for "current" and "nativeElement" in case someone wants to pass in a ref or something. 

Link to comment
Share on other sites

I can see the use of this in React mostly when dealing with a lot of refs. In Vue it would also be useful but only to reduce template boilerplate, that is defining the ref name in the template tag. Vue is smart enough to handle all refs inside an object, which makes it super easy to access, also if you use a ref in a v-for loop, each DOM node will reside in an array with the name of such ref. So Vue kind of makes things easy for developers that way, but that approach is not very well known.

 

In React you have to define the ref in the code and then add it in the JSX which leads to a lot of refs in larger components that can't be break down into smaller ones. Of course you can go the Vue route and create a single object for your refs and store them in it using the ref callback, which is something React should have thought about, but yet again, there are many things the React team should've thought about 🤷‍♂️. Personally I do that when there are more than 3-4 refs in a component. It's far simpler and easy to work with and you define kind of a store for refs soto speak.

 

To summarize: There are simple and easy ways to handle a bunch of refs in a component that most users are either unaware of or too lazy to implement, so in those cases it would help.

 

Finally in the particular case of this thread it would also help of course.

  • Thanks 1
Link to comment
Share on other sites

I don't know enough about the inner workings of frameworks to utter an educated opinion on the matter. I'm not even versed enough on shadowDOM for that matter.

 

All I can see in this discussion is that there are workarounds to the matter only people don't get a good enough grasp of the tools they use in order to be aware of them. If an option is wanted of me, I'd vote to ruminate on this idea a bit longer before making a decision.

  • Thanks 1
Link to comment
Share on other sites

  • 2 weeks later...

Alright, there's an experimental new gsap.utils.scopedSelector() function in the latest beta...

 

minified core (for CodePen):

https://assets.codepen.io/16327/gsap-latest-beta.min.js

 

.tgz file (to npm install):

https://assets.codepen.io/16327/gsap-beta.tgz

 

You simply pass it an element (or selector text or React ref or Angular object that has a "nativeElement" property) and it will querySelectorAll() on THAT. So if it's a React ref, it'll look for the .current value whenever you call it. Example:

const q = gsap.utils.scopedSelector(myElement);

gsap.to(q(".box"), {x: 100});
gsap.to(q(".circle"), {y: 200});

As discussed in this thread, that gives a nice and tidy way of scoping things to a particular element which should be helpful for React modules where you may have a bunch of instances of a particular module (thus document.querySelectorAll() would give you ALL instances on the entire page - not good). My hope is that it would reduce the need for storing tons of refs. You can just use classes and then create a scopedSelector in your React component, scope it to the container element, and press it into service wherever you want. 

 

This isn't just for React or Angular, of course - it could be useful in other cases as well. 

 

When you call the scoped selector, it'll always return a proper Array too (not a NodeList), so it'll have all the handy Array method on it. 

 

I'd love to get your feedback on this before we decide whether or not to include it in the 3.7.0 release (soon). Please kick the tires and let me know what you think. 

  • Like 1
Link to comment
Share on other sites

@chrisgannon, you might like this feature as I know you like to do this.

 

let select = s => document.querySelector(s),
  selectAll = s =>  document.querySelectorAll(s);

 

This would be the same as selectAll.

const q = gsap.utils.scopedSelector(document);

 

For React, I would use the component's main element as the scoped selector. Now you only need 1 ref.

function MyComponent() {
  
  const el = useRef(); 
  
  useEffect(() => {
    const q = gsap.utils.scopedSelector(el);
    
    gsap.to(q(".box"), {x: 100});
	gsap.to(q(".circle"), {y: 200});
  }, []);
      
  return (
    <div ref={el}>
      ...
    </div>
  );
}

 

See the Pen d86f6dea741f0fe2139afce2c546fc43 by osublake (@osublake) on CodePen

 

 

 

  • Like 2
Link to comment
Share on other sites

7 hours ago, OSUblake said:

This would be the same as selectAll.


const q = gsap.utils.scopedSelector(document);

 

But slightly better - the GSAP version would return a true Array whereas the .querySelectorAll() returns a NodeList. 👍

 

Thanks for the demos, Blake. 

  • Like 2
Link to comment
Share on other sites

  • 1 year later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...