浏览代码

implemented fallback arg for LabIcon.resolveX methods

- also bugfix in svg replacement routine
telamonian 5 年之前
父节点
当前提交
2de04f2c37

+ 1 - 0
.cleanignore

@@ -21,4 +21,5 @@
 
 # ms IDE stuff
 @*.code-workspace
+@.history
 @.vscode

+ 1 - 0
.gitignore

@@ -58,4 +58,5 @@ junit.xml
 
 # ms IDE stuff
 *.code-workspace
+.history
 .vscode

+ 4 - 6
packages/apputils/src/toolbar.tsx

@@ -497,13 +497,11 @@ export function ToolbarButtonComponent(props: ToolbarButtonComponent.IProps) {
     >
       <LabIcon.resolveReact
         icon={props.icon}
-        iconClass={props.iconClass}
-        className={
-          // if props.icon is unset, add extra classes for proper support of icon-as-css-background
-          props.icon
-            ? 'jp-ToolbarButtonComponent-icon'
-            : classes('jp-ToolbarButtonComponent-icon', 'jp-Icon', 'jp-Icon-16')
+        iconClass={
+          // add some extra classes for proper support of icons-as-css-backgorund
+          classes(props.iconClass, 'jp-Icon', 'jp-Icon-16')
         }
+        className="jp-ToolbarButtonComponent-icon"
         tag="span"
         justify="center"
         kind="toolbarButton"

+ 5 - 12
packages/filebrowser/src/listing.ts

@@ -1834,22 +1834,15 @@ export namespace DirListing {
       const modified = DOMUtils.findElement(node, ITEM_MODIFIED_CLASS);
 
       // render the file item's icon
-      const iconProps: LabIcon.IProps = {
+      LabIcon.resolveElement({
+        icon: fileType?.icon,
+        iconClass: fileType?.iconClass,
+        fallback: fileIcon,
         container: iconContainer,
         className: ITEM_ICON_CLASS,
         justify: 'center',
         kind: 'listing'
-      };
-      if (!(fileType?.icon || fileType?.iconClass)) {
-        // no icon set on fileType, fall back to default file icon
-        fileIcon.element(iconProps);
-      } else {
-        LabIcon.resolveElement({
-          icon: fileType.icon,
-          iconClass: fileType.iconClass,
-          ...iconProps
-        });
-      }
+      });
 
       let hoverText = 'Name: ' + model.name;
       // add file size to pop up if its available

+ 8 - 15
packages/settingeditor/src/pluginlist.tsx

@@ -277,21 +277,14 @@ namespace Private {
             key={id}
             title={itemTitle}
           >
-            {!(icon || iconClass) ? (
-              <settingsIcon.react
-                title={iconTitle}
-                tag="span"
-                kind="settingsEditor"
-              />
-            ) : (
-              <LabIcon.resolveReact
-                icon={icon}
-                iconClass={iconClass}
-                title={iconTitle}
-                tag="span"
-                kind="settingsEditor"
-              />
-            )}
+            <LabIcon.resolveReact
+              icon={icon}
+              iconClass={iconClass}
+              fallback={settingsIcon}
+              title={iconTitle}
+              tag="span"
+              kind="settingsEditor"
+            />
             <span>{schema.title || id}</span>
           </li>
         );

+ 73 - 76
packages/ui-components/src/icon/labicon.tsx

@@ -21,63 +21,6 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
    * statics *
    ***********/
 
-  /**
-   * Get any existing LabIcon instance by name.
-   *
-   * @param name - name of the LabIcon instance to fetch
-   *
-   * @param fallback - optional default LabIcon instance to use if
-   * name is not found
-   *
-   * @returns A LabIcon instance
-   */
-  private static _get(name: string, fallback?: LabIcon): LabIcon | undefined {
-    if (LabIcon._instances.has(name)) {
-      return LabIcon._instances.get(name);
-    }
-
-    // lookup failed
-    if (LabIcon._debug) {
-      // fail noisily
-      console.error(`Invalid icon name: ${name}`);
-    }
-
-    // fail silently
-    return fallback;
-  }
-
-  /**
-   * UNSTABLE - only exists for handling a single special case
-   *
-   * TODO: Fix the remaining case that relies on this and then
-   *   remove this method:
-   *     - index.tsx in launcher
-   */
-  static UNSTABLE_getReact({
-    name,
-    fallback,
-    ...props
-  }: { name: string; fallback?: LabIcon } & LabIcon.IReactProps) {
-    for (let className of name.split(/\s+/)) {
-      if (LabIcon._instances.has(className)) {
-        const icon = LabIcon._instances.get(className)!;
-        return <icon.react {...props} />;
-      }
-    }
-
-    // lookup failed if execution reached here
-    if (LabIcon._debug) {
-      // fail noisily
-      console.error(`Invalid icon name: ${name}`);
-      return <badIcon.react {...props} />;
-    } else if (fallback) {
-      return <fallback.react {...props} />;
-    } else {
-      // try to render the icon as a css background image via iconClass
-      return <Private.iconAsCssBackgroundReact {...props} />;
-    }
-  }
-
   /**
    * Remove any rendered icon from the element that contains it
    *
@@ -115,11 +58,19 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
 
     if (typeof icon === 'string') {
       // do a dynamic lookup of existing icon by name
-      const resolved = LabIcon._get(icon);
+      const resolved = LabIcon._instances.get(icon);
       if (resolved) {
         return resolved;
       }
 
+      // lookup failed
+      if (LabIcon._debug) {
+        // fail noisily
+        console.warn(
+          `Lookup failed for icon, creating loading icon. icon: ${icon}`
+        );
+      }
+
       // no matching icon currently registered, create a new loading icon
       // TODO: find better icon (maybe animate?) for loading icon
       return new LabIcon({ name: icon, svgstr: refreshSvgstr, _loading: true });
@@ -138,10 +89,13 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
    * an empty div.
    *
    * @param icon - optional, either a string with the name of an existing icon
-   * or an object with {name: string, svgstr: string} fields.
+   * or an object with {name: string, svgstr: string} fields
    *
    * @param iconClass - optional, if the icon arg is not set, the iconClass arg
-   * should be a CSS class associated with an existing CSS background-image.
+   * should be a CSS class associated with an existing CSS background-image
+   *
+   * @param fallback - optional, a LabIcon instance that will be used if
+   * neither icon nor iconClass are defined
    *
    * @param props - any additional args are passed though to the element method
    * of the resolved icon on render
@@ -154,12 +108,16 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
     fallback,
     ...props
   }: Partial<LabIcon.IResolverProps> & LabIcon.IProps) {
-    // combine iconClass with any class from the props
-    props.className = classes(iconClass, props.className);
-
     if (!icon) {
-      // try to render the icon as a css background image via iconClass
-      return Private.iconAsCssBackgroundElement(props);
+      if (!iconClass && fallback) {
+        // if neither icon nor iconClass are defined, use fallback
+        return fallback.element(props);
+      }
+
+      // set the icon's class to iconClass plus props.className
+      props.className = classes(iconClass, props.className);
+      // render icon as css background image, assuming one is set on iconClass
+      return Private.blankElement(props);
     }
 
     return LabIcon.resolve({ icon }).element(props);
@@ -173,10 +131,13 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
    * will simply render an empty div.
    *
    * @param icon - optional, either a string with the name of an existing icon
-   * or an object with {name: string, svgstr: string} fields.
+   * or an object with {name: string, svgstr: string} fields
    *
    * @param iconClass - optional, if the icon arg is not set, the iconClass arg
-   * should be a CSS class associated with an existing CSS background-image.
+   * should be a CSS class associated with an existing CSS background-image
+   *
+   * @param fallback - optional, a LabIcon instance that will be used if
+   * neither icon nor iconClass are defined
    *
    * @param props - any additional args are passed though to the React component
    * of the resolved icon on render
@@ -189,12 +150,16 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
     fallback,
     ...props
   }: Partial<LabIcon.IResolverProps> & LabIcon.IReactProps) {
-    // combine iconClass with any class from the props
-    props.className = classes(iconClass, props.className);
-
     if (!icon) {
-      // try to render the icon as a css background image via iconClass
-      return <Private.iconAsCssBackgroundReact {...props} />;
+      if (!iconClass && fallback) {
+        // if neither icon nor iconClass are defined, use fallback
+        return <fallback.react {...props} />;
+      }
+
+      // set the icon's class to iconClass plus props.className
+      props.className = classes(iconClass, props.className);
+      // render icon as css background image, assuming one is set on iconClass
+      return <Private.blankReact {...props} />;
     }
 
     const resolved = LabIcon.resolve({ icon });
@@ -204,7 +169,7 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
   /**
    * Resolve a {name, svgstr} pair into an actual svg node.
    */
-  static resolveSvg({ name, svgstr }: LabIcon.ILabIcon): HTMLElement | null {
+  static resolveSvg({ name, svgstr }: LabIcon.IIcon): HTMLElement | null {
     const svgDoc = new DOMParser().parseFromString(svgstr, 'image/svg+xml');
 
     const svgError = svgDoc.querySelector('parsererror');
@@ -237,6 +202,38 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
     LabIcon._debug = debug ?? !LabIcon._debug;
   }
 
+  /**
+   * UNSTABLE - only exists for handling a single special case
+   *
+   * TODO: Fix the remaining case that relies on this and then
+   *   remove this method:
+   *     - index.tsx in launcher
+   */
+  static UNSTABLE_getReact({
+    name,
+    fallback,
+    ...props
+  }: { name: string; fallback?: LabIcon } & LabIcon.IReactProps) {
+    for (let className of name.split(/\s+/)) {
+      if (LabIcon._instances.has(className)) {
+        const icon = LabIcon._instances.get(className)!;
+        return <icon.react {...props} />;
+      }
+    }
+
+    // lookup failed if execution reached here
+    if (LabIcon._debug) {
+      // fail noisily
+      console.error(`Invalid icon name: ${name}`);
+      return <badIcon.react {...props} />;
+    } else if (fallback) {
+      return <fallback.react {...props} />;
+    } else {
+      // try to render the icon as a css background image via iconClass
+      return <Private.blankReact {...props} />;
+    }
+  }
+
   private static _debug: boolean = false;
   private static _instances = new Map<string, LabIcon>();
 
@@ -388,7 +385,7 @@ export class LabIcon implements LabIcon.ILabIcon, LabIcon.IRenderer {
 
     // update icon elements created using .element method
     document
-      .querySelectorAll(`[data-icon-id=${uuidOld}]`)
+      .querySelectorAll(`[data-icon-id="${uuidOld}"]`)
       .forEach(oldSvgElement => {
         const svgElement = this._initSvg({ uuid });
         if (svgElement) {
@@ -727,7 +724,7 @@ export namespace LabIcon {
 }
 
 namespace Private {
-  export function iconAsCssBackgroundElement({
+  export function blankElement({
     className = '',
     container,
     label,
@@ -757,7 +754,7 @@ namespace Private {
     return container;
   }
 
-  export const iconAsCssBackgroundReact = React.forwardRef(
+  export const blankReact = React.forwardRef(
     (
       {
         className = '',