-
-
Save addisonschultz/1811e75b498311211a7f6b8634fb27cd to your computer and use it in GitHub Desktop.
| import * as React from "react" | |
| import { useState, useEffect } from "react" | |
| // Hook | |
| let cachedScripts = [] | |
| export function useScript(src) { | |
| // Keeping track of script loaded and error state | |
| const [state, setState] = useState({ | |
| loaded: false, | |
| error: false, | |
| }) | |
| useEffect(() => { | |
| // If cachedScripts array already includes src that means another instance ... | |
| // ... of this hook already loaded this script, so no need to load again. | |
| if (cachedScripts.includes(src)) { | |
| setState({ | |
| loaded: true, | |
| error: false, | |
| }) | |
| } else { | |
| cachedScripts.push(src) | |
| // Create script | |
| let script = document.createElement("script") | |
| script.src = src | |
| script.async = true | |
| // Script event listener callbacks for load and error | |
| const onScriptLoad = () => { | |
| setState({ | |
| loaded: true, | |
| error: false, | |
| }) | |
| } | |
| const onScriptError = () => { | |
| // Remove from cachedScripts we can try loading again | |
| const index = cachedScripts.indexOf(src) | |
| if (index >= 0) cachedScripts.splice(index, 1) | |
| script.remove() | |
| setState({ | |
| loaded: true, | |
| error: true, | |
| }) | |
| } | |
| script.addEventListener("load", onScriptLoad) | |
| script.addEventListener("error", onScriptError) | |
| // Add script to document body | |
| document.body.appendChild(script) | |
| // Remove event listeners on cleanup | |
| return () => { | |
| script.removeEventListener("load", onScriptLoad) | |
| script.removeEventListener("error", onScriptError) | |
| } | |
| } | |
| }, [src]) // Only re-run effect if script src changes | |
| return [state.loaded, state.error] | |
| } |
You can totally use css inside of Framer X! The easiest and most straight forward way is to include the css file in the code folder of your Framer X Project. If you're loading it from a link, maybe the above solution is the best!
Make sure you include the className in the component as well.
A cool way you could have a dynamic component that you can change would be something like
export function Component(props) {
return (
<div className={props.className}></div>
)
}
addPropertyControls(Component, {
className: {type: ControlType.String, title: "Class Name"}
})
thank you :)
What's the best way to execute a function after the script is loaded?
@AndrewTraub I would suggest using it in the useEffect from the example above. It returns a boolean if it's loaded, and if so, you can then do what you'd like from there.
what if the script exists as a project file and not a url? how would you modify the hook?
@ridhwaans I have a Framer Example that lets you choose either a URL or a local file using a property control in the component itself :)
You can see how it's set up here: https://github.com/framer/framer-bridge-stencil-kit/tree/master/code/utils
You can look into constants.tsx to see the actual util
This rocks! Question - I've built out my design system with the external stylesheet and CSS variables. Any tips or tricks on getting that available inside framer x?