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
Adds JLIcon, an easier way to consume icons as SVG nodes #7299
Conversation
Thanks for making a pull request to JupyterLab! To try out this branch on binder, follow this link: |
The design goal of this PR can be thought of as a riff on Saul's suggestion. |
b3a9e37
to
9a524d2
Compare
The return type of export interface IComponent extends ReturnType<typeof React.forwardRef<HTMLDivElement, JLIcon.IProps>> {
element?: (props: IProps) => HTMLElement;
} but that's not valid syntax, due to the vagaries of the current type _ret<T, P> = typeof React.forwardRef;
export interface IComponent extends ReturnType<_ret<HTMLDivElement, JLIcon.IProps>> {
element?: (props: IProps) => HTMLElement;
} but for reasons I don't understand, the concrete template parameters in export interface IComponent extends ForwardRefExoticComponent<PropsWithoutRef<IProps> & RefAttributes<HTMLDivElement>> {
element?: (props: IProps) => HTMLElement;
} This works well, though it seems kind of fragile (wrt changes to |
I think I like Saul's quoted idea above. Create an <span>myIcon.component()</span> |
Whelp, apparently I was under some mistaken impressions about valid syntax for JSX component names; I thought they had to start with an uppercase letter and have no dot. In actual fact, the only invalid names seem to be those that start with a lowercase letter but don't have a dot: const bar = TrustedIcon;
const Bar = TrustedIcon;
const foo: any = {};
const Foo = foo;
foo.icon = TrustedIcon;
foo.Icon = TrustedIcon;
const barFunc = () => TrustedIcon;
const BarFunc = () => TrustedIcon;
foo.iconFunc = () => TrustedIcon;
foo.IconFunc = () => TrustedIcon;
return (
<div style={{display: "inline-flex"}}>
<bar/> {/* error! */}
<Bar/> {/* valid */}
<foo.icon/> {/* valid */}
<foo.Icon/> {/* valid */}
<Foo.icon/> {/* valid */}
<Foo.Icon/> {/* valid */}
{/* can't use a function call as a JSX component */}
<barFunc()/> {/* error! */}
<BarFunc()/> {/* error! */}
<foo.iconFunc()/> {/* error! */}
<foo.IconFunc()/> {/* error! */}
<Foo.iconFunc()/> {/* error! */}
<Foo.IconFunc()/> {/* error! */}
{/* but you can use function calls if you escape from JSX */}
{barFunc()} {/* valid */}
{React.createElement(barFunc(), {className: "bar"})} {/* valid */}
</div> Function calls are never valid JSX components, but you can use them if you escape from JSX. |
@sccolbert I'll take your suggestion (to take Saul's original suggestion) and rearrange |
@saulshanabrook @sccolbert Thank you for your feedback. It helped me to figure out how to vastly simplify the design of the new icon objects and still get the ease-of-use in JSX that I was chasing after. In the latest changes that I just pushed, all of the icon objects are now instances of the jupyterlab/packages/notebook/src/truststatus.tsx Lines 47 to 51 in 006b57a
Though the internals of The next thing for me to tackle will be the non-React use cases for |
45848ba
to
f72c96b
Compare
also had to revert the cleanup of createIcon's return type. The new way didn't work since some template parameters weren't specified
also added explicit types to the call to `React.forwardRef` within `createIcon`
individual icons are now instances of JLIcon class
more efficient, since this way the component returned by .react is created only once (as part of the constructor) and cached. Need to be careful with future changes to JLIcon.constructor, as execution order of initializers is now important
57737c9
to
6d38176
Compare
The Before this can be pulled in we'll need to do another |
I will review this today! Thanks @telamonian for all your work here. |
Thanks @saulshanabrook! If you actually want to test the code from this PR, you'll also need to
|
@telamonian Great, I will have a go at running it locally. Looks good overall! I wanna do some tests around the React component stuff... Curious if I can factor out the component into an external function. |
@saulshanabrook Looking over your comments so far, it might be better if you just take a look at #7700. It's the direct continuation of this PR, and already has resolutions for most the things you pointed out in the review. For example, I dropped the use of |
Since #7700 includes this PR and important fixes for this PR, should we just close this PR in deference to that one? |
@jasongrout I think that's fine. I originally split this into two PRs in order to make it easier to read over and review the basic code for So as long as someone is up to reviewing #7700 as one big piece (it currently has changes to 239 files and over 4000 lines), feel free to close #7299 |
@saulshanabrook - since you are reviewing this (thanks again!), how about you make the decision about whether to review this PR or close it and just look at #7700. |
Let's close this and just look at that one. |
References
Followup to #6034, #7192, #7266, and a bunch of others
Code changes
Working on the one true way to consume icons in jlab, with a goal to get this in by
v2.0
. The basic design plan is this:.svg
file (as astring
) and return aReact.Component
class.svg
file).svg
then making a call to the wrapperUser-facing changes
None
Backwards-incompatible changes
Will remove all other means of consuming icons. In exchange, will add a super easy way to setup/consume theme-aware icons in extensions.